Fixing big endian playback with ALSA and long outstanding bug with
[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 #include <string.h>
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
195 int tX_audiodevice_alsa :: open()
196 {
197         snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
198         snd_pcm_hw_params_t *hw_params;
199         char pcm_name[64];
200         char *pos;
201         
202         strncpy(pcm_name, globals.alsa_device_id, sizeof(pcm_name));
203         if ((pos = strchr(pcm_name, '#')) != NULL) *pos = 0;
204         
205         if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
206                 tX_error("ALSA: Failed to access PCM device \"%s\"", pcm_name);
207                 return -1;
208         }
209         
210         is_open=true;
211
212         snd_pcm_hw_params_alloca(&hw_params);   
213         
214         if (snd_pcm_hw_params_any(pcm_handle, hw_params) < 0) {
215                 tX_error("ALSA: Failed to configure PCM device \"%s\"", pcm_name);
216                 snd_pcm_hw_params_free (hw_params);
217                 return -1;
218         }
219         
220         /* Setting INTERLEAVED stereo... */
221 #ifdef USE_ALSA_MEMCPY
222         if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
223 #else
224         if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
225 #endif  
226                 tX_error("ALSA: Failed to set interleaved access for PCM device \"%s\"", pcm_name);
227                 snd_pcm_hw_params_free (hw_params);
228                 return -1;
229         }
230         
231         /* Make it 16 Bit native endian */
232         if (snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16) < 0) {
233                 tX_error("ALSA: Error setting 16 Bit sample width for PCM device \"%s\"", pcm_name);
234                 snd_pcm_hw_params_free (hw_params);
235                 return -1;
236         }
237         
238         /* Setting sampling rate */
239         unsigned int hw_rate=(unsigned int)globals.alsa_samplerate;
240         int dir;
241         
242         if (snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &hw_rate, &dir) < 0) {
243                 tX_error("ALSA: Failed setting sample rate: %i", globals.alsa_samplerate);
244                 snd_pcm_hw_params_free (hw_params);
245                 return -1;
246         }
247         
248         if (dir != 0) {
249                 tX_warning("ALSA: The PCM device \"%s\" doesnt support 44100 Hz playback - using %i instead", pcm_name, hw_rate);
250         }       
251
252         sample_rate=hw_rate;
253         
254         /* Using stereo output */
255         if (snd_pcm_hw_params_set_channels(pcm_handle, hw_params, 2) < 0) {
256                 tX_error("ALSA: PCM device \"%s\" does not support stereo operation", pcm_name);
257                 snd_pcm_hw_params_free (hw_params);
258                 return -1;
259         }
260         
261         unsigned int buffer_time=globals.alsa_buffer_time;
262         unsigned int period_time=globals.alsa_period_time;
263         
264         if (snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hw_params, &buffer_time, &dir) < 0) {
265                 tX_error("ALSA: failed to set the buffer time opf %i usecs", globals.alsa_buffer_time);
266                 return -1;
267         }
268
269         long unsigned int buffer_size;
270
271         if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) < 0) {
272                 tX_error("ALSA: failed to retreive buffer size");
273                 return -1;
274         }
275         
276         tX_debug("ALSA: buffer size is %lu", buffer_size);
277         
278         if (snd_pcm_hw_params_set_period_time_near(pcm_handle, hw_params, &period_time, &dir) < 0) {
279                 tX_error("ALSA: failed to set period time %i", globals.alsa_period_time);
280                 return -1;
281         }
282         
283         if (snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir)<0) {
284                 tX_error("ALSA: failed to retreive period size");
285                 return -1;
286         }
287         
288         samples_per_buffer=period_size;
289         
290         /* Apply all that setup work.. */
291         if (snd_pcm_hw_params(pcm_handle, hw_params) < 0) {
292                 tX_error("ALSA: Failed to apply settings to PCM device \"%s\"", pcm_name);
293                 snd_pcm_hw_params_free (hw_params);
294                 return -1;
295         }
296         
297         if (globals.alsa_free_hwstats) {
298                 snd_pcm_hw_params_free (hw_params);
299         }
300         
301         return 0; //snd_pcm_prepare(pcm_handle);
302 }
303
304 int tX_audiodevice_alsa :: close()
305 {
306         if (is_open) {
307                 snd_pcm_close(pcm_handle);
308         }
309         is_open=false;
310         
311         return 0;
312 }
313
314 tX_audiodevice_alsa :: tX_audiodevice_alsa() : tX_audiodevice(),
315 pcm_handle(NULL) {}
316
317 void tX_audiodevice_alsa :: play(int16_t *buffer)
318 {
319         int underrun_ctr=0;
320         snd_pcm_sframes_t pcmreturn;
321         
322 #ifdef USE_ALSA_MEMCPY
323         pcmreturn = snd_pcm_writei(pcm_handle, buffer, samples_per_buffer >> 1);
324 #else   
325         pcmreturn = snd_pcm_mmap_writei(pcm_handle, buffer, samples_per_buffer >> 1);
326 #endif
327         
328         while (pcmreturn==-EPIPE) {
329                 snd_pcm_prepare(pcm_handle);
330                 
331 #ifdef USE_ALSA_MEMCPY
332                 pcmreturn = snd_pcm_writei(pcm_handle, buffer, samples_per_buffer >> 1);
333 #else   
334                 pcmreturn = snd_pcm_mmap_writei(pcm_handle, buffer, samples_per_buffer >> 1);
335 #endif
336                 underrun_ctr++;
337                 if (underrun_ctr>100) {
338                         tX_error("tX_audiodevice_alsa::play() more than 10 EPIPE cycles. Giving up.");
339                         break;
340                 }
341                 //tX_warning("ALSA: ** buffer underrun **");
342         }
343         
344         if (pcmreturn<0) {
345                 printf("snd_pcm_writei says: %s.\n", strerror(-1*pcmreturn));
346         }
347 }
348
349 #endif //USE_ALSA
350
351 #ifdef USE_JACK
352
353 tX_jack_client* tX_jack_client::instance=NULL;
354
355 void tX_jack_client::init()
356 {
357                 tX_jack_client *test=new tX_jack_client();
358                 
359                 if (!instance) {
360                         delete test;
361                 }       
362 }
363
364 tX_jack_client::tX_jack_client():device(NULL),jack_shutdown(false)
365 {
366         jack_set_error_function(tX_jack_client::error);
367         
368         if ((client=jack_client_new("terminatorX"))==0) {
369                 tX_error("tX_jack_client() -> failed to connect to jackd.");
370                 instance=NULL;
371         } else {
372                 instance=this;
373                 const char **ports;
374                 
375                 /* Setting up jack callbacks... */              
376                 jack_set_process_callback(client, tX_jack_client::process, NULL);
377                 jack_set_sample_rate_callback(client, tX_jack_client::srate, NULL);             
378                 jack_on_shutdown (client, tX_jack_client::shutdown, NULL);
379                 
380                 /* Creating the port... */
381                 left_port = jack_port_register (client, "output_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
382                 right_port = jack_port_register (client, "output_2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
383         
384                 /* Action... */
385                 jack_activate(client);
386                 
387                 /* Connect some ports... */
388                 if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
389                         tX_error("tX_jack_client() no ports to connect to found. Connect manually.");
390                 } else if (ports[0] && ports[1]) {
391                         if (jack_connect (client, jack_port_name(left_port), ports[0])) {
392                                 tX_error("tX_jack_client() failed to connect left port.");
393                         }
394                         if (jack_connect (client, jack_port_name(right_port), ports[1])) {
395                                 tX_error("tX_jack_client() failed to connect right port.");
396                         }
397                         free (ports);
398                 }
399         }
400 }
401
402 tX_jack_client::~tX_jack_client()
403 {
404         instance=NULL;
405         if (client) jack_client_close(client);
406 }
407
408 void tX_jack_client::error(const char *desc)
409 {
410         tX_error("jack error: %s.", desc);
411 }
412
413 int tX_jack_client::srate(jack_nframes_t nframes, void *arg)
414 {
415         tX_error("tX_jack_client::srate() jack changed samplerate - ignored.");
416         return 0;
417 }
418
419 void tX_jack_client::shutdown(void *arg)
420 {
421         tX_error("tX_jack_client::shutdown() jack daemon has shut down. Bad!");
422         if (instance) instance->jack_shutdown=true;
423 }
424
425 int tX_jack_client::process(jack_nframes_t nframes, void *arg)
426 {
427         if (instance) {
428                 return instance->play(nframes);
429         }
430         
431         /* Hmm, what to do in such a case? */
432         return 0;
433 }
434
435 int tX_jack_client::play(jack_nframes_t nframes)
436 {
437         jack_default_audio_sample_t *left = (jack_default_audio_sample_t *) jack_port_get_buffer (left_port, nframes);
438         jack_default_audio_sample_t *right = (jack_default_audio_sample_t *) jack_port_get_buffer (right_port, nframes);
439
440         if (device) {
441                 device->fill_frames(left, right, nframes);
442         } else {
443                 memset(left, 0, sizeof (jack_default_audio_sample_t) * nframes);
444                 memset(right, 0, sizeof (jack_default_audio_sample_t) * nframes);
445         }
446         
447         return 0;
448 }
449
450 int tX_jack_client::get_sample_rate() 
451 {
452         return jack_get_sample_rate(client);
453 }
454
455 /* tX_audiodevice_jack */
456
457 tX_audiodevice_jack::tX_audiodevice_jack():tX_audiodevice()
458 {
459         client=NULL;
460 }
461
462 int tX_audiodevice_jack::open()
463 {
464         tX_jack_client *jack_client=tX_jack_client::get_instance();
465         
466         if (jack_client) {
467                 sample_rate=jack_client->get_sample_rate();
468                 client=jack_client;
469                 is_open=true;
470                 
471                 return 0;
472         }
473         
474         return 1;
475 }
476
477 int tX_audiodevice_jack::close()
478 {
479         if (client) {
480                 client->set_device(NULL);
481         }
482         
483         is_open=false;  
484         
485         return 0;
486 }
487
488 void tX_audiodevice_jack::play(int16_t *buffer)
489 {
490         tX_error("tX_audiodevice_jack::play()");
491 }
492
493 void tX_audiodevice_jack::start()
494 {
495         overrun_buffer=new f_prec[vtt_class::samples_in_mix_buffer];
496         
497         client->set_device(this);
498         while ((!engine->is_stopped()) && !(client->get_jack_shutdown())) {
499                 usleep(100);
500         }       
501         client->set_device(NULL);
502         
503         delete [] overrun_buffer;
504 }
505
506 void tX_audiodevice_jack::fill_frames(jack_default_audio_sample_t *left, jack_default_audio_sample_t *right, jack_nframes_t nframes)
507 {
508         unsigned int outbuffer_pos=0;
509         unsigned int sample;
510         
511         if (samples_in_overrun_buffer) {
512                 for (sample=0; ((sample<samples_in_overrun_buffer) && (outbuffer_pos<nframes));) {
513                         left[outbuffer_pos]=overrun_buffer[sample++]/32767.0;
514                         right[outbuffer_pos++]=overrun_buffer[sample++]/32767.0;
515                 }
516         }
517         
518         while (outbuffer_pos<nframes) {
519                 engine->render_cycle();
520                 
521                 for (sample=0; ((sample<(unsigned int) vtt_class::samples_in_mix_buffer) && (outbuffer_pos<nframes));) {
522                         left[outbuffer_pos]=vtt_class::mix_buffer[sample++]/32767.0;
523                         right[outbuffer_pos++]=vtt_class::mix_buffer[sample++]/32767.0;
524                 }
525                 
526                 if (sample<(unsigned int) vtt_class::samples_in_mix_buffer) {
527                         samples_in_overrun_buffer=vtt_class::samples_in_mix_buffer-sample;
528                         /* There's more data in the mixbuffer... */
529                         memcpy(overrun_buffer, &vtt_class::mix_buffer[sample], sizeof(f_prec) * samples_in_overrun_buffer);
530                 } else {
531                         samples_in_overrun_buffer=0;
532                 }
533         }
534 }
535
536 #endif // USE_JACK