some more JACK code, this should be a first working version -> not yet tested
This commit is contained in:
parent
1697b8f9cd
commit
2fcb37d0e9
3 changed files with 150 additions and 21 deletions
151
linux/sound.cpp
151
linux/sound.cpp
|
@ -15,7 +15,7 @@
|
||||||
# if USE_JACK
|
# if USE_JACK
|
||||||
CSound::CSound ( void (*fpNewCallback) ( CVector<short>& psData, void* arg ),
|
CSound::CSound ( void (*fpNewCallback) ( CVector<short>& psData, void* arg ),
|
||||||
void* arg ) :
|
void* arg ) :
|
||||||
CSoundBase ( false, fpNewCallback, arg )
|
CSoundBase ( true, fpNewCallback, arg )
|
||||||
{
|
{
|
||||||
jack_status_t JackStatus;
|
jack_status_t JackStatus;
|
||||||
|
|
||||||
|
@ -29,41 +29,160 @@ CSound::CSound ( void (*fpNewCallback) ( CVector<short>& psData, void* arg ),
|
||||||
// tell the JACK server to call "process()" whenever
|
// tell the JACK server to call "process()" whenever
|
||||||
// there is work to be done
|
// there is work to be done
|
||||||
jack_set_process_callback ( pJackClient, process, this );
|
jack_set_process_callback ( pJackClient, process, this );
|
||||||
|
|
||||||
|
// TEST check sample rate, if not correct, just fire error
|
||||||
|
if ( jack_get_sample_rate ( pJackClient ) != SND_CRD_SAMPLE_RATE )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Jack server sample rate is different from "
|
||||||
|
"required one" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create four ports
|
||||||
|
input_port_left = jack_port_register ( pJackClient, "input left",
|
||||||
|
JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
|
||||||
|
input_port_right = jack_port_register ( pJackClient, "input right",
|
||||||
|
JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
|
||||||
|
|
||||||
|
output_port_left = jack_port_register ( pJackClient, "output left",
|
||||||
|
JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
|
||||||
|
output_port_right = jack_port_register ( pJackClient, "output right",
|
||||||
|
JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSound::Start()
|
||||||
|
{
|
||||||
|
const char** ports;
|
||||||
|
|
||||||
|
// tell the JACK server that we are ready to roll
|
||||||
|
if ( jack_activate ( pJackClient ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot activate client" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect the ports, note: you cannot do this before
|
||||||
|
// the client is activated, because we cannot allow
|
||||||
|
// connections to be made to clients that are not
|
||||||
|
// running
|
||||||
|
if ( ( ports = jack_get_ports ( pJackClient, NULL, NULL,
|
||||||
|
JackPortIsPhysical | JackPortIsOutput ) ) == NULL )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot find any physical capture ports" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !ports[1] )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot find enough physical capture ports" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( jack_connect ( pJackClient, ports[0], jack_port_name ( input_port_left ) ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot connect input ports" );
|
||||||
|
}
|
||||||
|
if ( jack_connect ( pJackClient, ports[1], jack_port_name ( input_port_right ) ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot connect input ports" );
|
||||||
|
}
|
||||||
|
|
||||||
|
free ( ports );
|
||||||
|
|
||||||
|
if ( ( ports = jack_get_ports ( pJackClient, NULL, NULL,
|
||||||
|
JackPortIsPhysical | JackPortIsInput ) ) == NULL )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot find any physical playback ports" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !ports[1] )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot find enough physical playback ports" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( jack_connect ( pJackClient, jack_port_name ( output_port_left ), ports[0] ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot connect output ports" );
|
||||||
|
}
|
||||||
|
if ( jack_connect ( pJackClient, jack_port_name ( output_port_right ), ports[1] ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "Cannot connect output ports" );
|
||||||
|
}
|
||||||
|
|
||||||
|
free ( ports );
|
||||||
|
|
||||||
|
// call base class
|
||||||
|
CSoundBase::Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSound::Stop()
|
||||||
|
{
|
||||||
|
// deactivate client
|
||||||
|
jack_deactivate ( pJackClient );
|
||||||
|
|
||||||
|
// call base class
|
||||||
|
CSoundBase::Stop();
|
||||||
|
}
|
||||||
|
|
||||||
int CSound::Init ( const int iNewPrefMonoBufferSize )
|
int CSound::Init ( const int iNewPrefMonoBufferSize )
|
||||||
{
|
{
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
return iNewPrefMonoBufferSize;
|
iJACKBufferSizeMono = jack_get_buffer_size ( pJackClient );
|
||||||
|
|
||||||
|
// init base clasee
|
||||||
|
CSoundBase::Init ( iJACKBufferSizeMono );
|
||||||
|
|
||||||
|
// set internal buffer size value and calculate stereo buffer size
|
||||||
|
iJACKBufferSizeStero = 2 * iJACKBufferSizeMono;
|
||||||
|
|
||||||
|
// create memory for intermediate audio buffer
|
||||||
|
vecsTmpAudioSndCrdStereo.Init ( iJACKBufferSizeStero );
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
return iJACKBufferSizeMono;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSound::Read ( CVector<short>& psData )
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CSound::Write ( CVector<short>& psData )
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// JACK callbacks --------------------------------------------------------------
|
// JACK callbacks --------------------------------------------------------------
|
||||||
int CSound::process ( jack_nframes_t nframes, void* arg )
|
int CSound::process ( jack_nframes_t nframes, void* arg )
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
CSound* pSound = reinterpret_cast<CSound*> ( arg );
|
CSound* pSound = reinterpret_cast<CSound*> ( arg );
|
||||||
|
|
||||||
|
// get input data
|
||||||
|
jack_default_audio_sample_t* in_left =
|
||||||
|
(jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->input_port_left, nframes );
|
||||||
|
|
||||||
|
jack_default_audio_sample_t* in_right =
|
||||||
|
(jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->input_port_right, nframes );
|
||||||
|
|
||||||
|
// copy input data
|
||||||
|
for ( i = 0; i < pSound->iJACKBufferSizeMono; i++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO better conversion from float to short
|
||||||
|
|
||||||
|
pSound->vecsTmpAudioSndCrdStereo[2 * i] = (short) in_left[i];
|
||||||
|
pSound->vecsTmpAudioSndCrdStereo[2 * i + 1] = (short) in_right[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// call processing callback function
|
||||||
|
pSound->Callback ( pSound->vecsTmpAudioSndCrdStereo );
|
||||||
|
|
||||||
|
// put output data
|
||||||
|
jack_default_audio_sample_t* out_left =
|
||||||
|
(jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->output_port_left, nframes );
|
||||||
|
|
||||||
|
jack_default_audio_sample_t* out_right =
|
||||||
|
(jack_default_audio_sample_t*) jack_port_get_buffer ( pSound->output_port_right, nframes );
|
||||||
|
|
||||||
|
// copy output data
|
||||||
|
for ( i = 0; i < pSound->iJACKBufferSizeMono; i++ )
|
||||||
|
{
|
||||||
|
out_left[i] = pSound->vecsTmpAudioSndCrdStereo[2 * i];
|
||||||
|
out_right[i] = pSound->vecsTmpAudioSndCrdStereo[2 * i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
return 0; // zero on success, non-zero on error
|
return 0; // zero on success, non-zero on error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# else
|
# else
|
||||||
// Wave in *********************************************************************
|
// Wave in *********************************************************************
|
||||||
void CSound::InitRecording()
|
void CSound::InitRecording()
|
||||||
|
|
|
@ -55,20 +55,30 @@ public:
|
||||||
CSound ( void (*fpNewCallback) ( CVector<short>& psData, void* arg ), void* arg );
|
CSound ( void (*fpNewCallback) ( CVector<short>& psData, void* arg ), void* arg );
|
||||||
virtual ~CSound() {}
|
virtual ~CSound() {}
|
||||||
|
|
||||||
|
virtual int Init ( const int iNewPrefMonoBufferSize );
|
||||||
|
virtual void Start();
|
||||||
|
virtual void Stop();
|
||||||
|
|
||||||
// not implemented yet, always return one device and default string
|
// not implemented yet, always return one device and default string
|
||||||
int GetNumDev() { return 1; }
|
int GetNumDev() { return 1; }
|
||||||
std::string GetDeviceName ( const int iDiD ) { return "wave mapper"; }
|
std::string GetDeviceName ( const int iDiD ) { return "wave mapper"; }
|
||||||
std::string SetDev ( const int iNewDev ) { return ""; } // dummy
|
std::string SetDev ( const int iNewDev ) { return ""; } // dummy
|
||||||
int GetDev() { return 0; }
|
int GetDev() { return 0; }
|
||||||
|
|
||||||
virtual int Init ( const int iNewPrefMonoBufferSize );
|
// these variables should be protected but cannot since we want
|
||||||
virtual bool Read ( CVector<short>& psData );
|
// to access them from the callback function
|
||||||
virtual bool Write ( CVector<short>& psData );
|
CVector<short> vecsTmpAudioSndCrdStereo;
|
||||||
|
int iJACKBufferSizeMono;
|
||||||
|
int iJACKBufferSizeStero;
|
||||||
|
|
||||||
|
jack_port_t* input_port_left;
|
||||||
|
jack_port_t* input_port_right;
|
||||||
|
jack_port_t* output_port_left;
|
||||||
|
jack_port_t* output_port_right;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// callback
|
// callback
|
||||||
static int process ( jack_nframes_t nframes, void* arg );
|
static int process ( jack_nframes_t nframes, void* arg );
|
||||||
|
|
||||||
jack_client_t* pJackClient;
|
jack_client_t* pJackClient;
|
||||||
};
|
};
|
||||||
# else
|
# else
|
||||||
|
|
|
@ -489,7 +489,7 @@ void CSound::bufferSwitch ( long index, ASIOBool processNow )
|
||||||
}
|
}
|
||||||
|
|
||||||
// call processing callback function
|
// call processing callback function
|
||||||
pSound->Callback( vecsTmpAudioSndCrdStereo );
|
pSound->Callback ( vecsTmpAudioSndCrdStereo );
|
||||||
|
|
||||||
// perform the processing for input and output
|
// perform the processing for input and output
|
||||||
for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) // stereo
|
for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) // stereo
|
||||||
|
|
Loading…
Reference in a new issue