framework2
318 строк · 9.6 Кб
1#include "ofRtAudioSoundStream.h"
2#include "ofMath.h"
3#include "ofUtils.h"
4#include "ofAppRunner.h"
5#include "ofLog.h"
6#include "RtAudio.h"
7
8using std::vector;
9using std::shared_ptr;
10
11//------------------------------------------------------------------------------
12RtAudio::Api toRtAudio(ofSoundDevice::Api api){
13switch (api) {
14case ofSoundDevice::Api::ALSA:
15return RtAudio::Api::LINUX_ALSA;
16case ofSoundDevice::Api::PULSE:
17return RtAudio::Api::LINUX_PULSE;
18case ofSoundDevice::Api::OSS:
19return RtAudio::Api::LINUX_OSS;
20case ofSoundDevice::Api::JACK:
21return RtAudio::Api::UNIX_JACK;
22#ifndef TARGET_LINUX
23case ofSoundDevice::Api::OSX_CORE:
24return RtAudio::Api::MACOSX_CORE;
25case ofSoundDevice::Api::MS_WASAPI:
26return RtAudio::Api::WINDOWS_WASAPI;
27case ofSoundDevice::Api::MS_ASIO:
28return RtAudio::Api::WINDOWS_ASIO;
29case ofSoundDevice::Api::MS_DS:
30return RtAudio::Api::WINDOWS_DS;
31#endif
32default:
33return RtAudio::Api::UNSPECIFIED;
34}
35}
36
37//------------------------------------------------------------------------------
38ofSoundDevice::Api toOf(RtAudio::Api api){
39switch (api) {
40case RtAudio::Api::LINUX_ALSA:
41return ofSoundDevice::Api::ALSA;
42case RtAudio::Api::LINUX_PULSE:
43return ofSoundDevice::Api::PULSE;
44case RtAudio::Api::LINUX_OSS:
45return ofSoundDevice::Api::OSS;
46case RtAudio::Api::UNIX_JACK:
47return ofSoundDevice::Api::JACK;
48#ifndef TARGET_LINUX
49case RtAudio::Api::MACOSX_CORE:
50return ofSoundDevice::Api::OSX_CORE;
51case RtAudio::Api::WINDOWS_WASAPI:
52return ofSoundDevice::Api::MS_WASAPI;
53case RtAudio::Api::WINDOWS_ASIO:
54return ofSoundDevice::Api::MS_ASIO;
55case RtAudio::Api::WINDOWS_DS:
56return ofSoundDevice::Api::MS_DS;
57#endif
58default:
59return ofSoundDevice::Api::UNSPECIFIED;
60}
61}
62
63//------------------------------------------------------------------------------
64ofRtAudioSoundStream::ofRtAudioSoundStream() {
65tickCount = 0;
66}
67
68//------------------------------------------------------------------------------
69ofRtAudioSoundStream::~ofRtAudioSoundStream() {
70stop();
71close();
72}
73
74//------------------------------------------------------------------------------
75std::vector<ofSoundDevice> ofRtAudioSoundStream::getDeviceList(ofSoundDevice::Api api) const{
76vector<ofSoundDevice> deviceList;
77try {
78auto rtAudioApi = toRtAudio(api);
79RtAudio audioTemp(toRtAudio(api));
80audioTemp.showWarnings(false);
81if(audioTemp.getCurrentApi()!=rtAudioApi && rtAudioApi!=RtAudio::Api::UNSPECIFIED){
82return deviceList;
83}
84auto deviceCount = audioTemp.getDeviceCount();
85RtAudio::DeviceInfo info;
86for (unsigned int i = 0; i < deviceCount; i++) {
87try {
88info = audioTemp.getDeviceInfo(i);
89}
90catch (std::exception &error) {
91ofLogError("ofRtAudioSoundStream") << "Error retrieving info for device " << i;
92ofLogError() << error.what();
93break;
94}
95
96ofSoundDevice dev;
97dev.deviceID = i;
98dev.name = info.name;
99dev.outputChannels = info.outputChannels;
100dev.inputChannels = info.inputChannels;
101dev.sampleRates = info.sampleRates;
102dev.isDefaultInput = info.isDefaultInput;
103dev.isDefaultOutput = info.isDefaultOutput;
104dev.api = api;
105deviceList.push_back(dev);
106}
107}catch (std::exception &error) {
108ofLogError() << error.what();
109}
110
111return deviceList;
112
113}
114
115//------------------------------------------------------------------------------
116void ofRtAudioSoundStream::setInput(ofBaseSoundInput * soundInput) {
117settings.setInListener(soundInput);
118}
119
120//------------------------------------------------------------------------------
121void ofRtAudioSoundStream::setOutput(ofBaseSoundOutput * soundOutput) {
122settings.setOutListener(soundOutput);
123}
124
125//------------------------------------------------------------------------------
126bool ofRtAudioSoundStream::setup(const ofSoundStreamSettings & settings_)
127{
128if (audio != nullptr) {
129close();
130}
131
132this->settings = settings_;
133
134tickCount = 0;
135this->settings.bufferSize = ofNextPow2(settings.bufferSize); // must be pow2
136
137try {
138if (settings.getApi() != ofSoundDevice::Api::UNSPECIFIED) {
139audio = std::make_shared<RtAudio>(toRtAudio(settings.getApi()));
140}else{
141audio = std::make_shared<RtAudio>();
142}
143}
144catch (std::exception &error) {
145ofLogError() << error.what();
146return false;
147}
148
149RtAudio::StreamParameters outputParameters;
150RtAudio::StreamParameters inputParameters;
151if (settings.numInputChannels > 0) {
152if (!settings.getInDevice()) {
153ofSoundDevice device;
154device.deviceID = audio->getDefaultInputDevice();
155settings.setInDevice(device);
156}
157inputParameters.deviceId = settings.getInDevice()->deviceID;
158inputParameters.nChannels = settings.numInputChannels;
159}
160
161if (settings.numOutputChannels > 0) {
162if (!settings.getOutDevice()) {
163ofSoundDevice device;
164device.deviceID = audio->getDefaultOutputDevice();
165settings.setOutDevice(device);
166}
167outputParameters.deviceId = settings.getOutDevice()->deviceID;
168outputParameters.nChannels = settings.numOutputChannels;
169}
170
171RtAudio::StreamOptions options;
172options.flags = RTAUDIO_SCHEDULE_REALTIME;
173options.numberOfBuffers = settings.numBuffers;
174options.priority = 1;
175outputBuffer.setDeviceID(outputParameters.deviceId);
176inputBuffer.setDeviceID(inputParameters.deviceId);
177outputBuffer.setSampleRate(settings.sampleRate);
178inputBuffer.setSampleRate(settings.sampleRate);
179unsigned int bufferSize = settings.bufferSize;
180try {
181audio->openStream((settings.numOutputChannels > 0) ? &outputParameters : nullptr, (settings.numInputChannels > 0) ? &inputParameters : nullptr, RTAUDIO_FLOAT32,
182settings.sampleRate, &bufferSize, &rtAudioCallback, this, &options);
183audio->startStream();
184}
185catch (std::exception &error) {
186ofLogError() << error.what();
187return false;
188}
189return true;
190}
191
192//------------------------------------------------------------------------------
193void ofRtAudioSoundStream::start() {
194if (audio == nullptr) return;
195
196try {
197audio->startStream();
198}
199catch (std::exception &error) {
200ofLogError() << error.what();
201}
202}
203
204//------------------------------------------------------------------------------
205void ofRtAudioSoundStream::stop() {
206if (audio == nullptr) return;
207
208try {
209if (audio->isStreamRunning()) {
210audio->stopStream();
211}
212}
213catch (std::exception &error) {
214ofLogError() << error.what();
215}
216}
217
218//------------------------------------------------------------------------------
219void ofRtAudioSoundStream::close() {
220if (audio == nullptr) return;
221
222try {
223if (audio->isStreamOpen()) {
224audio->closeStream();
225}
226}
227catch (std::exception &error) {
228ofLogError() << error.what();
229}
230settings.outCallback = nullptr;
231settings.inCallback = nullptr;
232audio.reset(); // delete
233}
234
235//------------------------------------------------------------------------------
236uint64_t ofRtAudioSoundStream::getTickCount() const {
237return tickCount;
238}
239
240//------------------------------------------------------------------------------
241int ofRtAudioSoundStream::getNumInputChannels() const {
242return settings.numInputChannels;
243}
244
245//------------------------------------------------------------------------------
246int ofRtAudioSoundStream::getNumOutputChannels() const {
247return settings.numOutputChannels;
248}
249
250//------------------------------------------------------------------------------
251int ofRtAudioSoundStream::getSampleRate() const {
252return settings.sampleRate;
253}
254
255//------------------------------------------------------------------------------
256int ofRtAudioSoundStream::getBufferSize() const {
257return settings.bufferSize;
258}
259
260ofSoundDevice ofRtAudioSoundStream::getInDevice() const{
261return *settings.getInDevice();
262}
263
264ofSoundDevice ofRtAudioSoundStream::getOutDevice() const{
265return *settings.getOutDevice();
266}
267
268//------------------------------------------------------------------------------
269int ofRtAudioSoundStream::rtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFramesPerBuffer, double streamTime, RtAudioStreamStatus status, void *data) {
270ofRtAudioSoundStream * rtStreamPtr = (ofRtAudioSoundStream *)data;
271
272if (status) {
273ofLogWarning("ofRtAudioSoundStream") << "stream over/underflow detected";
274}
275
276// rtAudio uses a system by which the audio
277// can be of different formats
278// char, float, etc.
279// we choose float
280float * fPtrOut = (float *)outputBuffer;
281float * fPtrIn = (float *)inputBuffer;
282// [zach] memset output to zero before output call
283// this is because of how rtAudio works: duplex w/ one callback
284// you need to cut in the middle. if the simpleApp
285// doesn't produce audio, we pass silence instead of duplex...
286
287size_t nInputChannels = rtStreamPtr->getNumInputChannels();
288size_t nOutputChannels = rtStreamPtr->getNumOutputChannels();
289
290if (nInputChannels > 0) {
291if (rtStreamPtr->settings.inCallback) {
292rtStreamPtr->inputBuffer.copyFrom(fPtrIn, nFramesPerBuffer, nInputChannels, rtStreamPtr->getSampleRate());
293rtStreamPtr->inputBuffer.setTickCount(rtStreamPtr->tickCount);
294rtStreamPtr->settings.inCallback(rtStreamPtr->inputBuffer);
295}
296// [damian] not sure what this is for? assuming it's for underruns? or for when the sound system becomes broken?
297memset(fPtrIn, 0, nFramesPerBuffer * nInputChannels * sizeof(float));
298}
299
300if (nOutputChannels > 0) {
301if (rtStreamPtr->settings.outCallback) {
302
303if (rtStreamPtr->outputBuffer.size() != nFramesPerBuffer*nOutputChannels || rtStreamPtr->outputBuffer.getNumChannels() != nOutputChannels) {
304rtStreamPtr->outputBuffer.setNumChannels(nOutputChannels);
305rtStreamPtr->outputBuffer.resize(nFramesPerBuffer*nOutputChannels);
306}
307rtStreamPtr->outputBuffer.setTickCount(rtStreamPtr->tickCount);
308rtStreamPtr->settings.outCallback(rtStreamPtr->outputBuffer);
309}
310rtStreamPtr->outputBuffer.copyTo(fPtrOut, nFramesPerBuffer, nOutputChannels, 0);
311rtStreamPtr->outputBuffer.set(0);
312}
313
314// increment tick count
315rtStreamPtr->tickCount++;
316
317return 0;
318}
319