1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#include "audioio.h"
#include <exception>
#include <iostream>
#include <portaudiocpp/AutoSystem.hxx>
#include <portaudiocpp/CallbackInterface.hxx>
#include <portaudiocpp/Device.hxx>
#include <portaudiocpp/InterfaceCallbackStream.hxx>
#include <portaudiocpp/StreamParameters.hxx>
#include <portaudiocpp/System.hxx>
#include <portaudiocpp/SystemDeviceIterator.hxx>
namespace {
class Callback: public portaudio::CallbackInterface {
public:
Callback(int size): mBuffer(size){}
std::vector<std::complex<double>> mBuffer;
int paCallbackFun( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags ) override
{
std::cout << "Callback" << std::endl;
float* buf = (float*)inputBuffer;
for (int i = 0; i < framesPerBuffer; i++) {
mBuffer[i] = buf[i];
}
return 0;
}
};
int bufferSizeFromSampleRate(double sampleRate) {
int result = 1;
while (result < sampleRate)
result <<= 1;
result /= 32;
if (result < 1024)
throw std::runtime_error(std::string("Bad buffer size ") + std::to_string(result) + " for sample rate " + std::to_string(sampleRate));
return result;
}
void printDeviceList() {
portaudio::System& mSystem = portaudio::System::instance();
std::cout << "Number of Devices: " << mSystem.deviceCount() << std::endl;
std::for_each(mSystem.devicesBegin(), mSystem.devicesEnd(),
[](const portaudio::Device& device){ std::cout
<< "Device Name: " << device.name()
<< " Default Rate: " << device.defaultSampleRate()
<< std::endl;
}
);
}
} // namespace
struct RIT::AudioIO::Impl {
Impl()
: mAudioSystem()
, mSystem(portaudio::System::instance())
, mDevice(mSystem.defaultInputDevice())
, mSampleRate(mDevice.defaultSampleRate())
, mSize(bufferSizeFromSampleRate(mSampleRate))
, mInputParams(mDevice, 1, portaudio::FLOAT32, false, mDevice.defaultLowInputLatency(), nullptr)
, mOutputParams(portaudio::System::nullDevice(), 0, portaudio::FLOAT32, false, mDevice.defaultLowInputLatency(), nullptr)
, mParameters(mInputParams, mOutputParams, mSampleRate, mSize, paNoFlag)
, mCallback(mSize)
, mStream(mParameters, mCallback)
{
printDeviceList();
mStream.start();
if (!mStream.isOpen())
throw std::runtime_error("Error: Stream not open");
if (!mStream.isActive())
throw std::runtime_error("Error: Stream not active");
std::cout << "Activated Device: " << mDevice.name() << " at " << mSampleRate << " Hz, buffer: " << mSize << " samples, running..." << std::endl;
}
~Impl() {}
// Port audio specific
portaudio::AutoSystem mAudioSystem; // init / deinit portaudio
portaudio::System& mSystem;
portaudio::Device& mDevice;
double mSampleRate;
int mSize;
portaudio::DirectionSpecificStreamParameters mInputParams;
portaudio::DirectionSpecificStreamParameters mOutputParams;
portaudio::StreamParameters mParameters;
Callback mCallback;
portaudio::InterfaceCallbackStream mStream;
};
RIT::AudioIO::AudioIO(): mImpl(std::make_unique<AudioIO::Impl>())
{
}
RIT::AudioIO::~AudioIO()
{
}
std::vector<std::complex<double>> RIT::AudioIO::sample()
{
return mImpl->mCallback.mBuffer; // TODO: thread synchronization! Ringbuffer? PaUtilRingBuffer?
}
int RIT::AudioIO::size() const
{
return mImpl->mSize;
}
int RIT::AudioIO::sampleFrequency() const
{
return int(mImpl->mSampleRate);
}
|