|
|
|
|
@ -32,23 +32,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
using namespace nqr;
|
|
|
|
|
|
|
|
|
|
static RingBufferT<float> buffer(BUFFER_LENGTH);
|
|
|
|
|
static RingBufferT<float> record_buffer(BUFFER_LENGTH / 2);
|
|
|
|
|
|
|
|
|
|
static int rt_callback(void * output_buffer, void * input_buffer, uint32_t num_bufferframes, double stream_time, RtAudioStreamStatus status, void * user_data)
|
|
|
|
|
{
|
|
|
|
|
if (status) std::cerr << "[rtaudio] Buffer over or underflow" << std::endl;
|
|
|
|
|
if (status) std::cerr << "[rtaudio] buffer over or underflow" << std::endl;
|
|
|
|
|
|
|
|
|
|
if (buffer.getAvailableRead())
|
|
|
|
|
{
|
|
|
|
|
buffer.read((float*) output_buffer, BUFFER_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memset(output_buffer, 0, BUFFER_LENGTH * sizeof(float));
|
|
|
|
|
}
|
|
|
|
|
// Playback
|
|
|
|
|
if (buffer.getAvailableRead()) buffer.read((float*) output_buffer, BUFFER_LENGTH);
|
|
|
|
|
else memset(output_buffer, 0, BUFFER_LENGTH * sizeof(float));
|
|
|
|
|
|
|
|
|
|
// Recording
|
|
|
|
|
if (record_buffer.getAvailableWrite()) record_buffer.write((float*) input_buffer, BUFFER_LENGTH / 2);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AudioDevice::AudioDevice(int numChannels, int sampleRate, int deviceId)
|
|
|
|
|
{
|
|
|
|
|
rtaudio = std::unique_ptr<RtAudio>(new RtAudio);
|
|
|
|
|
info.id = (deviceId != -1) ? deviceId : rtaudio->getDefaultOutputDevice();
|
|
|
|
|
info.numChannels = numChannels;
|
|
|
|
|
info.sampleRate = sampleRate;
|
|
|
|
|
info.frameSize = FRAME_SIZE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AudioDevice::~AudioDevice()
|
|
|
|
|
{
|
|
|
|
|
if (rtaudio)
|
|
|
|
|
{
|
|
|
|
|
rtaudio->stopStream();
|
|
|
|
|
if (rtaudio->isStreamOpen())
|
|
|
|
|
{
|
|
|
|
|
rtaudio->closeStream();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AudioDevice::Open(const int deviceId)
|
|
|
|
|
{
|
|
|
|
|
if (!rtaudio) throw std::runtime_error("rtaudio not created yet");
|
|
|
|
|
@ -59,10 +79,12 @@ bool AudioDevice::Open(const int deviceId)
|
|
|
|
|
outputParams.firstChannel = 0;
|
|
|
|
|
|
|
|
|
|
RtAudio::StreamParameters inputParams;
|
|
|
|
|
inputParams.deviceId = info.id;
|
|
|
|
|
inputParams.nChannels = info.numChannels;
|
|
|
|
|
inputParams.deviceId = rtaudio->getDefaultInputDevice();
|
|
|
|
|
inputParams.nChannels = 1;
|
|
|
|
|
inputParams.firstChannel = 0;
|
|
|
|
|
|
|
|
|
|
std::cout << "Input Device Id: " << inputParams.deviceId << std::endl;
|
|
|
|
|
|
|
|
|
|
rtaudio->openStream(&outputParams, &inputParams, RTAUDIO_FLOAT32, info.sampleRate, &info.frameSize, &rt_callback, (void*) & buffer);
|
|
|
|
|
|
|
|
|
|
if (rtaudio->isStreamOpen())
|
|
|
|
|
@ -99,11 +121,34 @@ bool AudioDevice::Play(const std::vector<float> & data)
|
|
|
|
|
|
|
|
|
|
int writeCount = 0;
|
|
|
|
|
|
|
|
|
|
while(writeCount < sizeInFrames)
|
|
|
|
|
while (writeCount < sizeInFrames)
|
|
|
|
|
{
|
|
|
|
|
bool status = buffer.write((data.data() + (writeCount * BUFFER_LENGTH)), BUFFER_LENGTH);
|
|
|
|
|
if (status) writeCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AudioDevice::Record(const uint32_t lengthInSamples, std::vector<float> & recordingBuffer)
|
|
|
|
|
{
|
|
|
|
|
uint32_t recordedSamples = 0;
|
|
|
|
|
|
|
|
|
|
// Allocate memory upfront (revisit this later...)
|
|
|
|
|
recordingBuffer.resize(lengthInSamples + (BUFFER_LENGTH)); // + a little padding
|
|
|
|
|
|
|
|
|
|
while (recordedSamples < lengthInSamples)
|
|
|
|
|
{
|
|
|
|
|
if (record_buffer.getAvailableRead())
|
|
|
|
|
{
|
|
|
|
|
if(record_buffer.read(recordingBuffer.data() + recordedSamples, BUFFER_LENGTH / 2))
|
|
|
|
|
{
|
|
|
|
|
recordedSamples += (BUFFER_LENGTH / 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::cout << recordedSamples << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|