Skip to content

Commit

Permalink
Clean up RT Audio Integration Code (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
RinoReyns authored Oct 30, 2024
1 parent 6696481 commit 44caab4
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 69 deletions.
3 changes: 3 additions & 0 deletions VstHost_Python/UnitTests/test_c_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,32 @@
#include "easylogging++.h"
#include "AudioCapture.h"
#include "AudioRender.h"

#include "RtAudio.h"

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<AudioCapture> audio_capture_;
std::unique_ptr<AudioRender> audio_render_;
std::unique_ptr<RtAudio> adac_;
std::vector<unsigned int> device_ids_;
size_t buffer_bytes_;
uint8_t verbose_ = 0;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#include <chrono>
#include <thread>
#include <future>
#include <iostream>
#include <cstdlib>
#include <cstring>

#include "VstHostMacro.h"
#include "AudioEndpointManager.h"

#include "RtAudio.h"
#include <iostream>
#include <cstdlib>
#include <cstring>
typedef double MY_TYPE;
#define FORMAT RTAUDIO_FLOAT64
#undef max
Expand All @@ -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,
Expand All @@ -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<std::string> 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<std::string> 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<AudioEndpointManager*>(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<unsigned int> 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 <enter> to quit (buffer frames = " << bufferFrames << ").";
char input;
std::cout << "\nRunning ... press <enter> 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;
}
3 changes: 2 additions & 1 deletion VstHost_VisualC++/modules/Common/header/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion VstHost_VisualC++/modules/VstHostTool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 1 addition & 6 deletions VstHost_VisualC++/modules/VstHostTool/src/VstHostTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,10 @@ int VstHostTool::ParsArgs()

int VstHostTool::EndpointProcessingPipeline()
{

#ifdef _WIN32
std::unique_ptr<AudioEndpointManager> 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;
}

Expand Down

0 comments on commit 44caab4

Please sign in to comment.