simple recording functionality for later encoding tests

pull/18/head
Dimitri Diakopoulos 10 years ago
parent 26713c3fd8
commit 20d12d7f97

@ -83,9 +83,20 @@ int main(int argc, const char **argv) try
// 1 + 2 channel musepack
//loader.Load(fileData.get(), "test_data/ad_hoc/44_16_stereo.mpc");
loader.Load(fileData.get(), "test_data/ad_hoc/44_16_mono.mpc");
//loader.Load(fileData.get(), "test_data/ad_hoc/44_16_mono.mpc");
}
fileData->samples.reserve(44100 * 2);
fileData->channelCount = 1;
fileData->frameSize = 32;
fileData->lengthSeconds = 2.0;
fileData->sampleRate = 44100;
// Test Recording Capabilities of Audio Device
std::cout << "Starting recording for two seconds..." << std::endl;
std::vector<float> recordingBuffer;
myDevice.Record(44100 * 2, fileData->samples);
// Libnyquist does not (currently) perform sample rate conversion
if (fileData->sampleRate != desiredSampleRate)
{
@ -106,8 +117,8 @@ int main(int argc, const char **argv) try
myDevice.Play(fileData->samples);
}
int encoderStatus = WavEncoder::WriteFile({2, PCM_16, DITHER_NONE }, fileData.get(), "encoded.wav");
std::cout << "Encoder Status: " << encoderStatus << std::endl;
//int encoderStatus = WavEncoder::WriteFile({2, PCM_16, DITHER_NONE }, fileData.get(), "encoded.wav");
//std::cout << "Encoder Status: " << encoderStatus << std::endl;
return EXIT_SUCCESS;
}

@ -23,70 +23,49 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// This file implements a simple sound file player based on RtAudio for testing / example purposes.
#ifndef AUDIO_DEVICE_H
#define AUDIO_DEVICE_H
// This file implements a simple sound file player based on RtAudio for testing / example purposes.
#include "Common.h"
#include "RingBuffer.h"
#include "rtaudio/RtAudio.h"
#include <iostream>
#include <memory>
namespace nqr
{
const uint32_t FRAME_SIZE = 512;
const int32_t CHANNELS = 2;
const int32_t BUFFER_LENGTH = FRAME_SIZE * CHANNELS;
const uint32_t FRAME_SIZE = 512;
const int32_t CHANNELS = 2;
const int32_t BUFFER_LENGTH = FRAME_SIZE * CHANNELS;
struct AudioDeviceInfo
{
struct AudioDeviceInfo
{
uint32_t id;
uint32_t numChannels;
uint32_t sampleRate;
uint32_t frameSize;
bool isPlaying = false;
};
};
class AudioDevice
{
class AudioDevice
{
NO_MOVE(AudioDevice);
std::unique_ptr<RtAudio> rtaudio;
public:
public:
AudioDeviceInfo info;
AudioDevice(int numChannels, int sampleRate, int deviceId = -1)
{
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()
{
if (rtaudio)
{
rtaudio->stopStream();
if (rtaudio->isStreamOpen())
{
rtaudio->closeStream();
}
}
}
AudioDevice(int numChannels, int sampleRate, int deviceId = -1);
~AudioDevice();
bool Open(const int deviceId);
bool Play(const std::vector<float> & data);
bool Record(const uint32_t lengthInSamples, std::vector<float> & recordingBuffer);
static void ListAudioDevices();
};
};
} // end namespace nqr

@ -26,6 +26,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef LIBNYQUIST_COMMON_H
#define LIBNYQUIST_COMMON_H
#include <memory>
#include <vector>
#include <algorithm>
#include <cmath>
@ -36,6 +37,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <type_traits>
#include <numeric>
#include <array>
#include "PostProcess.h"
#include "Dither.h"

@ -43,18 +43,12 @@ class RingBufferT
public:
// Constructs a RingBufferT with size = 0
RingBufferT() : mData(nullptr), mAllocatedSize(0), mWriteIndex(0), mReadIndex(0) {
}
RingBufferT() : mData(nullptr), mAllocatedSize(0), mWriteIndex(0), mReadIndex(0) {}
// Constructs a RingBufferT with \a count maximum elements.
RingBufferT(size_t count) : mAllocatedSize(0)
{
resize(count);
}
RingBufferT(size_t count) : mAllocatedSize(0) { resize(count); }
RingBufferT(RingBufferT &&other)
: mData(other.mData), mAllocatedSize(other.mAllocatedSize), mWriteIndex(0), mReadIndex(0)
RingBufferT(RingBufferT &&other) : mData(other.mData), mAllocatedSize(other.mAllocatedSize), mWriteIndex(0), mReadIndex(0)
{
other.mData = nullptr;
other.mAllocatedSize = 0;
@ -81,7 +75,7 @@ class RingBufferT
clear();
}
// Invalidates the internal buffer and resets read / write indices to 0. \note Must be synchronized with both read and write threads.
// Invalidates the internal buffer and resets read / write indices to 0. Must be synchronized with both read and write threads.
void clear()
{
mWriteIndex = 0;
@ -91,16 +85,16 @@ class RingBufferT
// Returns the maximum number of elements.
size_t getSize() const
{
return mAllocatedSize - 1;
}
// Returns the number of elements available for wrtiing. \note Only safe to call from the write thread.
// Returns the number of elements available for writing. Only safe to call from the write thread.
size_t getAvailableWrite() const
{
return getAvailableWrite(mWriteIndex, mReadIndex);
}
// Returns the number of elements available for wrtiing. \note Only safe to call from the read thread.
// Returns the number of elements available for reading. Only safe to call from the read thread.
size_t getAvailableRead() const
{
return getAvailableRead(mWriteIndex, mReadIndex);
@ -188,7 +182,7 @@ class RingBufferT
return writeIndex + mAllocatedSize - readIndex;
}
T *mData;
T * mData;
size_t mAllocatedSize;
std::atomic<size_t> mWriteIndex, mReadIndex;
};
@ -196,4 +190,3 @@ class RingBufferT
typedef RingBufferT<float> RingBuffer;
#endif

@ -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,7 +121,7 @@ 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++;
@ -107,3 +129,26 @@ bool AudioDevice::Play(const std::vector<float> & data)
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;
}

Loading…
Cancel
Save