~ubuntu-branches/debian/sid/terminatorx/sid

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