]> lisas.de Git - terminatorX.git/blob - src/tX_audiodevice.cc
Bump to v4.2.0
[terminatorX.git] / src / tX_audiodevice.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2022  Alexander K├Ânig
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, see <http://www.gnu.org/licenses/>.
17
18     File: tX_aduiodevice.cc
19
20     Description: Implements Audiodevice handling...
21 */
22
23 #define ALSA_PCM_NEW_HW_PARAMS_API
24
25 #include "tX_audiodevice.h"
26 #include "tX_vtt.h"
27
28 #include <config.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <sys/soundcard.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #include "tX_endian.h"
37
38 #ifndef __USE_XOPEN
39 #define __USE_XOPEN // we need this for swab()
40 #include <unistd.h>
41 #undef __USE_XOPEN
42 #else
43 #include <unistd.h>
44 #endif
45
46 #include "tX_engine.h"
47 #include <errno.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 tX_audiodevice ::tX_audiodevice()
52     : samples_per_buffer(0)
53     , current_buffer(0)
54     , buffer_pos(0)
55     , is_open(false) {
56     sample_buffer[0] = NULL;
57     sample_buffer[1] = NULL;
58     engine = tX_engine::get_instance();
59 }
60
61 void tX_audiodevice ::start() {
62     sample_buffer[0] = new int16_t[samples_per_buffer * 2];
63     sample_buffer[1] = new int16_t[samples_per_buffer * 2];
64     int current = 0;
65     vtt_buffer_size = vtt_class::get_mix_buffer_size() << 1;
66
67     buffer_pos = 0;
68
69     while (!engine->is_stopped()) {
70         current = current ? 0 : 1;
71
72         int16_t* current_buffer = sample_buffer[current];
73         int16_t* next_buffer = sample_buffer[current ? 0 : 1];
74
75         fill_buffer(current_buffer, next_buffer);
76         play(current_buffer);
77     }
78
79     delete[] sample_buffer[0];
80     delete[] sample_buffer[1];
81 }
82
83 void tX_audiodevice ::fill_buffer(int16_t* target_buffer, int16_t* next_target_buffer) {
84     int prefill = 0;
85
86     while (buffer_pos <= samples_per_buffer) {
87         int16_t* data = engine->render_cycle();
88
89         int rest = (buffer_pos + vtt_buffer_size) - samples_per_buffer;
90
91         if (rest <= 0) {
92             memcpy(&target_buffer[buffer_pos], data, vtt_buffer_size << 1);
93         } else {
94             memcpy(&target_buffer[buffer_pos], data, (vtt_buffer_size - rest) << 1);
95             memcpy(next_target_buffer, &data[vtt_buffer_size - rest], rest << 1);
96             prefill = rest;
97         }
98
99         buffer_pos += vtt_buffer_size;
100     }
101
102     buffer_pos = prefill;
103 }
104
105 /* Driver Specific Code follows.. */
106
107 #ifdef USE_OSS
108
109 int tX_audiodevice_oss ::open() {
110     int i = 0;
111     int p;
112     int buff_cfg;
113
114     if (fd)
115         return 1;
116     fd = ::open(globals.oss_device, O_WRONLY, 0);
117
118     if (fd == -1) {
119         tX_error("tX_audiodevice_oss::open() can't open device: %s", strerror(errno));
120         return -1;
121     }
122
123     is_open = true;
124
125     /* setting buffer size */
126     buff_cfg = (globals.oss_buff_no << 16) | globals.oss_buff_size;
127     p = buff_cfg;
128
129     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);
130
131     i = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &p);
132     ioctl(fd, SNDCTL_DSP_RESET, 0);
133
134     /* 16 Bits */
135
136     p = 16;
137     i += ioctl(fd, SOUND_PCM_WRITE_BITS, &p);
138
139     /* STEREO :) */
140
141     p = 2;
142     i += ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &p);
143
144     /* 44.1 khz */
145
146     p = globals.oss_samplerate;
147     i += ioctl(fd, SOUND_PCM_WRITE_RATE, &p);
148
149     sample_rate = globals.oss_samplerate;
150
151     /* Figure actual blocksize.. */
152
153     i += ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize);
154
155     samples_per_buffer = blocksize / sizeof(int16_t);
156
157     tX_debug("tX_adudiodevice_oss::open() - blocksize: %i, samples_per_buffer: %i", blocksize, samples_per_buffer);
158
159     ioctl(fd, SNDCTL_DSP_SYNC, 0);
160
161     return i;
162 }
163
164 int tX_audiodevice_oss ::close() {
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()
177     : tX_audiodevice()
178     , fd(0)
179     , blocksize(0) {}
180
181 void tX_audiodevice_oss ::play(int16_t* buffer) {
182 #ifdef BIG_ENDIAN_MACHINE
183     swapbuffer(buffer, samples_per_buffer);
184 #endif
185     int res = write(fd, buffer, blocksize);
186     if (res == -1) {
187         tX_error("failed to write to audiodevice: %s", strerror(errno));
188         exit(-1);
189     }
190 }
191
192 #endif // USE_OSS
193
194 #ifdef USE_ALSA
195
196 #define tX_abs(x) (x < 0 ? -x : x)
197
198 int tX_audiodevice_alsa ::open() {
199     snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
200     snd_pcm_hw_params_t* hw_params;
201     char pcm_name[64];
202     char* pos;
203
204     strncpy(pcm_name, globals.alsa_device_id, sizeof(pcm_name));
205     if ((pos = strchr(pcm_name, '#')) != NULL)
206         *pos = 0;
207
208     if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
209         tX_error("ALSA: Failed to access PCM device \"%s\"", pcm_name);
210         return -1;
211     }
212
213     is_open = true;
214
215     snd_pcm_hw_params_alloca(&hw_params);
216
217     if (snd_pcm_hw_params_any(pcm_handle, hw_params) < 0) {
218         tX_error("ALSA: Failed to configure PCM device \"%s\"", pcm_name);
219         snd_pcm_hw_params_free(hw_params);
220         return -1;
221     }
222
223     /* Setting INTERLEAVED stereo... */
224 #ifdef USE_ALSA_MEMCPY
225     if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
226 #else
227     if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
228 #endif
229         tX_error("ALSA: Failed to set interleaved access for PCM device \"%s\"", pcm_name);
230         snd_pcm_hw_params_free(hw_params);
231         return -1;
232     }
233
234     /* Make it 16 Bit native endian */
235     if (snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16) < 0) {
236         tX_error("ALSA: Error setting 16 Bit sample width for PCM device \"%s\"", pcm_name);
237         snd_pcm_hw_params_free(hw_params);
238         return -1;
239     }
240
241     /* Setting sampling rate */
242     unsigned int hw_rate = (unsigned int)globals.alsa_samplerate;
243     int dir;
244
245     if (snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &hw_rate, &dir) < 0) {
246         tX_error("ALSA: Failed setting sample rate: %i", globals.alsa_samplerate);
247         snd_pcm_hw_params_free(hw_params);
248         return -1;
249     }
250
251     if (dir != 0) {
252         if (tX_abs(globals.alsa_samplerate - hw_rate) > 2) {
253             tX_warning("ALSA: The PCM device \"%s\" doesn\'t support %i Hz playback - using %i instead", pcm_name, globals.alsa_samplerate, hw_rate);
254         }
255     }
256
257     sample_rate = hw_rate;
258
259     /* Using stereo output */
260     if (snd_pcm_hw_params_set_channels(pcm_handle, hw_params, 2) < 0) {
261         tX_error("ALSA: PCM device \"%s\" does not support stereo operation", pcm_name);
262         snd_pcm_hw_params_free(hw_params);
263         return -1;
264     }
265
266     unsigned int buffer_time = globals.alsa_buffer_time;
267     unsigned int period_time = globals.alsa_period_time;
268
269     if (snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hw_params, &buffer_time, &dir) < 0) {
270         tX_error("ALSA: failed to set the buffer time opf %i usecs", globals.alsa_buffer_time);
271         return -1;
272     }
273
274     long unsigned int buffer_size;
275
276     if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) < 0) {
277         tX_error("ALSA: failed to retrieve buffer size");
278         return -1;
279     }
280
281     tX_debug("ALSA: buffer size is %lu", buffer_size);
282
283     if (snd_pcm_hw_params_set_period_time_near(pcm_handle, hw_params, &period_time, &dir) < 0) {
284         tX_error("ALSA: failed to set period time %i", globals.alsa_period_time);
285         return -1;
286     }
287
288     if (snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir) < 0) {
289         tX_error("ALSA: failed to retrieve period size");
290         return -1;
291     }
292
293     samples_per_buffer = period_size;
294
295     /* Apply all that setup work.. */
296     if (snd_pcm_hw_params(pcm_handle, hw_params) < 0) {
297         tX_error("ALSA: Failed to apply settings to PCM device \"%s\"", pcm_name);
298         snd_pcm_hw_params_free(hw_params);
299         return -1;
300     }
301
302     if (globals.alsa_free_hwstats) {
303         snd_pcm_hw_params_free(hw_params);
304     }
305
306     return 0; // snd_pcm_prepare(pcm_handle);
307 }
308
309 int tX_audiodevice_alsa ::close() {
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()
319     : tX_audiodevice()
320     , pcm_handle(NULL) {}
321
322 void tX_audiodevice_alsa ::play(int16_t* buffer) {
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_PULSE
356 #include <pulse/error.h>
357
358 void tX_audiodevice_pulse::wrap_stream_started_callback(pa_stream* stream, void* userdata) {
359     tX_audiodevice_pulse* device = (tX_audiodevice_pulse*)userdata;
360     device->stream_started_callback(stream);
361 }
362
363 void tX_audiodevice_pulse::wrap_stream_underflow_callback(pa_stream* stream, void* userdata) {
364     tX_audiodevice_pulse* device = (tX_audiodevice_pulse*)userdata;
365     device->stream_underflow_callback(stream);
366 }
367
368 void tX_audiodevice_pulse::wrap_stream_overflow_callback(pa_stream* stream, void* userdata) {
369     tX_audiodevice_pulse* device = (tX_audiodevice_pulse*)userdata;
370     device->stream_overflow_callback(stream);
371 }
372
373 void tX_audiodevice_pulse::wrap_stream_drain_complete_callback(pa_stream* stream, int success, void* userdata) {
374     tX_audiodevice_pulse* device = (tX_audiodevice_pulse*)userdata;
375     device->stream_drain_complete_callback(stream, success);
376 }
377
378 void tX_audiodevice_pulse::wrap_stream_trigger_success_callback(pa_stream* stream, int success, void* userdata) {
379     tX_audiodevice_pulse* device = (tX_audiodevice_pulse*)userdata;
380     device->stream_trigger_success_callback(stream, success);
381 }
382
383 void tX_audiodevice_pulse::wrap_stream_write_callback(pa_stream* stream, size_t length, void* userdata) {
384     tX_audiodevice_pulse* device = (tX_audiodevice_pulse*)userdata;
385     device->stream_write_callback(stream, length);
386 }
387
388 void tX_audiodevice_pulse::wrap_context_state_callback(pa_context* context, void* userdata) {
389     tX_audiodevice_pulse* device = (tX_audiodevice_pulse*)userdata;
390     device->context_state_callback(context);
391 }
392
393 void tX_audiodevice_pulse::context_state_callback(pa_context* context) {
394     pa_context_state_t state;
395
396     state = pa_context_get_state(context);
397
398     tX_debug("pulseaudio context state: %i", state);
399     switch (state) {
400     case PA_CONTEXT_UNCONNECTED:
401     case PA_CONTEXT_CONNECTING:
402     case PA_CONTEXT_AUTHORIZING:
403     case PA_CONTEXT_SETTING_NAME:
404         break;
405     case PA_CONTEXT_FAILED:
406     case PA_CONTEXT_TERMINATED:
407         if (!engine->is_stopped()) {
408             tX_error("pulseaudio disconnected");
409         }
410         break;
411
412     case PA_CONTEXT_READY:
413         pa_sample_spec spec = {
414             .format = PA_SAMPLE_S16LE,
415             .rate = 44100,
416             .channels = 2
417         };
418
419         pa_buffer_attr attr = {
420             .maxlength = (uint32_t)-1,
421             .tlength = (uint32_t)(globals.pulse_buffer_length * 2 * sizeof(int16_t)), // 2 bytes per sample, 2 channels
422             .prebuf = (uint32_t)-1,
423             .minreq = (uint32_t)-1,
424             .fragsize = (uint32_t)-1
425         };
426
427         pa_stream_flags_t flags = PA_STREAM_ADJUST_LATENCY;
428
429         if ((stream = pa_stream_new(context, "terminatorX", &spec, NULL))) {
430             tX_debug("pulseaudio stream created");
431             // pa_stream_set_started_callback(stream, tX_audiodevice_pulse::wrap_stream_started_callback, this);
432             // pa_stream_set_underflow_callback(stream, tX_audiodevice_pulse::wrap_stream_underflow_callback, this);
433             pa_stream_set_overflow_callback(stream, tX_audiodevice_pulse::wrap_stream_overflow_callback, this);
434             pa_stream_set_write_callback(stream, tX_audiodevice_pulse::wrap_stream_write_callback, this);
435
436             if (pa_stream_connect_playback(stream, NULL, &attr, flags, NULL, NULL) >= 0) {
437                 // start the playback.
438                 pa_stream_trigger(stream, tX_audiodevice_pulse::wrap_stream_trigger_success_callback, this);
439             } else {
440                 tX_error("Failed to connect pulseaudio stream playback: %s", pa_strerror(pa_context_errno(context)));
441             }
442         } else {
443             tX_error("Failed to create pulseaudio stream: %s", pa_strerror(pa_context_errno(context)));
444         }
445         break;
446     }
447 }
448
449 void tX_audiodevice_pulse::wrap_context_drain_complete_callback(pa_context* context, void* userdata) {
450     tX_audiodevice_pulse* device = (tX_audiodevice_pulse*)userdata;
451     device->context_drain_complete_callback(context);
452 }
453
454 void tX_audiodevice_pulse::context_drain_complete_callback(pa_context* context) {
455     pa_context_disconnect(context);
456     is_open = false;
457     pa_mainloop_quit(mainloop, 0);
458 }
459
460 void tX_audiodevice_pulse::stream_started_callback(pa_stream* stream) {
461     tX_debug("pulseaudio stream started");
462 }
463
464 void tX_audiodevice_pulse::stream_underflow_callback(pa_stream* stream) {
465     tX_debug("pulseaudio stream underflow");
466 }
467
468 void tX_audiodevice_pulse::stream_overflow_callback(pa_stream* stream) {
469     tX_debug("pulseaudio stream overflow");
470 }
471
472 void tX_audiodevice_pulse::stream_trigger_success_callback(pa_stream* stream, int success) {
473     tX_debug("pulseaudio trigger success %i", success);
474 }
475
476 void tX_audiodevice_pulse::stream_drain_complete_callback(pa_stream* stream, int success) {
477     if (!success) {
478         tX_debug("pulseaudio drain failed %s", pa_strerror(pa_context_errno(context)));
479     } else {
480         pa_operation* operation;
481         pa_stream_disconnect(stream);
482         pa_stream_unref(stream);
483         stream = NULL;
484
485         if (!(operation = pa_context_drain(context, tX_audiodevice_pulse::wrap_context_drain_complete_callback, this))) {
486             pa_context_disconnect(context);
487             is_open = false;
488             pa_mainloop_quit(mainloop, -1);
489         } else {
490             pa_operation_unref(operation);
491         }
492     }
493 }
494
495 void tX_audiodevice_pulse::stream_write_callback(pa_stream* stream, size_t length) {
496     size_t sample_length = length / 2;
497
498     if (engine->is_stopped()) {
499         tX_debug("pulseaudio write callback trying to disconnect pulseaudio");
500         pa_operation* operation;
501         pa_stream_set_write_callback(stream, NULL, NULL);
502         if (!(operation = pa_stream_drain(stream, tX_audiodevice_pulse::wrap_stream_drain_complete_callback, this))) {
503             tX_error("pulseaudio failed to initiate drain %s", pa_strerror(pa_context_errno(context)));
504         }
505         pa_operation_unref(operation);
506     } else {
507         unsigned int outbuffer_pos = 0;
508         unsigned int sample;
509
510         int16_t* outbuffer = NULL;
511         size_t outbuffer_bytes = length;
512         pa_stream_begin_write(stream, (void**)&outbuffer, &outbuffer_bytes);
513
514         if (samples_in_overrun_buffer) {
515             memcpy(outbuffer, overrun_buffer, sizeof(int16_t) * samples_in_overrun_buffer);
516             outbuffer_pos += samples_in_overrun_buffer;
517         }
518
519         while (outbuffer_pos < sample_length) {
520             int16_t* data = engine->render_cycle();
521
522             sample = tX_min(vtt_class::samples_in_mix_buffer, (sample_length - outbuffer_pos));
523
524             memcpy(&outbuffer[outbuffer_pos], data, sizeof(int16_t) * sample);
525             outbuffer_pos += sample;
526
527             if (sample < vtt_class::samples_in_mix_buffer) {
528                 samples_in_overrun_buffer = vtt_class::samples_in_mix_buffer - sample;
529                 /* There's more data in the mixbuffer... */
530                 memcpy(overrun_buffer, &data[sample], sizeof(int16_t) * samples_in_overrun_buffer);
531             } else {
532                 samples_in_overrun_buffer = 0;
533             }
534         }
535
536         if (pa_stream_write(stream, (uint8_t*)outbuffer, length, NULL, 0, PA_SEEK_RELATIVE) < 0) {
537             tX_error("pulseaudio error writing to stream: %s", pa_strerror(pa_context_errno(context)));
538         }
539         outbuffer = NULL;
540     }
541 }
542
543 void tX_audiodevice_pulse::start() {
544     overrun_buffer = new int16_t[vtt_class::samples_in_mix_buffer];
545     samples_in_overrun_buffer = 0;
546     int result;
547
548     tX_debug("handover flow control to pulseaudio");
549
550     while (!engine->is_stopped()) {
551         pa_mainloop_run(mainloop, &result);
552         tX_debug("pulseaudio mainloop has terminated: %i", result);
553     }
554
555     delete[] overrun_buffer;
556 }
557
558 int tX_audiodevice_pulse::open() {
559     mainloop = pa_mainloop_new();
560     mainloop_api = pa_mainloop_get_api(mainloop);
561     context = pa_context_new(mainloop_api, "terminatorX");
562     pa_context_flags_t flags = PA_CONTEXT_NOFLAGS;
563     pa_context_connect(context, NULL, flags, NULL);
564     pa_context_set_state_callback(context, tX_audiodevice_pulse::wrap_context_state_callback, this);
565
566     sample_rate = 44100;
567     tX_debug("pulseaudio opened.");
568
569     is_open = true;
570     return 0;
571 }
572
573 int tX_audiodevice_pulse ::close() {
574     return 0;
575 }
576
577 tX_audiodevice_pulse ::tX_audiodevice_pulse()
578     : tX_audiodevice()
579     , mainloop(NULL)
580     , mainloop_api(NULL)
581     , context(NULL)
582     , stream(NULL) {
583 }
584
585 void tX_audiodevice_pulse ::play(int16_t* buffer) {
586     tX_error("tX_audiodevice_pulse::play()");
587 }
588
589 tX_audiodevice_pulse ::~tX_audiodevice_pulse() {
590 }
591
592 #endif // USE_PULSE
593
594 #ifdef USE_JACK
595
596 tX_jack_client tX_jack_client::instance;
597
598 bool tX_jack_client::init() {
599     if (!client_initialized) {
600         if ((client = jack_client_open("terminatorX", (jack_options_t)NULL, NULL)) == 0) {
601             tX_error("tX_jack_client() -> failed to connect to jackd.");
602         } else {
603             client_initialized = true;
604             const char** ports;
605
606             /* Setting up jack callbacks... */
607             jack_set_process_callback(client, tX_jack_client::process, NULL);
608             jack_set_sample_rate_callback(client, tX_jack_client::srate, NULL);
609             jack_on_shutdown(client, tX_jack_client::shutdown, NULL);
610
611             /* Creating the port... */
612             left_port = jack_port_register(client, "output_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
613             right_port = jack_port_register(client, "output_2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
614
615             /* Action... */
616             jack_activate(client);
617
618             /* Connect some ports... */
619             if ((ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical | JackPortIsInput)) == NULL) {
620                 tX_error("tX_jack_client() no ports to connect to found. Connect manually.");
621             } else if (ports[0] && ports[1]) {
622                 if (jack_connect(client, jack_port_name(left_port), ports[0])) {
623                     tX_error("tX_jack_client() failed to connect left port.");
624                 }
625                 if (jack_connect(client, jack_port_name(right_port), ports[1])) {
626                     tX_error("tX_jack_client() failed to connect right port.");
627                 }
628                 free(ports);
629             }
630         }
631     }
632
633     return client_initialized;
634 }
635
636 tX_jack_client::tX_jack_client()
637     : device(NULL)
638     , jack_shutdown(false)
639     , client_initialized(false) {
640     jack_set_error_function(tX_jack_client::error);
641 }
642
643 tX_jack_client::~tX_jack_client() {
644     if (client)
645         jack_client_close(client);
646 }
647
648 void tX_jack_client::error(const char* desc) {
649     tX_error("jack error: %s.", desc);
650 }
651
652 int tX_jack_client::srate(jack_nframes_t nframes, void* arg) {
653     tX_error("tX_jack_client::srate() jack changed samplerate - ignored.");
654     return 0;
655 }
656
657 void tX_jack_client::shutdown(void* arg) {
658     tX_error("tX_jack_client::shutdown() jack daemon has shut down. Bad!");
659     instance.jack_shutdown = true;
660 }
661
662 int tX_jack_client::process(jack_nframes_t nframes, void* arg) {
663     return instance.play(nframes);
664
665     /* Hmm, what to do in such a case? */
666     return 0;
667 }
668
669 int tX_jack_client::play(jack_nframes_t nframes) {
670     jack_default_audio_sample_t* left = (jack_default_audio_sample_t*)jack_port_get_buffer(left_port, nframes);
671     jack_default_audio_sample_t* right = (jack_default_audio_sample_t*)jack_port_get_buffer(right_port, nframes);
672
673     if (device) {
674         device->fill_frames(left, right, nframes);
675     } else {
676         memset(left, 0, sizeof(jack_default_audio_sample_t) * nframes);
677         memset(right, 0, sizeof(jack_default_audio_sample_t) * nframes);
678     }
679
680     return 0;
681 }
682
683 int tX_jack_client::get_sample_rate() {
684     return jack_get_sample_rate(client);
685 }
686
687 /* tX_audiodevice_jack */
688
689 tX_audiodevice_jack::tX_audiodevice_jack()
690     : tX_audiodevice() {
691     client = NULL;
692 }
693
694 int tX_audiodevice_jack::open() {
695     tX_jack_client* jack_client = tX_jack_client::get_instance();
696
697     if (jack_client) {
698         if (jack_client->init()) {
699             sample_rate = jack_client->get_sample_rate();
700             client = jack_client;
701             is_open = true;
702
703             return 0;
704         }
705     }
706
707     return 1;
708 }
709
710 int tX_audiodevice_jack::close() {
711     if (client) {
712         client->set_device(NULL);
713     }
714
715     is_open = false;
716
717     return 0;
718 }
719
720 void tX_audiodevice_jack::play(int16_t* buffer) {
721     tX_error("tX_audiodevice_jack::play()");
722 }
723
724 void tX_audiodevice_jack::start() {
725     overrun_buffer = new f_prec[vtt_class::samples_in_mix_buffer];
726
727     client->set_device(this);
728     while ((!engine->is_stopped()) && !(client->get_jack_shutdown())) {
729         usleep(100);
730     }
731     client->set_device(NULL);
732
733     delete[] overrun_buffer;
734 }
735
736 void tX_audiodevice_jack::fill_frames(jack_default_audio_sample_t* left, jack_default_audio_sample_t* right, jack_nframes_t nframes) {
737     unsigned int outbuffer_pos = 0;
738     unsigned int sample;
739
740     if (samples_in_overrun_buffer) {
741         for (sample = 0; ((sample < samples_in_overrun_buffer) && (outbuffer_pos < nframes));) {
742             left[outbuffer_pos] = overrun_buffer[sample++] / 32767.0;
743             right[outbuffer_pos++] = overrun_buffer[sample++] / 32767.0;
744         }
745     }
746
747     while (outbuffer_pos < nframes) {
748         if (is_open) {
749             engine->render_cycle();
750         }
751
752         for (sample = 0; ((sample < (unsigned int)vtt_class::samples_in_mix_buffer) && (outbuffer_pos < nframes));) {
753             left[outbuffer_pos] = vtt_class::mix_buffer[sample++] / 32767.0;
754             right[outbuffer_pos++] = vtt_class::mix_buffer[sample++] / 32767.0;
755         }
756
757         if (sample < (unsigned int)vtt_class::samples_in_mix_buffer) {
758             samples_in_overrun_buffer = vtt_class::samples_in_mix_buffer - sample;
759             /* There's more data in the mixbuffer... */
760             memcpy(overrun_buffer, &vtt_class::mix_buffer[sample], sizeof(f_prec) * samples_in_overrun_buffer);
761         } else {
762             samples_in_overrun_buffer = 0;
763         }
764     }
765 }
766
767 #endif // USE_JACK