diff --git a/VstHost_Python/UnitTests/test_c_api.py b/VstHost_Python/UnitTests/test_c_api.py index 85d4188..e50b986 100644 --- a/VstHost_Python/UnitTests/test_c_api.py +++ b/VstHost_Python/UnitTests/test_c_api.py @@ -84,6 +84,9 @@ def test_InitVstHostTwice(self): self.assertEqual(status, Status.VST_HOST_INSTANCE_ALREADY_CREATED.value) def test_RunBasicFlow(self): + if platform == "darwin": + return + self._PrintUnitTestName() status = self._vst_host.LoadLibrary(self._full_vst_host_lib_path) diff --git a/VstHost_VisualC++/modules/AudioEndpointManager/CMakeLists.txt b/VstHost_VisualC++/modules/AudioEndpointManager/CMakeLists.txt index 0c10d61..45bdaed 100644 --- a/VstHost_VisualC++/modules/AudioEndpointManager/CMakeLists.txt +++ b/VstHost_VisualC++/modules/AudioEndpointManager/CMakeLists.txt @@ -13,6 +13,7 @@ elseif(SMTG_WIN) ) add_library(${target} ${audio_enpoint_manager_src} ${audio_enpoint_manager_headers}) target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/header) + target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../external_modules/RtAudio/rtaudio/) target_compile_features(${target} PUBLIC cxx_std_17) target_link_libraries(${target} PRIVATE Common Logger AudioCapture AudioRender rtaudio AudioEndpointBase) diff --git a/VstHost_VisualC++/modules/AudioEndpointManager/header/AudioEndpointManager.h b/VstHost_VisualC++/modules/AudioEndpointManager/header/AudioEndpointManager.h index 28a24f3..83fda5f 100644 --- a/VstHost_VisualC++/modules/AudioEndpointManager/header/AudioEndpointManager.h +++ b/VstHost_VisualC++/modules/AudioEndpointManager/header/AudioEndpointManager.h @@ -7,7 +7,7 @@ #include "easylogging++.h" #include "AudioCapture.h" #include "AudioRender.h" - +#include "RtAudio.h" class AudioEndpointManager { @@ -15,15 +15,24 @@ class AudioEndpointManager public: explicit AudioEndpointManager(uint8_t verbose); ~AudioEndpointManager() = default; - int RunAudioEndpointHandler(); + int RunRtAudioEndpointHandler(); private: - int RunAudioCapture(); - int RunAudioRender(); + int RunWasapiAudioCapture(); + int RunWasapiAudioRender(); + int CloseRtAudioStream(); + int GetDeviceIds(); + unsigned int GetDeviceIndex(bool isInput = false); + static int AudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nBufferFrames, + double streamTime, RtAudioStreamStatus status, void* data); + private: std::unique_ptr audio_capture_; std::unique_ptr audio_render_; + std::unique_ptr adac_; + std::vector device_ids_; + size_t buffer_bytes_; uint8_t verbose_ = 0; }; diff --git a/VstHost_VisualC++/modules/AudioEndpointManager/source/AudioEndpointManager.cpp b/VstHost_VisualC++/modules/AudioEndpointManager/source/AudioEndpointManager.cpp index c3d39e2..3b9f4bd 100644 --- a/VstHost_VisualC++/modules/AudioEndpointManager/source/AudioEndpointManager.cpp +++ b/VstHost_VisualC++/modules/AudioEndpointManager/source/AudioEndpointManager.cpp @@ -1,14 +1,13 @@ #include #include #include +#include +#include +#include #include "VstHostMacro.h" #include "AudioEndpointManager.h" -#include "RtAudio.h" -#include -#include -#include typedef double MY_TYPE; #define FORMAT RTAUDIO_FLOAT64 #undef max @@ -18,7 +17,7 @@ AudioEndpointManager::AudioEndpointManager(uint8_t verbose) : { } -int AudioEndpointManager::RunAudioCapture() +int AudioEndpointManager::RunWasapiAudioCapture() { auto audio_capture_thread = std::async(std::launch::async, &AudioCapture::RecordAudioStream, @@ -40,99 +39,116 @@ int AudioEndpointManager::RunAudioCapture() return audio_capture_thread.get(); } -int AudioEndpointManager::RunAudioRender() +int AudioEndpointManager::RunWasapiAudioRender() { return audio_render_->RenderAudioStream(); } - -unsigned int getDeviceIndex(std::vector deviceNames, bool isInput = false) +unsigned int AudioEndpointManager::GetDeviceIndex(bool isInput) { - unsigned int i; + unsigned int device_id; std::string keyHit; std::cout << '\n'; - for (i = 0; i < deviceNames.size(); i++) - std::cout << " Device #" << i << ": " << deviceNames[i] << '\n'; - + std::vector device_names = adac_->getDeviceNames(); + + for (device_id = 0; device_id < device_names.size(); device_id++) + { + std::cout << " Device #" << device_id << ": " << device_names[device_id] << '\n'; + } + do { if (isInput) + { std::cout << "\nChoose an input device #: "; + } else + { std::cout << "\nChoose an output device #: "; - std::cin >> i; - } while (i >= deviceNames.size()); + } + std::cin >> device_id; + } while (device_id >= device_names.size()); std::getline(std::cin, keyHit); // used to clear out stdin - return i; + return device_ids_[device_id]; } -double streamTimePrintIncrement = 1.0; // seconds -double streamTimePrintTime = 1.0; // seconds - -int inout(void* outputBuffer, void* inputBuffer, unsigned int /*nBufferFrames*/, - double streamTime, RtAudioStreamStatus status, void* data) +int AudioEndpointManager::AudioCallback(void* outputBuffer, void* inputBuffer, unsigned int /*nBufferFrames*/, + double /*streamTime*/, RtAudioStreamStatus status, void* data) { - // Since the number of input and output channels is equal, we can do - // a simple buffer copy operation here. - if (status) std::cout << "Stream over/underflow detected." << std::endl; + AudioEndpointManager* _this = static_cast(data); - if (streamTime >= streamTimePrintTime) { - std::cout << "streamTime = " << streamTime << std::endl; - streamTimePrintTime += streamTimePrintIncrement; + if (status) + { + LOG(WARNING) << "Stream over/underflow detected." << std::endl; } - unsigned int* bytes = (unsigned int*)data; - memcpy(outputBuffer, inputBuffer, *bytes); - return 0; + // here is the place for processing + memcpy(outputBuffer, inputBuffer, _this->buffer_bytes_); + return VST_ERROR_STATUS::SUCCESS; } -int AudioEndpointManager::RunAudioEndpointHandler() +int AudioEndpointManager::CloseRtAudioStream() { - RtAudio adac; - std::vector deviceIds = adac.getDeviceIds(); - if (deviceIds.size() < 1) { - std::cout << "\nNo audio devices found!\n"; - exit(0); + if (adac_->isStreamOpen()) + { + adac_->closeStream(); + } + return VST_ERROR_STATUS::SUCCESS; +} + +int AudioEndpointManager::GetDeviceIds() +{ + device_ids_ = adac_->getDeviceIds(); + if (device_ids_.size() < 1) + { + return VST_ERROR_STATUS::NO_AUDIO_DEVICES_ID_FOUND; } + return VST_ERROR_STATUS::SUCCESS; +} + +/// @brief Rt Audio based endpoint handler. +/// @return VST_ERROR_STATUS status +int AudioEndpointManager::RunRtAudioEndpointHandler() +{ + adac_.reset(new RtAudio()); + RETURN_ERROR_IF_NOT_SUCCESS(this->GetDeviceIds()); // Set the same number of channels for both input and output. - unsigned int bufferBytes, bufferFrames = 1024; + unsigned int bufferFrames = 1024; RtAudio::StreamParameters iParams, oParams; uint16_t channels = 2; iParams.nChannels = channels; oParams.nChannels = channels; unsigned int fs = 48000; - unsigned int iDevice = getDeviceIndex(adac.getDeviceNames(), true); - iParams.deviceId = deviceIds[iDevice]; - unsigned int oDevice = getDeviceIndex(adac.getDeviceNames()); - oParams.deviceId = deviceIds[oDevice]; + iParams.deviceId = this->GetDeviceIndex(true); + oParams.deviceId = this->GetDeviceIndex(); RtAudio::StreamOptions options; //options.flags |= RTAUDIO_NONINTERLEAVED; - bufferBytes = bufferFrames * channels * sizeof(MY_TYPE); - if (adac.openStream(&oParams, &iParams, FORMAT, fs, &bufferFrames, &inout, (void*)&bufferBytes, &options)) { - goto cleanup; - } - - if (adac.isStreamOpen() == false) goto cleanup; + buffer_bytes_ = bufferFrames * channels * sizeof(MY_TYPE); - // Test RtAudio functionality for reporting latency. - std::cout << "\nStream latency = " << adac.getStreamLatency() << " frames" << std::endl; + if (adac_->openStream(&oParams, &iParams, FORMAT, fs, &bufferFrames, &AudioCallback, this, &options)) + { + this->CloseRtAudioStream(); + } - if (adac.startStream()) goto cleanup; + LOG(INFO) << "Stream latency = " << adac_->getStreamLatency() << " frames"; + + if (adac_->startStream()) + { + this->CloseRtAudioStream(); + } + LOG(INFO) << "Running ... press to quit (buffer frames = " << bufferFrames << ")."; char input; - std::cout << "\nRunning ... press to quit (buffer frames = " << bufferFrames << ").\n"; std::cin.get(input); // Stop the stream. - if (adac.isStreamRunning()) - adac.stopStream(); - -cleanup: - if (adac.isStreamOpen()) adac.closeStream(); - + if (adac_->isStreamRunning()) + { + return adac_->stopStream(); + } - return 0; + return VST_ERROR_STATUS::SUCCESS; } diff --git a/VstHost_VisualC++/modules/Common/header/enums.h b/VstHost_VisualC++/modules/Common/header/enums.h index e13f909..3f031d8 100644 --- a/VstHost_VisualC++/modules/Common/header/enums.h +++ b/VstHost_VisualC++/modules/Common/header/enums.h @@ -41,8 +41,9 @@ enum VST_ERROR_STATUS EMPTY_LIST_OF_ENPOINTS = 26, MISSING_PARAMETER_VALUE = 27, NOT_IMPLEMENTED = 28, + NO_AUDIO_DEVICES_ID_FOUND = 29, - MAX_STATUS_VALUE = NOT_IMPLEMENTED + MAX_STATUS_VALUE = NO_AUDIO_DEVICES_ID_FOUND }; namespace LogLevelType diff --git a/VstHost_VisualC++/modules/VstHostTool/CMakeLists.txt b/VstHost_VisualC++/modules/VstHostTool/CMakeLists.txt index ff758b7..2e98d25 100644 --- a/VstHost_VisualC++/modules/VstHostTool/CMakeLists.txt +++ b/VstHost_VisualC++/modules/VstHostTool/CMakeLists.txt @@ -21,7 +21,7 @@ if (NOT ${ANDROID_BUILD}) target_include_directories(${target}Lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/header) target_link_libraries (${target} - PRIVATE ${target}Lib base sdk ArgParser Logger Common) + PRIVATE ${target}Lib base sdk ArgParser Logger Common rtaudio) else() target_link_libraries (${target}Lib PUBLIC WaveIO AudioProcessing AudioHostLib PRIVATE base sdk ArgParser Logger Common sdk_hosting) diff --git a/VstHost_VisualC++/modules/VstHostTool/src/VstHostTool.cpp b/VstHost_VisualC++/modules/VstHostTool/src/VstHostTool.cpp index f5e1d90..600ba57 100644 --- a/VstHost_VisualC++/modules/VstHostTool/src/VstHostTool.cpp +++ b/VstHost_VisualC++/modules/VstHostTool/src/VstHostTool.cpp @@ -53,15 +53,10 @@ int VstHostTool::ParsArgs() int VstHostTool::EndpointProcessingPipeline() { - #ifdef _WIN32 std::unique_ptr endpoint_manager(new AudioEndpointManager(arg_parser_->GetPluginVerbosity())); - endpoint_manager->RunAudioEndpointHandler(); + return endpoint_manager->RunRtAudioEndpointHandler(); #endif - // 1. Get Data From Mic - // 2. Put In queue - // 3. Processing - // 4. Render return VST_ERROR_STATUS::NOT_IMPLEMENTED; }