2 terminatorX - realtime audio scratching software
3 Copyright (C) 1999-2004 Alexander König
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.
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.
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.
19 File: tX_aduiodevice.cc
21 Description: Implements Audiodevice handling...
24 #define ALSA_PCM_NEW_HW_PARAMS_API
26 #include "tX_audiodevice.h"
29 #include <sys/types.h>
31 #include <sys/ioctl.h>
33 #include <sys/soundcard.h>
37 #include "tX_endian.h"
40 # define __USE_XOPEN // we need this for swab()
50 #include "tX_engine.h"
52 tX_audiodevice :: tX_audiodevice() : samples_per_buffer(0),
53 current_buffer(0), buffer_pos(0), is_open(false)
55 sample_buffer[0]=NULL;
56 sample_buffer[1]=NULL;
57 engine=tX_engine::get_instance();
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];
64 vtt_buffer_size=vtt_class::get_mix_buffer_size()<<1;
68 while (!engine->is_stopped()) {
69 current=current ? 0 : 1;
71 int16_t *current_buffer=sample_buffer[current];
72 int16_t *next_buffer=sample_buffer[current ? 0 : 1];
74 fill_buffer(current_buffer, next_buffer);
78 delete [] sample_buffer[0];
79 delete [] sample_buffer[1];
82 void tX_audiodevice :: fill_buffer(int16_t *target_buffer, int16_t *next_target_buffer) {
85 while (buffer_pos <= samples_per_buffer) {
86 int16_t *data=engine->render_cycle();
88 int rest=(buffer_pos+vtt_buffer_size)-samples_per_buffer;
91 memcpy(&target_buffer[buffer_pos], data, vtt_buffer_size << 1);
93 memcpy(&target_buffer[buffer_pos], data, (vtt_buffer_size-rest) << 1);
94 memcpy(next_target_buffer, &data[vtt_buffer_size-rest], rest << 1);
98 buffer_pos+=vtt_buffer_size;
104 /* Driver Specific Code follows.. */
108 int tX_audiodevice_oss :: open()
115 fd=::open(globals.oss_device, O_WRONLY, 0);
118 tX_error("tX_audiodevice_oss::open() can't open device: %s", strerror(errno));
124 /* setting buffer size */
125 buff_cfg=(globals.oss_buff_no<<16) | globals.oss_buff_size;
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);
130 i = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &p);
131 ioctl(fd, SNDCTL_DSP_RESET, 0);
136 i += ioctl(fd, SOUND_PCM_WRITE_BITS, &p);
141 i += ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &p);
145 p = globals.oss_samplerate;
146 i += ioctl(fd, SOUND_PCM_WRITE_RATE, &p);
148 sample_rate=globals.oss_samplerate;
150 /* Figure actual blocksize.. */
152 i += ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize);
154 samples_per_buffer=blocksize/sizeof(int16_t);
156 tX_debug("tX_adudiodevice_oss::open() - blocksize: %i, samples_per_buffer: %i", blocksize, samples_per_buffer);
158 ioctl(fd, SNDCTL_DSP_SYNC, 0);
163 int tX_audiodevice_oss :: close()
176 tX_audiodevice_oss :: tX_audiodevice_oss() : tX_audiodevice(),
177 fd(0), blocksize(0) {}
179 void tX_audiodevice_oss :: play(int16_t *buffer)
181 #ifdef BIG_ENDIAN_MACHINE
182 swapbuffer (buffer, samples_per_buffer);
184 int res=write(fd, buffer, blocksize);
186 tX_error("failed to write to audiodevice: %s", strerror(errno));
195 int tX_audiodevice_alsa :: open()
197 snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
198 snd_pcm_hw_params_t *hw_params;
202 strncpy(pcm_name, globals.alsa_device_id, sizeof(pcm_name));
203 if ((pos = strchr(pcm_name, '#')) != NULL) *pos = 0;
205 if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
206 tX_error("ALSA: Failed to access PCM device \"%s\"", pcm_name);
212 snd_pcm_hw_params_alloca(&hw_params);
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);
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) {
224 if (snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
226 tX_error("ALSA: Failed to set interleaved access for PCM device \"%s\"", pcm_name);
227 snd_pcm_hw_params_free (hw_params);
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);
238 /* Setting sampling rate */
239 unsigned int hw_rate=(unsigned int)globals.alsa_samplerate;
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);
249 tX_warning("ALSA: The PCM device \"%s\" doesnt support 44100 Hz playback - using %i instead", pcm_name, hw_rate);
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);
261 unsigned int buffer_time=globals.alsa_buffer_time;
262 unsigned int period_time=globals.alsa_period_time;
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);
269 long unsigned int buffer_size;
271 if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) < 0) {
272 tX_error("ALSA: failed to retreive buffer size");
276 tX_debug("ALSA: buffer size is %lu", buffer_size);
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);
283 if (snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir)<0) {
284 tX_error("ALSA: failed to retreive period size");
288 samples_per_buffer=period_size;
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);
297 if (globals.alsa_free_hwstats) {
298 snd_pcm_hw_params_free (hw_params);
301 return 0; //snd_pcm_prepare(pcm_handle);
304 int tX_audiodevice_alsa :: close()
307 snd_pcm_close(pcm_handle);
314 tX_audiodevice_alsa :: tX_audiodevice_alsa() : tX_audiodevice(),
317 void tX_audiodevice_alsa :: play(int16_t *buffer)
320 snd_pcm_sframes_t pcmreturn;
322 #ifdef USE_ALSA_MEMCPY
323 pcmreturn = snd_pcm_writei(pcm_handle, buffer, samples_per_buffer >> 1);
325 pcmreturn = snd_pcm_mmap_writei(pcm_handle, buffer, samples_per_buffer >> 1);
328 while (pcmreturn==-EPIPE) {
329 snd_pcm_prepare(pcm_handle);
331 #ifdef USE_ALSA_MEMCPY
332 pcmreturn = snd_pcm_writei(pcm_handle, buffer, samples_per_buffer >> 1);
334 pcmreturn = snd_pcm_mmap_writei(pcm_handle, buffer, samples_per_buffer >> 1);
337 if (underrun_ctr>100) {
338 tX_error("tX_audiodevice_alsa::play() more than 10 EPIPE cycles. Giving up.");
341 //tX_warning("ALSA: ** buffer underrun **");
345 printf("snd_pcm_writei says: %s.\n", strerror(-1*pcmreturn));
353 tX_jack_client* tX_jack_client::instance=NULL;
355 void tX_jack_client::init()
357 tX_jack_client *test=new tX_jack_client();
364 tX_jack_client::tX_jack_client():device(NULL),jack_shutdown(false)
366 jack_set_error_function(tX_jack_client::error);
368 if ((client=jack_client_new("terminatorX"))==0) {
369 tX_error("tX_jack_client() -> failed to connect to jackd.");
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);
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);
385 jack_activate(client);
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.");
394 if (jack_connect (client, jack_port_name(right_port), ports[1])) {
395 tX_error("tX_jack_client() failed to connect right port.");
402 tX_jack_client::~tX_jack_client()
405 if (client) jack_client_close(client);
408 void tX_jack_client::error(const char *desc)
410 tX_error("jack error: %s.", desc);
413 int tX_jack_client::srate(jack_nframes_t nframes, void *arg)
415 tX_error("tX_jack_client::srate() jack changed samplerate - ignored.");
419 void tX_jack_client::shutdown(void *arg)
421 tX_error("tX_jack_client::shutdown() jack daemon has shut down. Bad!");
422 if (instance) instance->jack_shutdown=true;
425 int tX_jack_client::process(jack_nframes_t nframes, void *arg)
428 return instance->play(nframes);
431 /* Hmm, what to do in such a case? */
435 int tX_jack_client::play(jack_nframes_t nframes)
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);
441 device->fill_frames(left, right, nframes);
443 memset(left, 0, sizeof (jack_default_audio_sample_t) * nframes);
444 memset(right, 0, sizeof (jack_default_audio_sample_t) * nframes);
450 int tX_jack_client::get_sample_rate()
452 return jack_get_sample_rate(client);
455 /* tX_audiodevice_jack */
457 tX_audiodevice_jack::tX_audiodevice_jack():tX_audiodevice()
462 int tX_audiodevice_jack::open()
464 tX_jack_client *jack_client=tX_jack_client::get_instance();
467 sample_rate=jack_client->get_sample_rate();
477 int tX_audiodevice_jack::close()
480 client->set_device(NULL);
488 void tX_audiodevice_jack::play(int16_t *buffer)
490 tX_error("tX_audiodevice_jack::play()");
493 void tX_audiodevice_jack::start()
495 overrun_buffer=new f_prec[vtt_class::samples_in_mix_buffer];
497 client->set_device(this);
498 while ((!engine->is_stopped()) && !(client->get_jack_shutdown())) {
501 client->set_device(NULL);
503 delete [] overrun_buffer;
506 void tX_audiodevice_jack::fill_frames(jack_default_audio_sample_t *left, jack_default_audio_sample_t *right, jack_nframes_t nframes)
508 unsigned int outbuffer_pos=0;
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;
518 while (outbuffer_pos<nframes) {
519 engine->render_cycle();
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;
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);
531 samples_in_overrun_buffer=0;