/* MuSE - Multiple Streaming Engine * SoundDevice class interfacing Portaudio PABLIO library * Copyright (C) 2004 Denis Roio aka jaromil * * This source code is free software; you can redistribute it and/or * modify it under the terms of the GNU Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * Please refer to the GNU Public License for more details. * * You should have received a copy of the GNU Public License along with * this source code; if not, write to: * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. "$Id: dev_sound.cpp,v 1.5 2004/12/15 18:18:06 jaromil Exp $" */ #include #include #include #include #define PA_SAMPLE_TYPE paInt16 #define PA_SAMPLES_PER_FRAME 2 #define PA_MAX_FRAMES 4096 #define PA_NUM_SECONDS 5 #ifdef HAVE_JACK int dev_jack_process(jack_nframes_t nframes, void *arg) { jack_nframes_t opframes; SoundDevice *dev = (SoundDevice*)arg; if(!dev->jack) return 0; // just return // take output from pipe and send it to jack dev->jack_out_buf = (jack_default_audio_sample_t*) jack_port_get_buffer(dev->jack_out_port,nframes); opframes = dev->jack_out_pipe->read (nframes * sizeof(float) * 2 , dev->jack_out_buf); // take input from jack and send it in pipe dev->jack_in_buf = (jack_default_audio_sample_t*) jack_port_get_buffer(dev->jack_in_port,nframes); dev->jack_in_pipe->write // does the float2int conversion in one pass (nframes * sizeof(float) * 2 , dev->jack_in_buf); return 0; } void dev_jack_shutdown(void *arg) { SoundDevice *dev = (SoundDevice*)arg; // close the jack channels dev->jack = false; jack_port_unregister(dev->jack_client, dev->jack_in_port); jack_port_unregister(dev->jack_client, dev->jack_out_port); jack_deactivate(dev->jack_client); delete dev->jack_in_pipe; delete dev->jack_out_pipe; } #endif SoundDevice::SoundDevice() { aInStream = NULL; aOutStream = NULL; jack = false; jack_in = false; jack_out = false; } SoundDevice::~SoundDevice() { close(); } bool SoundDevice::pablio_input(bool state) { if(state && !aInStream) { err = OpenAudioStream( &aInStream, SAMPLE_RATE, PA_SAMPLE_TYPE, (PABLIO_READ | PABLIO_STEREO) ); if( err != paNoError) { Pa_Terminate(); error("error opening input sound device: %s",Pa_GetErrorText( err ) ); return false; } else info_input = Pa_GetDeviceInfo( Pa_GetDefaultInputDeviceID() ); } else if(!state && aInStream) { CloseAudioStream(aInStream); aInStream = NULL; info_input = NULL; } return true; } bool SoundDevice::input(bool state) { bool res = false; if(jack) return true; if(!res) res = pablio_input(state); return res; } bool SoundDevice::pablio_output(bool state) { if(state && !aOutStream) { err = OpenAudioStream( &aOutStream, SAMPLE_RATE, PA_SAMPLE_TYPE, (PABLIO_WRITE | PABLIO_STEREO) ); if( err != paNoError) { Pa_Terminate(); error("error opening output sound device: %s",Pa_GetErrorText( err ) ); return false; } else info_output = Pa_GetDeviceInfo( Pa_GetDefaultOutputDeviceID() ); } else if(!state && aOutStream) { CloseAudioStream(aOutStream); aOutStream = NULL; info_output = NULL; } return true; } bool SoundDevice::output(bool state) { bool res = false; if(jack) return true; if(!res) res = pablio_output(state); return res; } bool SoundDevice::open(bool read, bool write) { // notice("detecting sound device"); #ifdef HAVE_JACK // we try to open up a jack client jack_sample_size = sizeof(jack_default_audio_sample_t); if(!jack) // check if it is not allready on if( (jack_client = jack_client_new("MuSE")) !=0 ) { notice("jack audio daemon detected"); act("hooking in/out sound channels"); warning("this feature is still experimental and won't work!"); warning("you need to stop jack and free the audio card"); jack = true; jack_samplerate = jack_get_sample_rate(jack_client); jack_set_process_callback(jack_client, dev_jack_process, this); jack_on_shutdown(jack_client,dev_jack_shutdown,this); jack_in_pipe = new Pipe(); jack_in_pipe->set_output_type("copy_float_to_int16"); jack_in_pipe->set_block(false,true); jack_out_pipe = new Pipe(); jack_out_pipe->set_input_type("copy_int16_to_float"); jack_in_pipe->set_block(true,false); // open the jack input channel jack_in_port = jack_port_register(jack_client, "capture", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); // open the jack output channel jack_out_port = jack_port_register(jack_client, "playback", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); jack_activate(jack_client); return true; } #endif if( ! output(write) ) return false; if(info_output) func("output device: %s",info_output->name); else error("output device not available"); if( ! input(read) ) return false; if(info_input) func("input device: %s",info_input->name); else error("input device not available"); return true; } void SoundDevice::close() { if(aInStream) CloseAudioStream( aInStream); aInStream = NULL; if(aOutStream) CloseAudioStream( aOutStream); aOutStream = NULL; } int SoundDevice::read(void *buf, int len) { // len is in samples: 4*2 32bit stereo int res = -1; if(jack) { res = jack_in_pipe->read(len<<1,buf); } else if(aInStream) { // pablio // takes number of left and right frames (stereo / 2) res = ReadAudioStream( aInStream, buf, len); } return res; } int SoundDevice::write(void *buf, int len) { // len is in samples, for bytes must *2 (16bit) int res = -1; if(jack) { // jack audio daemon res = jack_out_pipe->write(len<<1,buf); } else if(aOutStream) { // pablio // takes number of left and right frames (stereo / 2) res = WriteAudioStream( aOutStream, buf, len>>1); } return res; }