diff --git a/.github/workflows/vst_host_ci.yml b/.github/workflows/vst_host_ci.yml index 235dcfb..7945fed 100644 --- a/.github/workflows/vst_host_ci.yml +++ b/.github/workflows/vst_host_ci.yml @@ -82,6 +82,7 @@ jobs: python -m pip install --upgrade pip pip install -r ${{github.workspace}}/VstHost_Python/requirements.txt sudo apt-get install libsndfile1-dev + sudo apt-get install libasound2-dev - name: Install Doxygen run: | @@ -118,6 +119,7 @@ jobs: .*argparser.hpp* .*json.hpp* .*vst3sdk* + .*rtaudio* fail-under-line: 80 coveralls-send: true github-token: ${{ secrets.COVERALLS_REPO_TOKEN }} @@ -228,6 +230,10 @@ jobs: uses: jwlawson/actions-setup-cmake@v1.13 with: cmake-version: '3.19.x' + + - name: Install Audio Drivers + run: | + sudo apt-get install libasound2-dev - name: Use cmake run: cmake --version diff --git a/.gitmodules b/.gitmodules index 61cee09..454ce45 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,6 @@ path = VstHost_VisualC++/modules/AudioProcessing/filter-c url = git@github.com:RinoReyns/filter-c.git +[submodule "VstHost_VisualC++/external_modules/RtAudio/rtaudio"] + path = VstHost_VisualC++/external_modules/RtAudio/rtaudio + url = https://github.com/thestk/rtaudio.git diff --git a/README.md b/README.md index 267e8a2..8ab0d1c 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ is why this repository was created. I know that it will take a lot of work but i 3. Android ``` NOTE: - Following instraction is made for Linux enviroment. However, steps for any OS should be similar. + Following instruction is made for Linux enviroment. However, steps for any OS should be similar. 1. Download Android NDK and unzip in the chosen location. (https://developer.android.com/ndk/downloads). 2. Set environmental variable for Android NDK as foloow: @@ -122,28 +122,17 @@ is why this repository was created. I know that it will take a lot of work but i - [x] Generate Documentation - [x] AudioProcessing Class that can wrap different non-vst algorithms - [x] Clean up code in vst host lib + - [x] Cross-Platform Audio Endpoint Render-Capture - TODO: - [ ] Add more advanced python-based Vst Host Lib utilization - [ ] Add more UT for python and Android - [ ] Integrate better wave reader - [ ] Build solution for ARM - - [ ] Create Render/Capture manager class. Its design should allow to use it for any OS. - - [ ] Work on Render and Capture implementation for Windows - [ ] Handle different audio formats e.g. sampling rate, bit depth etc. - - [ ] Create and pass config for AudioProcessing Class. - - [ ] Enable streaming processing (one frame in, one frame out). - -1. Windows OS - - - Implemented: - - [x] Basic code for Audio Endpoint Reader - - TODO: - - [ ] Clean up audio endpoint reader and utilize it in code (add queue, use it for processing with vst plugin etc) - -1. Linux & Mac OS - - - TODO: - - [ ] Add endpoint reader + - [ ] Create and pass config for AudioProcessing Class + - [ ] Enable streaming processing (one frame in, one frame out) + - [ ] Clean up Endpoint Manager Class + 1. Android @@ -161,6 +150,7 @@ is why this repository was created. I know that it will take a lot of work but i 1. [C ++ Json Handler](https://github.com/nlohmann/json) 1. [Windows Endpoint Reader](https://github.com/mofo7777/Stackoverflow/tree/master/WasapiCapture) 1. [Implementation of audio filters in C](https://github.com/adis300/filter-c) +1. [Real Timie Audio Render and Capture](https://github.com/thestk/rtaudio) VST is a trademark held by Steinberg Media Technologies, GMBH. diff --git a/VstHost_VisualC++/CMakeLists.txt b/VstHost_VisualC++/CMakeLists.txt index 8e7a70b..024332a 100644 --- a/VstHost_VisualC++/CMakeLists.txt +++ b/VstHost_VisualC++/CMakeLists.txt @@ -49,6 +49,7 @@ add_subdirectory(vst3sdk/base) add_subdirectory(vst3sdk/public.sdk) add_subdirectory(vst3sdk/public.sdk/samples/vst/adelay) add_subdirectory(modules) +add_subdirectory(external_modules) if (NOT ${ANDROID_BUILD}) set_target_properties(gtest PROPERTIES ${UNIT_TESTS_FOLDER}) diff --git a/VstHost_VisualC++/external_modules/CMakeLists.txt b/VstHost_VisualC++/external_modules/CMakeLists.txt new file mode 100644 index 0000000..5213e5e --- /dev/null +++ b/VstHost_VisualC++/external_modules/CMakeLists.txt @@ -0,0 +1,22 @@ +if (MSVC) + add_compile_options(/W1 /WX) + add_link_options(/WX) + include(SMTG_AddSubDirectories) + smtg_add_subdirectories() +elseif (UNIX AND !${ANDROID_BUILD}) + add_compile_options(-Werror -Wextra) +elseif(LINUX) + find_program(GCOV_PATH gcov) + if(NOT GCOV_PATH) + message(${GCOV_PATH}) + message("[WARNING] Code coverage analysis requires gcov!") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") + message("[MESSAGE] Code coverage analysis found gcov!") + endif() + include(SMTG_AddSubDirectories) + smtg_add_subdirectories() +endif() + + + diff --git a/VstHost_VisualC++/external_modules/RtAudio/CMakeLists.txt b/VstHost_VisualC++/external_modules/RtAudio/CMakeLists.txt new file mode 100644 index 0000000..0c381fd --- /dev/null +++ b/VstHost_VisualC++/external_modules/RtAudio/CMakeLists.txt @@ -0,0 +1,349 @@ +# Set minimum CMake required version for this project. +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) +# Define a C++ project. +project(RtAudio LANGUAGES CXX) + +# standards version +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +option(BUILD_SHARED_LIBS "Build as shared library" OFF) +# Check for Jack (any OS) +find_library(JACK_LIB jack) +find_package(PkgConfig) +pkg_check_modules(jack jack) +if(JACK_LIB OR jack_FOUND) + set(HAVE_JACK TRUE) +endif() + +# Check for Pulse (any OS) +pkg_check_modules(pulse libpulse-simple) + +# Check for known non-Linux unix-likes +if (CMAKE_SYSTEM_NAME MATCHES "kNetBSD.*|NetBSD.*") + message(STATUS "NetBSD detected, using OSS") + set(xBSD ON) +elseif(UNIX AND NOT APPLE) + set(LINUX ON) +endif() + +# Necessary for Windows +if(MINGW) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + set(NEED_PTHREAD ON) +endif() + +# Standard CMake options +option(BUILD_SHARED_LIBS "Build as shared library" OFF) + +if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug;Release;RelWithDebInfo;MinSizeRel") +endif() +if(WIN32) + set(CMAKE_DEBUG_POSTFIX d CACHE STRING "Postfix for debug version of library") +endif() + +# API Options +option(RTAUDIO_API_DS "Build DirectSound API" OFF) +option(RTAUDIO_API_ASIO "Build ASIO API" OFF) +option(RTAUDIO_API_WASAPI "Build WASAPI API" ${WIN32}) +option(RTAUDIO_API_OSS "Build OSS4 API" ${xBSD}) +option(RTAUDIO_API_ALSA "Build ALSA API" ${LINUX}) +option(RTAUDIO_API_PULSE "Build PulseAudio API" ${pulse_FOUND}) +option(RTAUDIO_API_JACK "Build JACK audio server API" ${HAVE_JACK}) +option(RTAUDIO_API_CORE "Build CoreAudio API" ${APPLE}) + +# Check for functions +include(CheckFunctionExists) +check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) +if (HAVE_GETTIMEOFDAY) + add_definitions(-DHAVE_GETTIMEOFDAY) +endif () + +# Add -Wall if possible +if (CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +endif (CMAKE_COMPILER_IS_GNUCXX) + +# Add debug flags +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-D__RTAUDIO_DEBUG__) + if (CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + endif (CMAKE_COMPILER_IS_GNUCXX) +endif () + +# Read libtool version info from configure.ac +set(R "m4_define\\(\\[lt_([a-z]+)\\], ([0-9]+)\\)") +file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/rtaudio/configure.ac" CONFIGAC + REGEX ${R}) +foreach(_S ${CONFIGAC}) + string(REGEX REPLACE ${R} "\\1" k ${_S}) + string(REGEX REPLACE ${R} "\\2" v ${_S}) + set(SO_${k} ${v}) +endforeach() +math(EXPR SO_current_minus_age "${SO_current} - ${SO_age}") +set(SO_VER "${SO_current_minus_age}") +set(FULL_VER "${SO_current_minus_age}.${SO_age}.${SO_revision}") + +# Read package version info from configure.ac +set(R "AC_INIT\\(RtAudio, ([0-9\\.]+),.*\\)") +file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/rtaudio/configure.ac" CONFIGAC + REGEX "${R}") +string(REGEX REPLACE "${R}" "\\1" PACKAGE_VERSION "${CONFIGAC}") + +# Init variables +set(RtAudio_SOURCES rtaudio/RtAudio.cpp rtaudio/RtAudio.h) +set(LINKLIBS) +set(PKGCONFIG_REQUIRES) +set(LIBS_REQUIRES) +set(API_DEFS) +set(API_LIST) + +# Tweak API-specific configuration. + +# Jack +if (RTAUDIO_API_JACK AND jack_FOUND) + set(NEED_PTHREAD ON) + list(APPEND PKGCONFIG_REQUIRES "jack") + list(APPEND API_DEFS "-D__UNIX_JACK__") + list(APPEND API_LIST "jack") + if(jack_FOUND) + list(APPEND LINKLIBS ${jack_LIBRARIES}) + list(APPEND INCDIRS ${jack_INCLUDEDIR}) + else() + list(APPEND LINKLIBS ${JACK_LIB}) + endif() +endif() + +# ALSA +if (RTAUDIO_API_ALSA) + set(NEED_PTHREAD ON) + find_package(ALSA) + if (NOT ALSA_FOUND) + message(FATAL_ERROR "ALSA API requested but no ALSA dev libraries found") + endif() + list(APPEND INCDIRS ${ALSA_INCLUDE_DIR}) + list(APPEND LINKLIBS ${ALSA_LIBRARIES}) + list(APPEND PKGCONFIG_REQUIRES "alsa") + list(APPEND API_DEFS "-D__LINUX_ALSA__") + list(APPEND API_LIST "alsa") +endif() + +# OSS +if (RTAUDIO_API_OSS) + set(NEED_PTHREAD ON) + find_library(OSSAUDIO_LIB ossaudio) + if (OSSAUDIO_LIB) + list(APPEND LINKLIBS ossaudio) + # Note: not an error on some systems + endif() + list(APPEND API_DEFS "-D__LINUX_OSS__") + list(APPEND API_LIST "oss") +endif() + +# Pulse +if (RTAUDIO_API_PULSE) + set(NEED_PTHREAD ON) + find_library(PULSE_LIB pulse) + find_library(PULSESIMPLE_LIB pulse-simple) + list(APPEND LINKLIBS ${PULSE_LIB} ${PULSESIMPLE_LIB}) + list(APPEND PKGCONFIG_REQUIRES "libpulse-simple") + list(APPEND API_DEFS "-D__LINUX_PULSE__") + list(APPEND API_LIST "pulse") +endif() + +# CoreAudio +if (RTAUDIO_API_CORE) + find_library(COREAUDIO_LIB CoreAudio) + find_library(COREFOUNDATION_LIB CoreFoundation) + list(APPEND LINKLIBS ${COREAUDIO_LIB} ${COREFOUNDATION_LIB}) + list(APPEND LIBS_REQUIRES "-framework CoreAudio -framework CoreFoundation") + list(APPEND API_DEFS "-D__MACOSX_CORE__") + list(APPEND API_LIST "core") +endif() + +# ASIO +if (RTAUDIO_API_ASIO) + set(NEED_WIN32LIBS ON) + include_directories(rtaudio/include) + list(APPEND RtAudio_SOURCES + rtaudio/include/asio.cpp + rtaudio/include/asiodrivers.cpp + rtaudio/include/asiolist.cpp + rtaudio/include/iasiothiscallresolver.cpp) + list(APPEND API_DEFS "-D__WINDOWS_ASIO__") + list(APPEND API_LIST "asio") +endif() + +# DSound +if (RTAUDIO_API_DS) + set(NEED_WIN32LIBS ON) + list(APPEND LINKLIBS dsound) + list(APPEND API_DEFS "-D__WINDOWS_DS__") + list(APPEND API_LIST "ds") +endif() + +# WASAPI +if (RTAUDIO_API_WASAPI) + include_directories(rtaudio/include) + set(NEED_WIN32LIBS ON) + list(APPEND LINKLIBS ksuser mfplat mfuuid wmcodecdspuuid) + list(APPEND API_DEFS "-D__WINDOWS_WASAPI__") + list(APPEND API_LIST "wasapi") +endif() + +# Windows libs +if (NEED_WIN32LIBS) + list(APPEND LINKLIBS winmm ole32) +endif() + +# pthread +if (NEED_PTHREAD) + find_package(Threads REQUIRED + CMAKE_THREAD_PREFER_PTHREAD + THREADS_PREFER_PTHREAD_FLAG) + list(APPEND LINKLIBS Threads::Threads) +endif() + +# Create library targets. +set(LIB_TARGETS) + +# Use RTAUDIO_BUILD_SHARED_LIBS / RTAUDIO_BUILD_STATIC_LIBS if they +# are defined, otherwise default to standard BUILD_SHARED_LIBS. +if (DEFINED RTAUDIO_BUILD_SHARED_LIBS) + if (RTAUDIO_BUILD_SHARED_LIBS) + add_library(rtaudio SHARED ${RtAudio_SOURCES}) + else() + + add_library(rtaudio STATIC ${RtAudio_SOURCES}) + set(RTAUDIO_IS_STATIC TRUE) + endif() +elseif (DEFINED RTAUDIO_BUILD_STATIC_LIBS) + if (RTAUDIO_BUILD_STATIC_LIBS) + add_library(rtaudio STATIC ${RtAudio_SOURCES}) + set(RTAUDIO_IS_STATIC TRUE) + else() + add_library(rtaudio SHARED ${RtAudio_SOURCES}) + endif() +else() + add_library(rtaudio ${RtAudio_SOURCES}) + if(NOT BUILD_SHARED_LIBS) + set(RTAUDIO_IS_STATIC TRUE) + endif() +endif() +list(APPEND LIB_TARGETS rtaudio) + +# Windows: If RTAUDIO_STATIC_MSVCRT is not set, it defaults to ON when building as a +# static library and OFF when building as a DLL. If you want to have more control, you +# can explicitly override RTAUDIO_STATIC_MSVCRT to turn it off/on. It controls the flags +# related to MSVC runtime linkage in the next clause, below. +if (NOT DEFINED RTAUDIO_STATIC_MSVCRT) + set(RTAUDIO_STATIC_MSVCRT ${RTAUDIO_IS_STATIC}) +endif() + +# In MSVC, set MD/MT appropriately for a static library +# (From https://github.com/protocolbuffers/protobuf/blob/master/cmake/CMakeLists.txt) +if(MSVC AND RTAUDIO_STATIC_MSVCRT) + foreach(flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif(${flag_var} MATCHES "/MD") + endforeach(flag_var) +endif() + +set_target_properties(rtaudio PROPERTIES + SOVERSION ${SO_VER} + VERSION ${FULL_VER}) + +# Set standard installation directories. +include(GNUInstallDirs) + +# Set include paths, populate target interface. +target_include_directories(rtaudio + PUBLIC + $ + $ + PRIVATE + ${INCDIRS} +) + +# Set compile-time definitions +target_compile_definitions(rtaudio PRIVATE ${API_DEFS}) +target_compile_definitions(rtaudio PRIVATE RTAUDIO_EXPORT) +target_link_libraries(rtaudio ${LINKLIBS}) + + +# Message +string(REPLACE ";" " " apilist "${API_LIST}") +message(STATUS "Compiling with support for: ${apilist}") + +# PkgConfig file +string(REPLACE ";" " " req "${PKGCONFIG_REQUIRES}") +string(REPLACE ";" " " req_libs "${LIBS_REQUIRES}") +string(REPLACE ";" " " api "${API_DEFS}") +set(prefix ${CMAKE_INSTALL_PREFIX}) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/rtaudio/rtaudio.pc.in" "rtaudio.pc" @ONLY) + +# Add install rule. +install(TARGETS ${LIB_TARGETS} + EXPORT RtAudioTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rtaudio) + +# Install public header files +install(FILES RtAudio.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rtaudio) + +# Store the package in the user registry. +export(PACKAGE RtAudio) + +# Set installation path for CMake files. +set(RTAUDIO_CMAKE_DESTINATION share/rtaudio) + +# Create CMake configuration export file. +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfig.cmake.in "@PACKAGE_INIT@\n") + +if(NEED_PTHREAD) + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfig.cmake.in "find_package(Threads REQUIRED)\n") +endif() + +file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfig.cmake.in "include(\${CMAKE_CURRENT_LIST_DIR}/RtAudioTargets.cmake)") + +# Install CMake configuration export file. +include(CMakePackageConfigHelpers) +configure_package_config_file( + ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfig.cmake + INSTALL_DESTINATION ${RTAUDIO_CMAKE_DESTINATION} +) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfig-version.cmake + VERSION ${FULL_VER} + COMPATIBILITY AnyNewerVersion +) + +install( + FILES + ${CMAKE_BINARY_DIR}/RtAudioConfig.cmake + ${CMAKE_BINARY_DIR}/RtAudioConfig-version.cmake + DESTINATION + ${RTAUDIO_CMAKE_DESTINATION} +) + +# Export library target (build-tree). +export(EXPORT RtAudioTargets + NAMESPACE RtAudio::) + +# Export library target (install-tree). +install(EXPORT RtAudioTargets + DESTINATION ${RTAUDIO_CMAKE_DESTINATION} + NAMESPACE RtAudio::) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/rtaudio.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) diff --git a/VstHost_VisualC++/external_modules/RtAudio/rtaudio b/VstHost_VisualC++/external_modules/RtAudio/rtaudio new file mode 160000 index 0000000..13a5839 --- /dev/null +++ b/VstHost_VisualC++/external_modules/RtAudio/rtaudio @@ -0,0 +1 @@ +Subproject commit 13a583912155f58a1289175a12f02d8fb9d930dc diff --git a/VstHost_VisualC++/modules/ArgParser/src/arg_parser.cpp b/VstHost_VisualC++/modules/ArgParser/src/arg_parser.cpp index 215ee67..c6010d8 100644 --- a/VstHost_VisualC++/modules/ArgParser/src/arg_parser.cpp +++ b/VstHost_VisualC++/modules/ArgParser/src/arg_parser.cpp @@ -81,6 +81,7 @@ int ArgParser::ParsParameters(std::vector args) int status = VST_ERROR_STATUS::SUCCESS; dump_tool_config_ = arg_parser_->get(DUMP_CMD_PARAM_STR); dump_plugin_params_ = arg_parser_->get(DUMP_PLUGINS_CONFIGS); + enable_audio_capture_ = arg_parser_->get("-enable_audio_capture"); if (dump_tool_config_) { @@ -109,7 +110,7 @@ int ArgParser::ParsParameters(std::vector args) } return status; } - else + else if (!enable_audio_capture_) { status = this->ValidateVstHostConfigParam(); @@ -133,7 +134,7 @@ int ArgParser::ParsParameters(std::vector args) } verbosity_ = static_cast(arg_parser_->get("-verbosity")); - enable_audio_capture_ = arg_parser_->get("-enable_audio_capture"); + return status; } diff --git a/VstHost_VisualC++/modules/AudioEndpointManager/CMakeLists.txt b/VstHost_VisualC++/modules/AudioEndpointManager/CMakeLists.txt index 46b2fbf..0c10d61 100644 --- a/VstHost_VisualC++/modules/AudioEndpointManager/CMakeLists.txt +++ b/VstHost_VisualC++/modules/AudioEndpointManager/CMakeLists.txt @@ -1,18 +1,19 @@ if(SMTG_LINUX) message("[WARNING] Audio Endpoint Manager for Linux is not implemented.") elseif(SMTG_WIN) - set(target AudioEndpointManager) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../external_modules/RtAudio/rtaudio/) + + set(target AudioEndpointManager) set(audio_enpoint_manager_headers header/AudioEndpointManager.h ) - set(audio_enpoint_manager_src source/AudioEndpointManager.cpp ) + add_library(${target} ${audio_enpoint_manager_src} ${audio_enpoint_manager_headers}) + target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/header) + target_compile_features(${target} PUBLIC cxx_std_17) + target_link_libraries(${target} PRIVATE Common Logger AudioCapture AudioRender rtaudio AudioEndpointBase) - add_library(${target} ${audio_enpoint_manager_src} ${audio_enpoint_manager_headers}) - target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/header) - target_compile_features(${target} PUBLIC cxx_std_17) - target_link_libraries(${target} PRIVATE Common Logger AudioCapture AudioRender AudioEndpointBase) endif(SMTG_LINUX) diff --git a/VstHost_VisualC++/modules/AudioEndpointManager/source/AudioEndpointManager.cpp b/VstHost_VisualC++/modules/AudioEndpointManager/source/AudioEndpointManager.cpp index af26182..c3d39e2 100644 --- a/VstHost_VisualC++/modules/AudioEndpointManager/source/AudioEndpointManager.cpp +++ b/VstHost_VisualC++/modules/AudioEndpointManager/source/AudioEndpointManager.cpp @@ -5,6 +5,12 @@ #include "VstHostMacro.h" #include "AudioEndpointManager.h" +#include "RtAudio.h" +#include +#include +#include +typedef double MY_TYPE; +#define FORMAT RTAUDIO_FLOAT64 #undef max AudioEndpointManager::AudioEndpointManager(uint8_t verbose) : @@ -39,50 +45,94 @@ int AudioEndpointManager::RunAudioRender() return audio_render_->RenderAudioStream(); } + +unsigned int getDeviceIndex(std::vector deviceNames, bool isInput = false) +{ + unsigned int i; + std::string keyHit; + std::cout << '\n'; + for (i = 0; i < deviceNames.size(); i++) + std::cout << " Device #" << i << ": " << deviceNames[i] << '\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::getline(std::cin, keyHit); // used to clear out stdin + return i; +} + +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) +{ + // 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; + + if (streamTime >= streamTimePrintTime) { + std::cout << "streamTime = " << streamTime << std::endl; + streamTimePrintTime += streamTimePrintIncrement; + } + + unsigned int* bytes = (unsigned int*)data; + memcpy(outputBuffer, inputBuffer, *bytes); + return 0; +} + int AudioEndpointManager::RunAudioEndpointHandler() { - // TODO: - // 1) Create queue - // 2) Write to queue in RecordAudioStream - // 3) Read from queue and write to file on other thread - // 4) Render data from queue - // 5) Put data from queue throught the plugin and render processed results. - // 6) First init audio render - it will render zeros or noise, but there will be minimal latency. - // The target for latency should be 1ms to 5 ms. Latency should be adjustable. - // 7) try to work on exclusive mode - use wasapi sample. Support for shared and exclusive - // mode should be provided. - - HRESULT stat = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); - if (!SUCCEEDED(stat)) - { - return VST_ERROR_STATUS::AUDIO_ENDPOINT_MANAGER_ERROR; + RtAudio adac; + std::vector deviceIds = adac.getDeviceIds(); + if (deviceIds.size() < 1) { + std::cout << "\nNo audio devices found!\n"; + exit(0); } - audio_capture_.reset(new AudioCapture(verbose_)); - RETURN_ERROR_IF_ENDPOINT_ERROR(audio_capture_->Init()); + // Set the same number of channels for both input and output. + unsigned int bufferBytes, 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]; + + 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; + } - uint32_t capture_sampling_rate; - RETURN_ERROR_IF_ENDPOINT_ERROR(audio_capture_->GetEndpointSamplingRate(&capture_sampling_rate)); - LOG(INFO) << "Capture sampling rate: " << capture_sampling_rate; + if (adac.isStreamOpen() == false) goto cleanup; - audio_render_.reset(new AudioRender()); - RETURN_ERROR_IF_ENDPOINT_ERROR(audio_render_->Init()); + // Test RtAudio functionality for reporting latency. + std::cout << "\nStream latency = " << adac.getStreamLatency() << " frames" << std::endl; - uint32_t render_sampling_rate; - RETURN_ERROR_IF_ENDPOINT_ERROR(audio_render_->GetEndpointSamplingRate(&render_sampling_rate)); - LOG(INFO) << "Render sampling rate: " << render_sampling_rate; + if (adac.startStream()) goto cleanup; - if (render_sampling_rate != capture_sampling_rate) - { - CoUninitialize(); - LOG(ERROR) << "Sampling rate of render and capture miss match."; - return VST_ERROR_STATUS::ENPOINTS_SAMPLING_RATE_MISS_MATCH; - } + char input; + std::cout << "\nRunning ... press to quit (buffer frames = " << bufferFrames << ").\n"; + std::cin.get(input); + + // Stop the stream. + if (adac.isStreamRunning()) + adac.stopStream(); - RETURN_ERROR_IF_ENDPOINT_ERROR(this->RunAudioCapture()); +cleanup: + if (adac.isStreamOpen()) adac.closeStream(); - int status = this->RunAudioRender(); - CoUninitialize(); - return status; + return 0; } diff --git a/VstHost_VisualC++/modules/CMakeLists.txt b/VstHost_VisualC++/modules/CMakeLists.txt index 33dd446..d730bf6 100644 --- a/VstHost_VisualC++/modules/CMakeLists.txt +++ b/VstHost_VisualC++/modules/CMakeLists.txt @@ -1,16 +1,16 @@ if (MSVC) - add_compile_options(/W4 /WX) - add_link_options(/WX) + add_compile_options(/W4 /WX) + add_link_options(/WX) elseif (UNIX AND !${ANDROID_BUILD}) add_compile_options(-Werror -Wextra) elseif(LINUX) find_program(GCOV_PATH gcov) if(NOT GCOV_PATH) - message(${GCOV_PATH}) - message("[WARNING] Code coverage analysis requires gcov!") + message(${GCOV_PATH}) + message("[WARNING] Code coverage analysis requires gcov!") else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") - message("[MESSAGE] Code coverage analysis found gcov!") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") + message("[MESSAGE] Code coverage analysis found gcov!") endif() endif()