framework2

Форк
0
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

8
using std::vector;
9
using std::shared_ptr;
10

11
//------------------------------------------------------------------------------
12
RtAudio::Api toRtAudio(ofSoundDevice::Api api){
13
	switch (api) {
14
	case ofSoundDevice::Api::ALSA:
15
		return RtAudio::Api::LINUX_ALSA;
16
	case ofSoundDevice::Api::PULSE:
17
		return RtAudio::Api::LINUX_PULSE;
18
	case ofSoundDevice::Api::OSS:
19
		return RtAudio::Api::LINUX_OSS;
20
	case ofSoundDevice::Api::JACK:
21
		return RtAudio::Api::UNIX_JACK;
22
#ifndef TARGET_LINUX
23
	case ofSoundDevice::Api::OSX_CORE:
24
		return RtAudio::Api::MACOSX_CORE;
25
	case ofSoundDevice::Api::MS_WASAPI:
26
		return RtAudio::Api::WINDOWS_WASAPI;
27
	case ofSoundDevice::Api::MS_ASIO:
28
		return RtAudio::Api::WINDOWS_ASIO;
29
	case ofSoundDevice::Api::MS_DS:
30
		return RtAudio::Api::WINDOWS_DS;
31
#endif
32
	default:
33
		return RtAudio::Api::UNSPECIFIED;
34
	}
35
}
36

37
//------------------------------------------------------------------------------
38
ofSoundDevice::Api toOf(RtAudio::Api api){
39
	switch (api) {
40
	case RtAudio::Api::LINUX_ALSA:
41
		return ofSoundDevice::Api::ALSA;
42
	case RtAudio::Api::LINUX_PULSE:
43
		return ofSoundDevice::Api::PULSE;
44
	case RtAudio::Api::LINUX_OSS:
45
		return ofSoundDevice::Api::OSS;
46
	case RtAudio::Api::UNIX_JACK:
47
		return ofSoundDevice::Api::JACK;
48
#ifndef TARGET_LINUX
49
	case RtAudio::Api::MACOSX_CORE:
50
		return ofSoundDevice::Api::OSX_CORE;
51
	case RtAudio::Api::WINDOWS_WASAPI:
52
		return ofSoundDevice::Api::MS_WASAPI;
53
	case RtAudio::Api::WINDOWS_ASIO:
54
		return ofSoundDevice::Api::MS_ASIO;
55
	case RtAudio::Api::WINDOWS_DS:
56
		return ofSoundDevice::Api::MS_DS;
57
#endif
58
	default:
59
		return ofSoundDevice::Api::UNSPECIFIED;
60
	}
61
}
62

63
//------------------------------------------------------------------------------
64
ofRtAudioSoundStream::ofRtAudioSoundStream() {
65
	tickCount = 0;
66
}
67

68
//------------------------------------------------------------------------------
69
ofRtAudioSoundStream::~ofRtAudioSoundStream() {
70
	stop();
71
	close();
72
}
73

74
//------------------------------------------------------------------------------
75
std::vector<ofSoundDevice> ofRtAudioSoundStream::getDeviceList(ofSoundDevice::Api api) const{
76
	vector<ofSoundDevice> deviceList;
77
	try {
78
		auto rtAudioApi = toRtAudio(api);
79
		RtAudio audioTemp(toRtAudio(api));
80
		audioTemp.showWarnings(false);
81
		if(audioTemp.getCurrentApi()!=rtAudioApi && rtAudioApi!=RtAudio::Api::UNSPECIFIED){
82
			return deviceList;
83
		}
84
		auto deviceCount = audioTemp.getDeviceCount();
85
		RtAudio::DeviceInfo info;
86
		for (unsigned int i = 0; i < deviceCount; i++) {
87
			try {
88
				info = audioTemp.getDeviceInfo(i);
89
			}
90
			catch (std::exception &error) {
91
				ofLogError("ofRtAudioSoundStream") << "Error retrieving info for device " << i;
92
				ofLogError() << error.what();
93
				break;
94
			}
95

96
			ofSoundDevice dev;
97
			dev.deviceID = i;
98
			dev.name = info.name;
99
			dev.outputChannels = info.outputChannels;
100
			dev.inputChannels = info.inputChannels;
101
			dev.sampleRates = info.sampleRates;
102
			dev.isDefaultInput = info.isDefaultInput;
103
			dev.isDefaultOutput = info.isDefaultOutput;
104
			dev.api = api;
105
			deviceList.push_back(dev);
106
		}
107
	}catch (std::exception &error) {
108
		ofLogError() << error.what();
109
	}
110

111
	return deviceList;
112

113
}
114

