1
by Mike Furr
Import upstream version 3.81 |
1 |
/*
|
2 |
terminatorX - realtime audio scratching software
|
|
1.1.2
by Alessio Treglia
Import upstream version 3.84 |
3 |
Copyright (C) 1999-2011 Alexander König
|
1
by Mike Furr
Import upstream version 3.81 |
4 |
|
5 |
This program is free software; you can redistribute it and/or modify
|
|
6 |
it under the terms of the GNU General Public License as published by
|
|
7 |
the Free Software Foundation; either version 2 of the License, or
|
|
8 |
(at your option) any later version.
|
|
9 |
|
|
10 |
This program is distributed in the hope that it will be useful,
|
|
11 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
GNU General Public License for more details.
|
|
14 |
|
|
15 |
You should have received a copy of the GNU General Public License
|
|
16 |
along with this program; if not, write to the Free Software
|
|
17 |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
18 |
|
|
19 |
File: tX_aduiodevice.cc
|
|
20 |
|
|
21 |
Description: Implements Audiodevice handling...
|
|
22 |
*/
|
|
23 |
||
24 |
#define ALSA_PCM_NEW_HW_PARAMS_API
|
|
25 |
||
26 |
#include "tX_audiodevice.h" |
|
27 |
#include "tX_vtt.h" |
|
28 |
||
29 |
#include <sys/types.h> |
|
30 |
#include <sys/stat.h> |
|
31 |
#include <sys/ioctl.h> |
|
32 |
#include <fcntl.h> |
|
33 |
#include <sys/soundcard.h> |
|
34 |
#include <config.h> |
|
1.1.1
by Daniel Holbach
Import upstream version 3.82 |
35 |
#include <string.h> |
1
by Mike Furr
Import upstream version 3.81 |
36 |
|
37 |
#include "tX_endian.h" |
|
38 |
||
39 |
#ifndef __USE_XOPEN
|
|
40 |
# define __USE_XOPEN // we need this for swab() |
|
41 |
# include <unistd.h>
|
|
42 |
# undef __USE_XOPEN
|
|
43 |
#else
|
|
44 |
# include <unistd.h>
|
|
45 |
#endif
|
|
46 |
||
47 |
#include <string.h> |
|
48 |
#include <errno.h> |
|
49 |
#include <stdlib.h> |
|
50 |
#include "tX_engine.h" |
|
51 |
||
52 |
tX_audiodevice :: tX_audiodevice() : samples_per_buffer(0), |
|
53 |
current_buffer(0), buffer_pos(0), is_open(false) |
|
54 |
{
|
|
55 |
sample_buffer[0]=NULL; |
|
56 |
sample_buffer[1]=NULL; |
|
57 |
engine=tX_engine::get_instance(); |
|
58 |
}
|
|
59 |
||
60 |
void tX_audiodevice :: start() { |
|
61 |
sample_buffer[0]=new int16_t[samples_per_buffer*2]; |
|
62 |
sample_buffer[1]=new int16_t[samples_per_buffer*2]; |
|
63 |
int current=0; |
|
64 |
vtt_buffer_size=vtt_class::get_mix_buffer_size()<<1; |
|
65 |
||
66 |
buffer_pos=0; |
|
67 |
||
68 |
while (!engine->is_stopped()) { |
|
69 |
current=current ? 0 : 1; |
|
70 |
||
71 |
int16_t *current_buffer=sample_buffer[current]; |
|
72 |
int16_t *next_buffer=sample_buffer[current ? 0 : 1]; |
|
73 |
||
74 |
fill_buffer(current_buffer, next_buffer); |
|
75 |
play(current_buffer); |
|
76 |
}
|
|
77 |
||
78 |
delete [] sample_buffer[0]; |
|
79 |
delete [] sample_buffer[1]; |
|
80 |
}
|
|
81 |
||
82 |
void tX_audiodevice :: fill_buffer(int16_t *target_buffer, int16_t *next_target_buffer) { |
|
83 |
int prefill=0; |
|
84 |
||
85 |
while (buffer_pos <= samples_per_buffer) { |
|
86 |
int16_t *data=engine->render_cycle(); |
|
87 |
||
88 |
int rest=(buffer_pos+vtt_buffer_size)-samples_per_buffer; |
|
89 |
||
90 |
if (rest<=0) { |
|
91 |
memcpy(&target_buffer[buffer_pos], data, vtt_buffer_size << 1); |
|
92 |
} else { |
|
93 |
memcpy(&target_buffer[buffer_pos], data, (vtt_buffer_size-rest) << 1); |
|
94 |
memcpy(next_target_buffer, &data[vtt_buffer_size-rest], rest << 1); |
|
95 |
prefill=rest; |
|
96 |
}
|
|
97 |
||
98 |
buffer_pos+=vtt_buffer_size; |
|
99 |
}
|
|
100 |
||
101 |
buffer_pos=prefill; |
|
102 |
}
|
|
103 |
||
104 |
/* Driver Specific Code follows.. */
|
|
105 |
||
106 |
#ifdef USE_OSS
|
|
107 |
||
108 |
int tX_audiodevice_oss :: open() |
|
109 |
{
|
|
110 |
int i=0; |
|
111 |
int p; |
|
112 |
int buff_cfg; |
|
113 |
||
114 |
if (fd) return (1); |
|
115 |
fd=::open(globals.oss_device, O_WRONLY, 0); |
|
116 |
||
117 |
if (fd==-1) { |
|
118 |
tX_error("tX_audiodevice_oss::open() can't open device: %s", strerror(errno)); |
|
119 |
return -1; |
|
120 |
}
|
|
121 |
||
122 |
is_open=true; |
|
123 |
||
124 |
/* setting buffer size */
|
|
125 |
buff_cfg=(globals.oss_buff_no<<16) | globals.oss_buff_size; |
|
126 |
p=buff_cfg; |
|
127 |
||
128 |
tX_debug("tX_audiodevice_oss::open() - buff_no: %i, buff_size: %i, buff_cfg: %08x", globals.oss_buff_no, globals.oss_buff_size, buff_cfg); |
|
129 |
||
130 |
i = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &p); |
|
131 |
ioctl(fd, SNDCTL_DSP_RESET, 0); |
|
132 |
||
133 |
/* 16 Bits */
|
|
134 |
||
135 |
p = 16; |
|
136 |
i += ioctl(fd, SOUND_PCM_WRITE_BITS, &p); |
|
137 |
||
138 |
/* STEREO :) */
|
|
139 |
||
140 |
p = 2; |
|
141 |
i += ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &p); |
|
142 |
||
143 |
/* 44.1 khz */
|
|
144 |
||
145 |
p = globals.oss_samplerate; |
|
146 |
i += ioctl(fd, SOUND_PCM_WRITE_RATE, &p); |
|
147 |
||
148 |
sample_rate=globals.oss_samplerate; |
|
149 |
||
150 |
/* Figure actual blocksize.. */
|
|
151 |
||
152 |
i += ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize); |
|
153 |
||
154 |
samples_per_buffer=blocksize/sizeof(int16_t); |
|
155 |
||
156 |
tX_debug("tX_adudiodevice_oss::open() - blocksize: %i, samples_per_buffer: %i", blocksize, samples_per_buffer); |
|
157 |
||
158 |
ioctl(fd, SNDCTL_DSP_SYNC, 0); |
|
159 |
||
160 |
return i; |
|
161 |
}
|
|
162 |
||
163 |
int tX_audiodevice_oss :: close() |
|
164 |
{
|
|
165 |
if (!fd) { |
|
166 |
return(1); |
|
167 |
}
|
|
168 |
is_open=false; |
|
169 |
::close(fd); |
|
170 |
fd=0; |
|
171 |
blocksize=0; |
|
172 |
||
173 |
return 0; |
|
174 |
}
|
|
175 |
||
176 |
tX_audiodevice_oss :: tX_audiodevice_oss() : tX_audiodevice(), |
|
177 |
fd(0), blocksize(0) {} |
|
178 |
||
179 |
void tX_audiodevice_oss :: play(int16_t *buffer) |
|
180 |
{
|
|
181 |
#ifdef BIG_ENDIAN_MACHINE
|
|
182 |
swapbuffer (buffer, samples_per_buffer); |
|
183 |
#endif
|
|
184 |
int res=write(fd, buffer, blocksize); |
|
185 |
if (res==-1) { |
|
186 |
tX_error("failed to write to audiodevice: %s", strerror(errno)); |
|
187 |
exit(-1); |
|
188 |
}
|
|
189 |
}
|
|
190 |
||
191 |
#endif //USE_OSS |
|
192 |
||
193 |
#ifdef USE_ALSA
|
|
194 |
||
1.1.1
by Daniel Holbach
Import upstream version 3.82 |
195 |
#define tX_abs(x) (x<0 ? -x : x)
|
196 |
||
1
by Mike Furr
Import upstream version 3.81 |
197 |
int tX_audiodevice_alsa :: open() |
198 |
{
|
|
199 |
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; |
|
200 |
snd_pcm_hw_params_t *hw_params; |
|
201 |
char pcm_name[64]; |
|
1.1.1
by Daniel Holbach
Import upstream version 3.82 |
202 |
char *pos; |
203 |
||
204 |
strncpy(pcm_name, globals.alsa_device_id, sizeof(pcm_name)); |
|
205 |
if ((pos = strchr(pcm_name, '#')) != NULL) *pos = 0; |
|
1
by Mike Furr
Import upstream version 3.81 |
206 |
|
207 |
if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) { |
|
208 |
tX_error("ALSA: Failed to access PCM device \"%s\"", pcm_name); |
|
209 |
return -1; |
|
210 |
}
|
|
211 |
||
212 |
is_open=true; |
|
213 |
||
214 |
snd_pcm_hw_params_alloca(&hw_params); |
|
215 |
||
216 |
if (snd_pcm_hw_params_any(pcm_handle, hw_params) < 0) { |
|
217 |
tX_error("ALSA: Failed to configure PCM device \"%s\"", pcm_name); |
|
218 |
snd_pcm_hw_params_free (hw_params); |
|
219 |
return -1; |
|
220 |
}
|
|
221 |
||
222 |
/* Setting INTERLEAVED stereo... */
|
|
223 |
#ifdef USE_ALSA_MEMCPY
|
|
224 |
if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { |
|
225 |
#else
|
|
226 |
if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { |
|
227 |
#endif
|
|
228 |
tX_error("ALSA: Failed to set interleaved access for PCM device \"%s\"", pcm_name); |
|
229 |
snd_pcm_hw_params_free (hw_params); |
|
230 |
return -1; |
|
231 |
}
|
|
232 |
||
1.1.1
by Daniel Holbach
Import upstream version 3.82 |
233 |
/* Make it 16 Bit native endian */
|
234 |
if (snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16) < 0) { |
|
1
by Mike Furr
Import upstream version 3.81 |
235 |
tX_error("ALSA: Error setting 16 Bit sample width for PCM device \"%s\"", pcm_name); |
236 |
snd_pcm_hw_params_free (hw_params); |
|
237 |
return -1; |
|
238 |
}
|
|
239 |
||
240 |
/* Setting sampling rate */
|
|
241 |
unsigned int hw_rate=(unsigned int)globals.alsa_samplerate; |
|
242 |
int dir; |
|
243 |
||
244 |
if (snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &hw_rate, &dir) < 0) { |
|
245 |
tX_error("ALSA: Failed setting sample rate: %i", globals.alsa_samplerate); |
|
246 |
snd_pcm_hw_params_free (hw_params); |
|
247 |
return -1; |
|
248 |
}
|
|
249 |
||
250 |
if (dir != 0) { |
|
1.1.1
by Daniel Holbach
Import upstream version 3.82 |
251 |
if (tX_abs(globals.alsa_samplerate - hw_rate) > 2) { |
252 |
tX_warning("ALSA: The PCM device \"%s\" doesn\'t support %i Hz playback - using %i instead", pcm_name, globals.alsa_samplerate, hw_rate); |
|
253 |
}
|
|
1
by Mike Furr
Import upstream version 3.81 |
254 |
}
|
255 |
||
256 |
sample_rate=hw_rate; |
|
257 |
||
258 |
/* Using stereo output */
|
|
259 |
if (snd_pcm_hw_params_set_channels(pcm_handle, hw_params, 2) < 0) { |
|
260 |
tX_error("ALSA: PCM device \"%s\" does not support stereo operation", pcm_name); |
|
261 |
snd_pcm_hw_params_free (hw_params); |
|
262 |
return -1; |
|
263 |
}
|
|
264 |
||
265 |
unsigned int buffer_time=globals.alsa_buffer_time; |
|
266 |
unsigned int period_time=globals.alsa_period_time; |
|
267 |
||
268 |
if (snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hw_params, &buffer_time, &dir) < 0) { |
|
269 |
tX_error("ALSA: failed to set the buffer time opf %i usecs", globals.alsa_buffer_time); |
|
270 |
return -1; |
|
271 |
}
|
|
272 |
||
273 |
long unsigned int buffer_size; |
|
274 |
||
275 |
if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) < 0) { |
|
276 |
tX_error("ALSA: failed to retreive buffer size"); |
|
277 |
return -1; |
|
278 |
}
|
|
279 |
||
280 |
tX_debug("ALSA: buffer size is %lu", buffer_size); |
|
281 |
||
282 |
if (snd_pcm_hw_params_set_period_time_near(pcm_handle, hw_params, &period_time, &dir) < 0) { |
|
283 |
tX_error("ALSA: failed to set period time %i", globals.alsa_period_time); |
|
284 |
return -1; |
|
285 |
}
|
|
286 |
||
287 |
if (snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir)<0) { |
|
288 |
tX_error("ALSA: failed to retreive period size"); |
|
289 |
return -1; |
|
290 |
}
|
|
291 |
||
292 |
samples_per_buffer=period_size; |
|
293 |
||
294 |
/* Apply all that setup work.. */
|
|
295 |
if (snd_pcm_hw_params(pcm_handle, hw_params) < 0) { |
|
296 |
tX_error("ALSA: Failed to apply settings to PCM device \"%s\"", pcm_name); |
|
297 |
snd_pcm_hw_params_free (hw_params); |
|
298 |
return -1; |
|
299 |
}
|
|
300 |
||
301 |
if (globals.alsa_free_hwstats) { |
|
302 |
snd_pcm_hw_params_free (hw_params); |
|
303 |
}
|
|
304 |
||
305 |
return 0; //snd_pcm_prepare(pcm_handle); |
|
306 |
}
|
|
307 |
||
308 |
int tX_audiodevice_alsa :: close() |
|
309 |
{
|
|
310 |
if (is_open) { |
|
311 |
snd_pcm_close(pcm_handle); |
|
312 |
}
|
|
313 |
is_open=false; |
|
314 |
||
315 |
return 0; |
|
316 |
}
|
|
317 |
||
318 |
tX_audiodevice_alsa :: tX_audiodevice_alsa() : tX_audiodevice(), |
|
319 |
pcm_handle(NULL) {} |
|
320 |
||
321 |
void tX_audiodevice_alsa :: play(int16_t *buffer) |
|
322 |
{
|
|
323 |
int underrun_ctr=0; |
|
324 |
snd_pcm_sframes_t pcmreturn; |
|
325 |
||
326 |
#ifdef USE_ALSA_MEMCPY
|
|
327 |
pcmreturn = snd_pcm_writei(pcm_handle, buffer, samples_per_buffer >> 1); |
|
328 |
#else
|
|
329 |
pcmreturn = snd_pcm_mmap_writei(pcm_handle, buffer, samples_per_buffer >> 1); |
|
330 |
#endif
|
|
331 |
||
332 |
while (pcmreturn==-EPIPE) { |
|
333 |
snd_pcm_prepare(pcm_handle); |
|
334 |
||
335 |
#ifdef USE_ALSA_MEMCPY
|
|
336 |
pcmreturn = snd_pcm_writei(pcm_handle, buffer, samples_per_buffer >> 1); |
|
337 |
#else
|
|
338 |
pcmreturn = snd_pcm_mmap_writei(pcm_handle, buffer, samples_per_buffer >> 1); |
|
339 |
#endif
|
|
340 |
underrun_ctr++; |
|
341 |
if (underrun_ctr>100) { |
|
342 |
tX_error("tX_audiodevice_alsa::play() more than 10 EPIPE cycles. Giving up."); |
|
343 |
break; |
|
344 |
}
|
|
345 |
//tX_warning("ALSA: ** buffer underrun **");
|
|
346 |
}
|
|
347 |
||
348 |
if (pcmreturn<0) { |
|
349 |
printf("snd_pcm_writei says: %s.\n", strerror(-1*pcmreturn)); |
|
350 |
}
|
|
351 |
}
|
|
352 |
||
353 |
#endif //USE_ALSA |
|
354 |
||
355 |
#ifdef USE_JACK
|
|
356 |
||
357 |
tX_jack_client* tX_jack_client::instance=NULL; |
|
358 |
||
359 |
void tX_jack_client::init() |
|
360 |
{
|
|
361 |
tX_jack_client *test=new tX_jack_client(); |
|
362 |
||
363 |
if (!instance) { |
|
364 |
delete test; |
|
365 |
}
|
|
366 |
}
|
|
367 |
||
368 |
tX_jack_client::tX_jack_client():device(NULL),jack_shutdown(false) |
|
369 |
{
|
|
370 |
jack_set_error_function(tX_jack_client::error); |
|
371 |
||
1.1.2
by Alessio Treglia
Import upstream version 3.84 |
372 |
if ((client=jack_client_open("terminatorX", (jack_options_t) NULL, NULL))==0) { |
1
by Mike Furr
Import upstream version 3.81 |
373 |
tX_error("tX_jack_client() -> failed to connect to jackd."); |
374 |
instance=NULL; |
|
375 |
} else { |
|
376 |
instance=this; |
|
377 |
const char **ports; |
|
378 |
||
379 |
/* Setting up jack callbacks... */
|
|
380 |
jack_set_process_callback(client, tX_jack_client::process, NULL); |
|
381 |
jack_set_sample_rate_callback(client, tX_jack_client::srate, NULL); |
|
382 |
jack_on_shutdown (client, tX_jack_client::shutdown, NULL); |
|
383 |
||
384 |
/* Creating the port... */
|
|
385 |
left_port = jack_port_register (client, "output_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); |
|
386 |
right_port = jack_port_register (client, "output_2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); |
|
387 |
||
388 |
/* Action... */
|
|
389 |
jack_activate(client); |
|
390 |
||
391 |
/* Connect some ports... */
|
|
392 |
if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) { |
|
393 |
tX_error("tX_jack_client() no ports to connect to found. Connect manually."); |
|
394 |
} else if (ports[0] && ports[1]) { |
|
395 |
if (jack_connect (client, jack_port_name(left_port), ports[0])) { |
|
396 |
tX_error("tX_jack_client() failed to connect left port."); |
|
397 |
}
|
|
398 |
if (jack_connect (client, jack_port_name(right_port), ports[1])) { |
|
399 |
tX_error("tX_jack_client() failed to connect right port."); |
|
400 |
}
|
|
401 |
free (ports); |
|
402 |
}
|
|
403 |
}
|
|
404 |
}
|
|
405 |
||
406 |
tX_jack_client::~tX_jack_client() |
|
407 |
{
|
|
408 |
instance=NULL; |
|
409 |
if (client) jack_client_close(client); |
|
410 |
}
|
|
411 |
||
412 |
void tX_jack_client::error(const char *desc) |
|
413 |
{
|
|
1.1.1
by Daniel Holbach
Import upstream version 3.82 |
414 |
tX_error("jack error: %s.", desc); |
1
by Mike Furr
Import upstream version 3.81 |
415 |
}
|
416 |
||
417 |
int tX_jack_client::srate(jack_nframes_t nframes, void *arg) |
|
418 |
{
|
|
419 |
tX_error("tX_jack_client::srate() jack changed samplerate - ignored."); |
|
420 |
return 0; |
|
421 |
}
|
|
422 |
||
423 |
void tX_jack_client::shutdown(void *arg) |
|
424 |
{
|
|
425 |
tX_error("tX_jack_client::shutdown() jack daemon has shut down. Bad!"); |
|
426 |
if (instance) instance->jack_shutdown=true; |
|
427 |
}
|
|
428 |
||
429 |
int tX_jack_client::process(jack_nframes_t nframes, void *arg) |
|
430 |
{
|
|
431 |
if (instance) { |
|
432 |
return instance->play(nframes); |
|
433 |
}
|
|
434 |
||
435 |
/* Hmm, what to do in such a case? */
|
|
436 |
return 0; |
|
437 |
}
|
|
438 |
||
439 |
int tX_jack_client::play(jack_nframes_t nframes) |
|
440 |
{
|
|
441 |
jack_default_audio_sample_t *left = (jack_default_audio_sample_t *) jack_port_get_buffer (left_port, nframes); |
|
442 |
jack_default_audio_sample_t *right = (jack_default_audio_sample_t *) jack_port_get_buffer (right_port, nframes); |
|
443 |
||
444 |
if (device) { |
|
445 |
device->fill_frames(left, right, nframes); |
|
446 |
} else { |
|
447 |
memset(left, 0, sizeof (jack_default_audio_sample_t) * nframes); |
|
448 |
memset(right, 0, sizeof (jack_default_audio_sample_t) * nframes); |
|
449 |
}
|
|
450 |
||
451 |
return 0; |
|
452 |
}
|
|
453 |
||
454 |
int tX_jack_client::get_sample_rate() |
|
455 |
{
|
|
456 |
return jack_get_sample_rate(client); |
|
457 |
}
|
|
458 |
||
459 |
/* tX_audiodevice_jack */
|
|
460 |
||
461 |
tX_audiodevice_jack::tX_audiodevice_jack():tX_audiodevice() |
|
462 |
{
|
|
463 |
client=NULL; |
|
464 |
}
|
|
465 |
||
466 |
int tX_audiodevice_jack::open() |
|
467 |
{
|
|
468 |
tX_jack_client *jack_client=tX_jack_client::get_instance(); |
|
469 |
||
470 |
if (jack_client) { |
|
471 |
sample_rate=jack_client->get_sample_rate(); |
|
472 |
client=jack_client; |
|
473 |
is_open=true; |
|
474 |
||
475 |
return 0; |
|
476 |
}
|
|
477 |
||
478 |
return 1; |
|
479 |
}
|
|
480 |
||
481 |
int tX_audiodevice_jack::close() |
|
482 |
{
|
|
483 |
if (client) { |
|
484 |
client->set_device(NULL); |
|
485 |
}
|
|
486 |
||
487 |
is_open=false; |
|
488 |
||
489 |
return 0; |
|
490 |
}
|
|
491 |
||
492 |
void tX_audiodevice_jack::play(int16_t *buffer) |
|
493 |
{
|
|
494 |
tX_error("tX_audiodevice_jack::play()"); |
|
495 |
}
|
|
496 |
||
497 |
void tX_audiodevice_jack::start() |
|
498 |
{
|
|
499 |
overrun_buffer=new f_prec[vtt_class::samples_in_mix_buffer]; |
|
500 |
||
501 |
client->set_device(this); |
|
502 |
while ((!engine->is_stopped()) && !(client->get_jack_shutdown())) { |
|
503 |
usleep(100); |
|
504 |
}
|
|
505 |
client->set_device(NULL); |
|
506 |
||
507 |
delete [] overrun_buffer; |
|
508 |
}
|
|
509 |
||
510 |
void tX_audiodevice_jack::fill_frames(jack_default_audio_sample_t *left, jack_default_audio_sample_t *right, jack_nframes_t nframes) |
|
511 |
{
|
|
512 |
unsigned int outbuffer_pos=0; |
|
513 |
unsigned int sample; |
|
514 |
||
515 |
if (samples_in_overrun_buffer) { |
|
516 |
for (sample=0; ((sample<samples_in_overrun_buffer) && (outbuffer_pos<nframes));) { |
|
517 |
left[outbuffer_pos]=overrun_buffer[sample++]/32767.0; |
|
518 |
right[outbuffer_pos++]=overrun_buffer[sample++]/32767.0; |
|
519 |
}
|
|
520 |
}
|
|
521 |
||
522 |
while (outbuffer_pos<nframes) { |
|
523 |
engine->render_cycle(); |
|
524 |
||
525 |
for (sample=0; ((sample<(unsigned int) vtt_class::samples_in_mix_buffer) && (outbuffer_pos<nframes));) { |
|
526 |
left[outbuffer_pos]=vtt_class::mix_buffer[sample++]/32767.0; |
|
527 |
right[outbuffer_pos++]=vtt_class::mix_buffer[sample++]/32767.0; |
|
528 |
}
|
|
529 |
||
530 |
if (sample<(unsigned int) vtt_class::samples_in_mix_buffer) { |
|
531 |
samples_in_overrun_buffer=vtt_class::samples_in_mix_buffer-sample; |
|
532 |
/* There's more data in the mixbuffer... */
|
|
533 |
memcpy(overrun_buffer, &vtt_class::mix_buffer[sample], sizeof(f_prec) * samples_in_overrun_buffer); |
|
534 |
} else { |
|
535 |
samples_in_overrun_buffer=0; |
|
536 |
}
|
|
537 |
}
|
|
538 |
}
|
|
539 |
||
540 |
#endif // USE_JACK |