Verbose plugin loading, code and minor gui cleanups - Alex
[terminatorX.git] / src / tX_audiodevice.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2004  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, 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>
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 <string.h>
47 #include <errno.h>
48 #include <stdlib.h>
49 #include "tX_engine.h"
50
51 tX_audiodevice :: tX_audiodevice() : samples_per_buffer(0),
52 current_buffer(0), buffer_pos(0), is_open(false)
53 {
54         sample_buffer[0]=NULL;
55         sample_buffer[1]=NULL;
56         engine=tX_engine::get_instance();
57 }
58
59 void tX_audiodevice :: start() {
60         sample_buffer[0]=new int16_t[samples_per_buffer*2];
61         sample_buffer[1]=new int16_t[samples_per_buffer*2];
62         int current=0;
63         vtt_buffer_size=vtt_class::get_mix_buffer_size()<<1;
64         
65         buffer_pos=0;
66         
67         while (!engine->is_stopped()) {
68                 current=current ? 0 : 1;
69                 
70                 int16_t *current_buffer=sample_buffer[current];
71                 int16_t *next_buffer=sample_buffer[current ? 0 : 1];
72                 
73                 fill_buffer(current_buffer, next_buffer);
74                 play(current_buffer);
75         }
76         
77         delete [] sample_buffer[0];
78         delete [] sample_buffer[1];
79 }
80
81 void tX_audiodevice :: fill_buffer(int16_t *target_buffer, int16_t *next_target_buffer) {
82         int prefill=0;
83         
84         while (buffer_pos <= samples_per_buffer) {
85                 int16_t *data=engine->render_cycle();
86                 
87                 int rest=(buffer_pos+vtt_buffer_size)-samples_per_buffer;
88                 
89                 if (rest<=0) {
90                         memcpy(&target_buffer[buffer_pos], data, vtt_buffer_size << 1);
91                 } else {
92                         memcpy(&target_buffer[buffer_pos], data, (vtt_buffer_size-rest) << 1);
93                         memcpy(next_target_buffer, &data[vtt_buffer_size-rest], rest << 1);
94                         prefill=rest;
95                 }
96                 
97                 buffer_pos+=vtt_buffer_size;
98         }
99         
100         buffer_pos=prefill;
101 }
102
103 /* Driver Specific Code follows.. */
104
105 #ifdef USE_OSS
106
107 int tX_audiodevice_oss :: open()
108 {
109         int i=0;
110         int p;
111         int buff_cfg;
112
113         if (fd) return (1);
114         fd=::open(globals.oss_device, O_WRONLY, 0);
115         
116         if (fd==-1) {
117                 tX_error("tX_audiodevice_oss::open() can't open device: %s", strerror(errno));
118                 return -1;
119         }
120         
121         is_open=true;
122         
123         /* setting buffer size */       
124         buff_cfg=(globals.oss_buff_no<<16) | globals.oss_buff_size;
125         p=buff_cfg;
126
127         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);
128                 
129         i = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &p);
130         ioctl(fd, SNDCTL_DSP_RESET, 0);         
131
132         /* 16 Bits */
133         
134         p =  16;
135         i +=  ioctl(fd, SOUND_PCM_WRITE_BITS, &p);
136
137         /* STEREO :) */
138         
139         p =  2;
140         i += ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &p);
141         
142         /* 44.1 khz */
143
144         p =  globals.oss_samplerate;
145         i += ioctl(fd, SOUND_PCM_WRITE_RATE, &p);
146         
147         sample_rate=globals.oss_samplerate;
148         
149         /* Figure actual blocksize.. */
150         
151         i += ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize);
152
153         samples_per_buffer=blocksize/sizeof(int16_t);
154
155         tX_debug("tX_adudiodevice_oss::open() - blocksize: %i, samples_per_buffer: %i", blocksize, samples_per_buffer);
156         
157         ioctl(fd, SNDCTL_DSP_SYNC, 0);
158
159         return i;
160 }
161
162 int tX_audiodevice_oss :: close()
163 {
164         if (!fd) {      
165                 return(1);              
166         }
167         is_open=false;
168         ::close(fd);
169         fd=0;
170         blocksize=0;
171                 
172         return 0;
173 }
174
175 tX_audiodevice_oss :: tX_audiodevice_oss() : tX_audiodevice(),
176 fd(0), blocksize(0) {}
177
178 void tX_audiodevice_oss :: play(int16_t *buffer)
179 {
180 #ifdef BIG_ENDIAN_MACHINE
181         swapbuffer (buffer, samples_per_buffer);
182 #endif
183         int res=write(fd, buffer, blocksize);   
184         if (res==-1) {
185                 tX_error("failed to write to audiodevice: %s", strerror(errno));
186                 exit(-1);
187         }
188 }
189
190 #endif //USE_OSS
191
192 #ifdef USE_ALSA
193
194 int tX_audiodevice_alsa :: open()
195 {
196         snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
197         snd_pcm_hw_params_t *hw_params;
198         char pcm_name[64];
199
200         /* Removing the device ID comment... */
201         for (unsigned int i=0; i<strlen(globals.alsa_device_id); i++) {
202                 if (globals.alsa_device_id[i]!='#') {
203                         pcm_name[i]=globals.alsa_device_id[i];
204                 } else {
205                         pcm_name[i]=0;
206                         break;
207                 }
208         }
209         
210         if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
211                 tX_error("ALSA: Failed to access PCM device \"%s\"", pcm_name);
212                 return -1;
213         }
214         
215         is_open=true;
216
217         snd_pcm_hw_params_alloca(&hw_params);   
218         
219         if (snd_pcm_hw_params_any(pcm_handle, hw_params) < 0) {
220                 tX_error("ALSA: Failed to configure PCM device \"%s\"", pcm_name);
221                 snd_pcm_hw_params_free (hw_params);
222                 return -1;
223         }
224         
225         /* Setting INTERLEAVED stereo... */
226 #ifdef USE_ALSA_MEMCPY
227         if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
228 #else
229         if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
230 #endif  
231                 tX_error("ALSA: Failed to set interleaved access for PCM device \"%s\"", pcm_name);
232                 snd_pcm_hw_params_free (hw_params);
233                 return -1;
234         }
235         
236         /* Make it 16 Bit LE - we handle converting from BE anyway... */
237         if (snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16_LE) < 0) {
238                 tX_error("ALSA: Error setting 16 Bit sample width for PCM device \"%s\"", pcm_name);
239                 snd_pcm_hw_params_free (hw_params);
240                 return -1;
241         }
242         
243         /* Setting sampling rate */
244         unsigned int hw_rate=(unsigned int)globals.alsa_samplerate;
245         int dir;
246         
247         if (snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &hw_rate, &dir) < 0) {
248                 tX_error("ALSA: Failed setting sample rate: %i", globals.alsa_samplerate);
249                 snd_pcm_hw_params_free (hw_params);
250                 return -1;
251         }
252         
253         if (dir != 0) {
254                 tX_warning("ALSA: The PCM device \"%s\" doesnt support 44100 Hz playback - using %i instead", pcm_name, hw_rate);
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 retreive 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 retreive 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 {
311         if (is_open) {
312                 snd_pcm_close(pcm_handle);
313         }
314         is_open=false;
315         
316         return 0;
317 }
318
319 tX_audiodevice_alsa :: tX_audiodevice_alsa() : tX_audiodevice(),
320 pcm_handle(NULL) {}
321
322 void tX_audiodevice_alsa :: play(int16_t *buffer)
323 {
324         int underrun_ctr=0;
325         snd_pcm_sframes_t pcmreturn;
326 #ifdef BIG_ENDIAN_MACHINE
327         swapbuffer (buffer, samples_per_buffer);
328 #endif
329         
330 #ifdef USE_ALSA_MEMCPY
331         pcmreturn = snd_pcm_writei(pcm_handle, buffer, samples_per_buffer >> 1);
332 #else   
333         pcmreturn = snd_pcm_mmap_writei(pcm_handle, buffer, samples_per_buffer >> 1);
334 #endif
335         
336         while (pcmreturn==-EPIPE) {
337                 snd_pcm_prepare(pcm_handle);
338                 
339 #ifdef USE_ALSA_MEMCPY
340                 pcmreturn = snd_pcm_writei(pcm_handle, buffer, samples_per_buffer >> 1);
341 #else   
342                 pcmreturn = snd_pcm_mmap_writei(pcm_handle, buffer, samples_per_buffer >> 1);
343 #endif
344                 underrun_ctr++;
345                 if (underrun_ctr>100) {
346                         tX_error("tX_audiodevice_alsa::play() more than 10 EPIPE cycles. Giving up.");
347                         break;
348                 }
349                 //tX_warning("ALSA: ** buffer underrun **");
350         }
351         
352         if (pcmreturn<0) {
353                 printf("snd_pcm_writei says: %s.\n", strerror(-1*pcmreturn));
354         }
355 }
356
357 #endif //USE_ALSA
358
359 #ifdef USE_JACK
360
361 tX_jack_client* tX_jack_client::instance=NULL;
362
363 void tX_jack_client::init()
364 {
365                 tX_jack_client *test=new tX_jack_client();
366                 
367                 if (!instance) {
368                         delete test;
369                 }       
370 }
371
372 tX_jack_client::tX_jack_client():device(NULL),jack_shutdown(false)
373 {
374         jack_set_error_function(tX_jack_client::error);
375         
376         if ((client=jack_client_new("terminatorX"))==0) {
377                 tX_error("tX_jack_client() -> failed to connect to jackd.");
378                 instance=NULL;
379         } else {
380                 instance=this;
381                 const char **ports;
382                 
383                 /* Setting up jack callbacks... */              
384                 jack_set_process_callback(client, tX_jack_client::process, NULL);
385                 jack_set_sample_rate_callback(client, tX_jack_client::srate, NULL);             
386                 jack_on_shutdown (client, tX_jack_client::shutdown, NULL);
387                 
388                 /* Creating the port... */
389                 left_port = jack_port_register (client, "output_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
390                 right_port = jack_port_register (client, "output_2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
391         
392                 /* Action... */
393                 jack_activate(client);
394                 
395                 /* Connect some ports... */
396                 if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
397                         tX_error("tX_jack_client() no ports to connect to found. Connect manually.");
398                 } else if (ports[0] && ports[1]) {
399                         if (jack_connect (client, jack_port_name(left_port), ports[0])) {
400                                 tX_error("tX_jack_client() failed to connect left port.");
401                         }
402                         if (jack_connect (client, jack_port_name(right_port), ports[1])) {
403                                 tX_error("tX_jack_client() failed to connect right port.");
404                         }
405                         free (ports);
406                 }
407         }
408 }
409
410 tX_jack_client::~tX_jack_client()
411 {
412         instance=NULL;
413         if (client) jack_client_close(client);
414 }
415
416 void tX_jack_client::error(const char *desc)
417 {
418         tX_error("jack error: %s.", desc);
419 }
420
421 int tX_jack_client::srate(jack_nframes_t nframes, void *arg)
422 {
423         tX_error("tX_jack_client::srate() jack changed samplerate - ignored.");
424         return 0;
425 }
426
427 void tX_jack_client::shutdown(void *arg)
428 {
429         tX_error("tX_jack_client::shutdown() jack daemon has shut down. Bad!");
430         if (instance) instance->jack_shutdown=true;
431 }
432
433 int tX_jack_client::process(jack_nframes_t nframes, void *arg)
434 {
435         if (instance) {
436                 return instance->play(nframes);
437         }
438         
439         /* Hmm, what to do in such a case? */
440         return 0;
441 }
442
443 int tX_jack_client::play(jack_nframes_t nframes)
444 {
445         jack_default_audio_sample_t *left = (jack_default_audio_sample_t *) jack_port_get_buffer (left_port, nframes);
446         jack_default_audio_sample_t *right = (jack_default_audio_sample_t *) jack_port_get_buffer (right_port, nframes);
447
448         if (device) {
449                 device->fill_frames(left, right, nframes);
450         } else {
451                 memset(left, 0, sizeof (jack_default_audio_sample_t) * nframes);
452                 memset(right, 0, sizeof (jack_default_audio_sample_t) * nframes);
453         }
454         
455         return 0;
456 }
457
458 int tX_jack_client::get_sample_rate() 
459 {
460         return jack_get_sample_rate(client);
461 }
462
463 /* tX_audiodevice_jack */
464
465 tX_audiodevice_jack::tX_audiodevice_jack():tX_audiodevice()
466 {
467         client=NULL;
468 }
469
470 int tX_audiodevice_jack::open()
471 {
472         tX_jack_client *jack_client=tX_jack_client::get_instance();
473         
474         if (jack_client) {
475                 sample_rate=jack_client->get_sample_rate();
476                 client=jack_client;
477                 is_open=true;
478                 
479                 return 0;
480         }
481         
482         return 1;
483 }
484
485 int tX_audiodevice_jack::close()
486 {
487         if (client) {
488                 client->set_device(NULL);
489         }
490         
491         is_open=false;  
492         
493         return 0;
494 }
495
496 void tX_audiodevice_jack::play(int16_t *buffer)
497 {
498         tX_error("tX_audiodevice_jack::play()");
499 }
500
501 void tX_audiodevice_jack::start()
502 {
503         overrun_buffer=new f_prec[vtt_class::samples_in_mix_buffer];
504         
505         client->set_device(this);
506         while ((!engine->is_stopped()) && !(client->get_jack_shutdown())) {
507                 usleep(100);
508         }       
509         client->set_device(NULL);
510         
511         delete [] overrun_buffer;
512 }
513
514 void tX_audiodevice_jack::fill_frames(jack_default_audio_sample_t *left, jack_default_audio_sample_t *right, jack_nframes_t nframes)
515 {
516         unsigned int outbuffer_pos=0;
517         unsigned int sample;
518         
519         if (samples_in_overrun_buffer) {
520                 for (sample=0; ((sample<samples_in_overrun_buffer) && (outbuffer_pos<nframes));) {
521                         left[outbuffer_pos]=overrun_buffer[sample++]/32767.0;
522                         right[outbuffer_pos++]=overrun_buffer[sample++]/32767.0;
523                 }
524         }
525         
526         while (outbuffer_pos<nframes) {
527                 engine->render_cycle();
528                 
529                 for (sample=0; ((sample<(unsigned int) vtt_class::samples_in_mix_buffer) && (outbuffer_pos<nframes));) {
530                         left[outbuffer_pos]=vtt_class::mix_buffer[sample++]/32767.0;
531                         right[outbuffer_pos++]=vtt_class::mix_buffer[sample++]/32767.0;
532                 }
533                 
534                 if (sample<(unsigned int) vtt_class::samples_in_mix_buffer) {
535                         samples_in_overrun_buffer=vtt_class::samples_in_mix_buffer-sample;
536                         /* There's more data in the mixbuffer... */
537                         memcpy(overrun_buffer, &vtt_class::mix_buffer[sample], sizeof(f_prec) * samples_in_overrun_buffer);
538                 } else {
539                         samples_in_overrun_buffer=0;
540                 }
541         }
542 }
543
544 #endif // USE_JACK