115
//------------------------------------------------------------------------------
116
void ofRtAudioSoundStream::setInput(ofBaseSoundInput * soundInput) {
117
	settings.setInListener(soundInput);
118
}
119

120
//------------------------------------------------------------------------------
121
void ofRtAudioSoundStream::setOutput(ofBaseSoundOutput * soundOutput) {
122
	settings.setOutListener(soundOutput);
123
}
124

125
//------------------------------------------------------------------------------
126
bool ofRtAudioSoundStream::setup(const ofSoundStreamSettings & settings_)
127
{
128
	if (audio != nullptr) {
129
		close();
130
	}
131

132
	this->settings = settings_;
133

134
	tickCount = 0;
135
	this->settings.bufferSize = ofNextPow2(settings.bufferSize);	// must be pow2
136

137
	try {
138
		if (settings.getApi() != ofSoundDevice::Api::UNSPECIFIED) {
139
			audio = std::make_shared<RtAudio>(toRtAudio(settings.getApi()));
140
		}else{
141
			audio = std::make_shared<RtAudio>();
142
		}
143
	}
144
	catch (std::exception &error) {
145
		ofLogError() << error.what();
146
		return false;
147
	}
148

149
	RtAudio::StreamParameters outputParameters;
150
	RtAudio::StreamParameters inputParameters;
151
	if (settings.numInputChannels > 0) {
152
		if (!settings.getInDevice()) {
153
			ofSoundDevice device;
154
			device.deviceID = audio->getDefaultInputDevice();
155
			settings.setInDevice(device);
156
		}
157
		inputParameters.deviceId = settings.getInDevice()->deviceID;
158
		inputParameters.nChannels = settings.numInputChannels;
159
	}
160

161
	if (settings.numOutputChannels > 0) {
162
		if (!settings.getOutDevice()) {
163
			ofSoundDevice device;
164
			device.deviceID = audio->getDefaultOutputDevice();
165
			settings.setOutDevice(device);
166
		}
167
		outputParameters.deviceId = settings.getOutDevice()->deviceID;
168
		outputParameters.nChannels = settings.numOutputChannels;
169
	}
170

171
	RtAudio::StreamOptions options;
172
	options.flags = RTAUDIO_SCHEDULE_REALTIME;
173
	options.numberOfBuffers = settings.numBuffers;
174
	options.priority = 1;
175
	outputBuffer.setDeviceID(outputParameters.deviceId);
176
	inputBuffer.setDeviceID(inputParameters.deviceId);
177
	outputBuffer.setSampleRate(settings.sampleRate);
178
	inputBuffer.setSampleRate(settings.sampleRate);
179
	unsigned int bufferSize = settings.bufferSize;
180
	try {
181
		audio->openStream((settings.numOutputChannels > 0) ? &outputParameters : nullptr, (settings.numInputChannels > 0) ? &inputParameters : nullptr, RTAUDIO_FLOAT32,
182
			settings.sampleRate, &bufferSize, &rtAudioCallback, this, &options);
183
		audio->startStream();
184
	}
185
	catch (std::exception &error) {
186
		ofLogError() << error.what();
187
		return false;
188
	}
189
	return true;
190
}
191

192
//------------------------------------------------------------------------------
193
void ofRtAudioSoundStream::start() {
194
	if (audio == nullptr) return;
195

196
	try {
197
		audio->startStream();
198
	}
199
	catch (std::exception &error) {
200
		ofLogError() << error.what();
201
	}
202
}
203

204
//------------------------------------------------------------------------------
205
void ofRtAudioSoundStream::stop() {
206
	if (audio == nullptr) return;
207

208
	try {
209
		if (audio->isStreamRunning()) {
210
			audio->stopStream();
211
		}
212
	}
213
	catch (std::exception &error) {
214
		ofLogError() << error.what();
215
	}
216
}
217

218
//------------------------------------------------------------------------------
219
void ofRtAudioSoundStream::close() {
220
	if (audio == nullptr) return;
221

222
	try {
223
		if (audio->isStreamOpen()) {
224
			audio->closeStream();
225
		}
226
	}
227
	catch (std::exception &error) {
228
		ofLogError() << error.what();
229
	}
230
	settings.outCallback = nullptr;
231
	settings.inCallback = nullptr;
232
	audio.reset();	// delete
233
}
234

235
//------------------------------------------------------------------------------
236
uint64_t ofRtAudioSoundStream::getTickCount() const {
237
	return tickCount;
238
}
239

240
//------------------------------------------------------------------------------
241
int ofRtAudioSoundStream::getNumInputChannels() const {
242
	return settings.numInputChannels;
243
}
244

245
//------------------------------------------------------------------------------
246
int ofRtAudioSoundStream::getNumOutputChannels() const {
247
	return  settings.numOutputChannels;
248
}
249

250
//------------------------------------------------------------------------------
251
int ofRtAudioSoundStream::getSampleRate() const {
252
	return settings.sampleRate;
253
}
254

255
//------------------------------------------------------------------------------
256
int ofRtAudioSoundStream::getBufferSize() const {
257
	return settings.bufferSize;
258
}
259

260
ofSoundDevice ofRtAudioSoundStream::getInDevice() const{
261
	return *settings.getInDevice();
262
}
263

264
ofSoundDevice ofRtAudioSoundStream::getOutDevice() const{
265
	return *settings.getOutDevice();
266
}
267

268
//------------------------------------------------------------------------------
269
int ofRtAudioSoundStream::rtAudioCallback(void *outputBuffer, void *inputBuffer, unsigned int nFramesPerBuffer, double streamTime, RtAudioStreamStatus status, void *data) {
270
	ofRtAudioSoundStream * rtStreamPtr = (ofRtAudioSoundStream *)data;
271

272
	if (status) {
273
		ofLogWarning("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
280
	float * fPtrOut = (float *)outputBuffer;
281
	float * 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

287
	size_t nInputChannels  = rtStreamPtr->getNumInputChannels();
288
	size_t nOutputChannels = rtStreamPtr->getNumOutputChannels();
289

290
	if (nInputChannels > 0) {
291
		if (rtStreamPtr->settings.inCallback) {
292
			rtStreamPtr->inputBuffer.copyFrom(fPtrIn, nFramesPerBuffer, nInputChannels, rtStreamPtr->getSampleRate());
293
			rtStreamPtr->inputBuffer.setTickCount(rtStreamPtr->tickCount);
294
			rtStreamPtr->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?
297
		memset(fPtrIn, 0, nFramesPerBuffer * nInputChannels * sizeof(float));
298
	}
299

300
	if (nOutputChannels > 0) {
301
		if (rtStreamPtr->settings.outCallback) {
302

303
			if (rtStreamPtr->outputBuffer.size() != nFramesPerBuffer*nOutputChannels || rtStreamPtr->outputBuffer.getNumChannels() != nOutputChannels) {
304
				rtStreamPtr->outputBuffer.setNumChannels(nOutputChannels);
305
				rtStreamPtr->outputBuffer.resize(nFramesPerBuffer*nOutputChannels);
306
			}
307
			rtStreamPtr->outputBuffer.setTickCount(rtStreamPtr->tickCount);
308
			rtStreamPtr->settings.outCallback(rtStreamPtr->outputBuffer);
309
		}
310
		rtStreamPtr->outputBuffer.copyTo(fPtrOut, nFramesPerBuffer, nOutputChannels, 0);
311
		rtStreamPtr->outputBuffer.set(0);
312
	}
313

314
	// increment tick count
315
	rtStreamPtr->tickCount++;
316

317
	return 0;
318
}
319

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.