mirror of
				https://github.com/ElvishArtisan/rivendell.git
				synced 2025-11-04 08:04:12 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1693 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1693 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// cae_jack.cpp
 | 
						|
//
 | 
						|
// The JACK Driver for the Core Audio Engine component of Rivendell
 | 
						|
//
 | 
						|
//   (C) Copyright 2002-2015 Fred Gleason <fredg@paravelsystems.com>
 | 
						|
//
 | 
						|
//   This program is free software; you can redistribute it and/or modify
 | 
						|
//   it under the terms of the GNU General Public License version 2 as
 | 
						|
//   published by the Free Software Foundation.
 | 
						|
//
 | 
						|
//   This program 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.  See the
 | 
						|
//   GNU General Public License for more details.
 | 
						|
//
 | 
						|
//   You should have received a copy of the GNU General Public
 | 
						|
//   License along with this program; if not, write to the Free Software
 | 
						|
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
//
 | 
						|
 | 
						|
#include <math.h>
 | 
						|
 | 
						|
#include <samplerate.h>
 | 
						|
 | 
						|
#include <qsignalmapper.h>
 | 
						|
 | 
						|
#include <rd.h>
 | 
						|
#include <rddatedecode.h>
 | 
						|
#include <rddb.h>
 | 
						|
#include <rdescape_string.h>
 | 
						|
#include <rdringbuffer.h>
 | 
						|
#include <rdprofile.h>
 | 
						|
#include <rdmeteraverage.h>
 | 
						|
 | 
						|
#include <cae.h>
 | 
						|
 | 
						|
#ifdef JACK
 | 
						|
//
 | 
						|
// Callback Variables
 | 
						|
//
 | 
						|
jack_client_t *jack_client;
 | 
						|
RDMeterAverage *jack_input_meter[RD_MAX_PORTS][2];
 | 
						|
RDMeterAverage *jack_output_meter[RD_MAX_PORTS][2];
 | 
						|
RDMeterAverage *jack_stream_output_meter[RD_MAX_STREAMS][2];
 | 
						|
volatile jack_default_audio_sample_t 
 | 
						|
  jack_input_volume[RD_MAX_PORTS];
 | 
						|
volatile jack_default_audio_sample_t 
 | 
						|
  jack_output_volume[RD_MAX_PORTS][RD_MAX_STREAMS];
 | 
						|
volatile jack_default_audio_sample_t
 | 
						|
  jack_passthrough_volume[RD_MAX_PORTS][RD_MAX_PORTS];
 | 
						|
volatile jack_default_audio_sample_t jack_input_vox[RD_MAX_PORTS];
 | 
						|
jack_port_t *jack_input_port[RD_MAX_PORTS][2];
 | 
						|
jack_port_t *jack_output_port[RD_MAX_PORTS][2];
 | 
						|
volatile int jack_input_channels[RD_MAX_PORTS];
 | 
						|
volatile int jack_output_channels[RD_MAX_STREAMS];
 | 
						|
volatile jack_default_audio_sample_t *jack_input_buffer[RD_MAX_PORTS][2];
 | 
						|
volatile jack_default_audio_sample_t *jack_output_buffer[RD_MAX_PORTS][2];
 | 
						|
RDRingBuffer *jack_play_ring[RD_MAX_STREAMS];
 | 
						|
RDRingBuffer *jack_record_ring[RD_MAX_PORTS];
 | 
						|
volatile bool jack_playing[RD_MAX_STREAMS];
 | 
						|
volatile bool jack_stopping[RD_MAX_STREAMS];
 | 
						|
volatile bool jack_eof[RD_MAX_STREAMS];
 | 
						|
volatile bool jack_recording[RD_MAX_PORTS];
 | 
						|
volatile bool jack_ready[RD_MAX_PORTS];
 | 
						|
volatile int jack_output_pos[RD_MAX_STREAMS];
 | 
						|
volatile unsigned jack_output_sample_rate[RD_MAX_STREAMS];
 | 
						|
volatile unsigned jack_sample_rate;
 | 
						|
int jack_input_mode[RD_MAX_CARDS][RD_MAX_PORTS];
 | 
						|
int jack_card_process;  // local copy of object member jack_card, for use by the callback process.
 | 
						|
 | 
						|
 | 
						|
//
 | 
						|
// Callback Buffers
 | 
						|
//
 | 
						|
jack_default_audio_sample_t jack_callback_buffer[RINGBUFFER_SIZE];
 | 
						|
 | 
						|
int JackProcess(jack_nframes_t nframes, void *arg)
 | 
						|
{
 | 
						|
  unsigned n=0;
 | 
						|
  jack_default_audio_sample_t in_meter[2];
 | 
						|
  jack_default_audio_sample_t out_meter[2];
 | 
						|
  jack_default_audio_sample_t stream_out_meter;
 | 
						|
 | 
						|
  //
 | 
						|
  // Ensure Buffers are Valid
 | 
						|
  //
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    for(int j=0;j<2;j++) {
 | 
						|
      if(jack_input_port[i][j]!=NULL) {
 | 
						|
	jack_input_buffer[i][j]=(jack_default_audio_sample_t *)
 | 
						|
	  jack_port_get_buffer(jack_input_port[i][j],nframes);
 | 
						|
      }
 | 
						|
      if(jack_output_port[i][j]!=NULL) {
 | 
						|
	jack_output_buffer[i][j]=(jack_default_audio_sample_t *)
 | 
						|
	  jack_port_get_buffer(jack_output_port[i][j],nframes);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Zero Output Ports
 | 
						|
  //
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    for(int j=0;j<2;j++) {
 | 
						|
      if(jack_output_port[i][j]!=NULL) {
 | 
						|
	for(unsigned k=0;k<nframes;k++) {
 | 
						|
	  jack_output_buffer[i][j][k]=0.0;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    } 
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Process Passthroughs
 | 
						|
  //
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    for(int j=0;j<RD_MAX_PORTS;j++) {
 | 
						|
      if(jack_passthrough_volume[i][j]>0.0) {
 | 
						|
	for(int k=0;k<2;k++) {
 | 
						|
	  if((jack_output_port[j][k]!=NULL)&&(jack_input_port[i][k]!=NULL)) {
 | 
						|
	    for(unsigned l=0;l<nframes;l++) {
 | 
						|
	      jack_output_buffer[j][k][l]+=
 | 
						|
		jack_input_buffer[i][k][l]*jack_passthrough_volume[i][j];
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Process Input Streams
 | 
						|
  //
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    if(jack_input_port[i][0]!=NULL) {
 | 
						|
      if(jack_recording[i]) {
 | 
						|
	switch(jack_input_channels[i]) {
 | 
						|
	case 1: // mono
 | 
						|
	  for(unsigned j=0;j<nframes;j++) {
 | 
						|
	    switch(jack_input_mode[jack_card_process][i]) {
 | 
						|
	    case 3: // R only
 | 
						|
	      jack_callback_buffer[j]=jack_input_volume[i]*
 | 
						|
		jack_input_buffer[i][1][j];
 | 
						|
	      break;
 | 
						|
	    case 2: // L only
 | 
						|
	      jack_callback_buffer[j]=jack_input_volume[i]*
 | 
						|
		jack_input_buffer[i][0][j];
 | 
						|
	      break;
 | 
						|
	    case 1: // swap, sum R+L
 | 
						|
	    case 0: // normal, sum L+R
 | 
						|
	    default:
 | 
						|
	      jack_callback_buffer[j]=jack_input_volume[i]*
 | 
						|
		(jack_input_buffer[i][0][j]+jack_input_buffer[i][1][j]);
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	  } // for nframes
 | 
						|
	  n=jack_record_ring[i]->
 | 
						|
	    write((char *)jack_callback_buffer,
 | 
						|
		  nframes*sizeof(jack_default_audio_sample_t))/
 | 
						|
	    sizeof(jack_default_audio_sample_t);
 | 
						|
	  break;
 | 
						|
 | 
						|
	case 2: // stereo
 | 
						|
	  for(unsigned j=0;j<nframes;j++) {
 | 
						|
	    switch(jack_input_mode[jack_card_process][i]) {
 | 
						|
	    case 3: // R only
 | 
						|
	      memset(&jack_callback_buffer[2*j],0,
 | 
						|
		     sizeof(jack_input_buffer[i][0][j]));
 | 
						|
	      jack_callback_buffer[2*j+1]=jack_input_volume[i]*
 | 
						|
		jack_input_buffer[i][1][j];
 | 
						|
	      break;
 | 
						|
	    case 2: // L only
 | 
						|
	      jack_callback_buffer[2*j]=jack_input_volume[i]*
 | 
						|
		jack_input_buffer[i][0][j];
 | 
						|
	      memset(&jack_callback_buffer[2*j+1],0,
 | 
						|
		     sizeof(jack_input_buffer[i][1][j]));
 | 
						|
	      break;
 | 
						|
	    case 1: // swap
 | 
						|
	      jack_callback_buffer[2*j]=jack_input_volume[i]*
 | 
						|
		jack_input_buffer[i][1][j];
 | 
						|
	      jack_callback_buffer[2*j+1]=jack_input_volume[i]*
 | 
						|
		jack_input_buffer[i][0][j];
 | 
						|
	      break;
 | 
						|
	    case 0: // normal
 | 
						|
	    default:
 | 
						|
	      jack_callback_buffer[2*j]=jack_input_volume[i]*
 | 
						|
		jack_input_buffer[i][0][j];
 | 
						|
	      jack_callback_buffer[2*j+1]=jack_input_volume[i]*
 | 
						|
		jack_input_buffer[i][1][j];
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	  } // for nframes
 | 
						|
	  n=jack_record_ring[i]->
 | 
						|
	    write((char *)jack_callback_buffer,
 | 
						|
		  2*nframes*sizeof(jack_default_audio_sample_t))/
 | 
						|
	    (2*sizeof(jack_default_audio_sample_t));
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Process Output Streams
 | 
						|
  //
 | 
						|
  for(int i=0;i<RD_MAX_STREAMS;i++) {
 | 
						|
    if(jack_playing[i]) {
 | 
						|
      switch(jack_output_channels[i]) {
 | 
						|
      case 1:
 | 
						|
	n=jack_play_ring[i]->
 | 
						|
	  read((char *)jack_callback_buffer,
 | 
						|
	       nframes*sizeof(jack_default_audio_sample_t))/
 | 
						|
	  sizeof(jack_default_audio_sample_t);
 | 
						|
	stream_out_meter=0.0;
 | 
						|
	for(unsigned j=0;j<n;j++) {  // Stream Output Meters
 | 
						|
	  if(fabsf(jack_callback_buffer[j])>stream_out_meter) {
 | 
						|
	    stream_out_meter=fabsf(jack_callback_buffer[j]);
 | 
						|
	  }
 | 
						|
	}
 | 
						|
	jack_stream_output_meter[i][0]->addValue(stream_out_meter);
 | 
						|
	jack_stream_output_meter[i][1]->addValue(stream_out_meter);
 | 
						|
	break;
 | 
						|
 | 
						|
      case 2:
 | 
						|
	n=jack_play_ring[i]->
 | 
						|
	  read((char *)jack_callback_buffer,
 | 
						|
	       2*nframes*sizeof(jack_default_audio_sample_t))/
 | 
						|
	  (2*sizeof(jack_default_audio_sample_t));
 | 
						|
	for(unsigned j=0;j<2;j++) {  // Stream Output Meters
 | 
						|
	  stream_out_meter=0.0;
 | 
						|
	  for(unsigned k=0;k<n;k+=2) {
 | 
						|
	    if(fabsf(jack_callback_buffer[k+j])>stream_out_meter) {
 | 
						|
	      stream_out_meter=fabsf(jack_callback_buffer[k+j]);
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	  jack_stream_output_meter[i][j]->addValue(stream_out_meter);
 | 
						|
	}
 | 
						|
	break;
 | 
						|
      }
 | 
						|
      for(int j=0;j<RD_MAX_PORTS;j++) {
 | 
						|
	if(jack_output_port[j][0]!=NULL) {
 | 
						|
	  if(jack_output_volume[j][i]>0.0) {
 | 
						|
	    switch(jack_output_channels[i]) {
 | 
						|
	    case 1:
 | 
						|
	      for(unsigned k=0;k<n;k++) {
 | 
						|
		jack_output_buffer[j][0][k]=
 | 
						|
		  jack_output_buffer[j][0][k]+jack_output_volume[j][i]*
 | 
						|
		  jack_callback_buffer[k];
 | 
						|
		jack_output_buffer[j][1][k]=
 | 
						|
		  jack_output_buffer[j][1][k]+jack_output_volume[j][i]*
 | 
						|
		  jack_callback_buffer[k];
 | 
						|
	      }
 | 
						|
	      if(n!=nframes && jack_eof[i]) {
 | 
						|
		jack_stopping[i]=true;
 | 
						|
		jack_playing[i]=false;
 | 
						|
	      }
 | 
						|
	      break;
 | 
						|
 | 
						|
	    case 2:
 | 
						|
	      for(unsigned k=0;k<n;k++) {
 | 
						|
		jack_output_buffer[j][0][k]=
 | 
						|
		  jack_output_buffer[j][0][k]+jack_output_volume[j][i]*
 | 
						|
		  jack_callback_buffer[k*2];
 | 
						|
		jack_output_buffer[j][1][k]=
 | 
						|
		  jack_output_buffer[j][1][k]+jack_output_volume[j][i]*
 | 
						|
		  jack_callback_buffer[k*2+1];
 | 
						|
	      }
 | 
						|
	      if(n!=nframes && jack_eof[i]) {
 | 
						|
		jack_stopping[i]=true;
 | 
						|
		jack_playing[i]=false;
 | 
						|
	      }
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
      double ratio=(double)jack_output_sample_rate[i]/(double)jack_sample_rate;
 | 
						|
      jack_output_pos[i]+=(int)(((double)n*ratio)+0.5);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Process Meters
 | 
						|
  //
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    if(jack_input_port[i][0]!=NULL) {
 | 
						|
      // input meters (taking input mode into account)
 | 
						|
      in_meter[0]=0.0;
 | 
						|
      in_meter[1]=0.0;
 | 
						|
      for(unsigned k=0;k<nframes;k++) {
 | 
						|
	switch(jack_input_mode[jack_card_process][i]) {
 | 
						|
	case 3: // R only
 | 
						|
	  if(jack_input_buffer[i][1][k]>in_meter[1]) 
 | 
						|
	    in_meter[1]=jack_input_buffer[i][1][k];
 | 
						|
	  break;
 | 
						|
	case 2: // L only
 | 
						|
	  if(jack_input_buffer[i][0][k]>in_meter[0]) 
 | 
						|
	    in_meter[0]=jack_input_buffer[i][0][k];
 | 
						|
	  break;
 | 
						|
	case 1: // swap
 | 
						|
	  if(jack_input_buffer[i][0][k]>in_meter[1]) 
 | 
						|
	    in_meter[1]=jack_input_buffer[i][0][k];
 | 
						|
	  if(jack_input_buffer[i][1][k]>in_meter[0]) 
 | 
						|
	    in_meter[0]=jack_input_buffer[i][1][k];
 | 
						|
	  break;
 | 
						|
	case 0: // normal
 | 
						|
	default:
 | 
						|
	  if(jack_input_buffer[i][0][k]>in_meter[0]) 
 | 
						|
	    in_meter[0]=jack_input_buffer[i][0][k];
 | 
						|
	  if(jack_input_buffer[i][1][k]>in_meter[1]) 
 | 
						|
	    in_meter[1]=jack_input_buffer[i][1][k];
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      } // for nframes
 | 
						|
      jack_input_meter[i][0]->addValue(in_meter[0]);
 | 
						|
      jack_input_meter[i][1]->addValue(in_meter[1]);
 | 
						|
    }
 | 
						|
    if(jack_output_port[i][0]!=NULL) {
 | 
						|
      // output meters
 | 
						|
      for(int j=0;j<2;j++) {
 | 
						|
	out_meter[j]=0.0;
 | 
						|
	for(unsigned k=0;k<nframes;k++) {
 | 
						|
	  if(jack_output_buffer[i][j][k]>out_meter[j]) 
 | 
						|
	    out_meter[j]=jack_output_buffer[i][j][k];
 | 
						|
	}
 | 
						|
	jack_output_meter[i][j]->addValue(out_meter[j]);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } // for RD_MAX_PORTS
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int JackSampleRate(jack_nframes_t nframes, void *arg)
 | 
						|
{
 | 
						|
  jack_sample_rate=nframes;
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void JackError(const char *desc)
 | 
						|
{
 | 
						|
  fprintf(stderr,"caed: Jack error: %s\n",desc);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void JackShutdown(void *arg)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void JackInitCallback()
 | 
						|
{
 | 
						|
  int avg_periods=(int)(330.0*jack_get_sample_rate(jack_client)/
 | 
						|
			(1000.0*jack_get_buffer_size(jack_client)));
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    jack_recording[i]=false;
 | 
						|
    jack_ready[i]=false;
 | 
						|
    jack_input_volume[i]=1.0;
 | 
						|
    jack_input_vox[i]=0.0;
 | 
						|
    for(int j=0;j<2;j++) {
 | 
						|
      jack_input_meter[i][j]=new RDMeterAverage(avg_periods);
 | 
						|
      jack_output_meter[i][j]=new RDMeterAverage(avg_periods);
 | 
						|
      jack_input_buffer[i][j]=NULL;
 | 
						|
      jack_output_buffer[i][j]=NULL;
 | 
						|
    }
 | 
						|
    for(int j=0;j<RD_MAX_STREAMS;j++) {
 | 
						|
      jack_output_volume[i][j]=1.0;
 | 
						|
    }
 | 
						|
    for(int j=0;j<RD_MAX_PORTS;j++) {
 | 
						|
      jack_passthrough_volume[i][j]=0.0;
 | 
						|
    }
 | 
						|
    jack_record_ring[i]=NULL;
 | 
						|
  }
 | 
						|
  for(int i=0;i<RD_MAX_STREAMS;i++) {
 | 
						|
    jack_play_ring[i]=NULL;
 | 
						|
    jack_playing[i]=false;
 | 
						|
    for(int j=0;j<2;j++) {
 | 
						|
      jack_stream_output_meter[i][j]=new RDMeterAverage(avg_periods);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
#endif  // JACK
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackStopTimerData(int stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  jackStopPlayback(jack_card,stream);
 | 
						|
  statePlayUpdate(jack_card,stream,2);
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackFadeTimerData(int stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  int level;
 | 
						|
  if(!jack_fade_up[stream]) {
 | 
						|
    level=jack_output_volume_db[jack_fade_port[stream]][stream]-
 | 
						|
      jack_fade_increment[stream];
 | 
						|
    if(level<=jack_fade_volume_db[stream]) {
 | 
						|
      level=jack_fade_volume_db[stream];
 | 
						|
      jack_fade_timer[stream]->stop();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    level=jack_output_volume_db[jack_fade_port[stream]][stream]+
 | 
						|
      jack_fade_increment[stream];
 | 
						|
    if(level>=jack_fade_volume_db[stream]) {
 | 
						|
      level=jack_fade_volume_db[stream];
 | 
						|
      jack_fade_timer[stream]->stop();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  jackSetOutputVolume(jack_card,stream,jack_fade_port[stream],level);
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackRecordTimerData(int stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  jackStopRecord(jack_card,stream);
 | 
						|
  stateRecordUpdate(jack_card,stream,2);
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackClientStartData()
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  QString sql=QString("select ")+
 | 
						|
    "DESCRIPTION,"+   // 00
 | 
						|
    "COMMAND_LINE "+  // 01
 | 
						|
    "from JACK_CLIENTS where "+
 | 
						|
    "STATION_NAME=\""+RDEscapeString(rd_config->stationName())+"\"";
 | 
						|
  RDSqlQuery *q=new RDSqlQuery(sql);
 | 
						|
  while(q->next()) {
 | 
						|
    QString cmd=RDDateDecode(q->value(1).toString(),QDate::currentDate(),
 | 
						|
			     cae_station,rd_config,
 | 
						|
			     rd_config->provisioningServiceName(rd_config->stationName()));
 | 
						|
    QStringList fields=cmd.split(" ");
 | 
						|
    jack_clients.push_back(new Q3Process(fields,this));
 | 
						|
    if(jack_clients.back()->start()) {
 | 
						|
      rd_config->log("caed",RDConfig::LogDebug,"started JACK Client \""+
 | 
						|
	      q->value(0).toString()+"\"");
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      rd_config->log("caed",RDConfig::LogWarning,"failed to start JACK Client \""+
 | 
						|
	      q->value(0).toString()+"\" ["+
 | 
						|
	      q->value(1).toString()+"]");
 | 
						|
    }
 | 
						|
    sleep(1);
 | 
						|
  }
 | 
						|
  delete q;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackInit(RDStation *station)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  jack_options_t jackopts=JackNullOption;
 | 
						|
  jack_status_t jackstat=JackFailure;
 | 
						|
  RDConfig::LogPriority prio=RDConfig::LogDebug;
 | 
						|
 | 
						|
  jack_connected=false;
 | 
						|
  jack_activated=false;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get Next Available Card Number
 | 
						|
  //
 | 
						|
  for(jack_card=0;jack_card<RD_MAX_CARDS;jack_card++) {
 | 
						|
    if(cae_driver[jack_card]==RDStation::None) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if(jack_card==RD_MAX_CARDS) {
 | 
						|
    rd_config->log("caed",RDConfig::LogInfo,"no more RD cards available");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  QString name=QString().sprintf("rivendell_%d",jack_card);
 | 
						|
 | 
						|
  //
 | 
						|
  // Start Jack Server
 | 
						|
  //
 | 
						|
  if(station->startJack()) {
 | 
						|
    QStringList fields=station->jackCommandLine().split(" ");
 | 
						|
    Q3Process *proc=new Q3Process(fields,this);
 | 
						|
    if(proc->start()) {
 | 
						|
      rd_config->log("caed",RDConfig::LogDebug,"JACK server started");
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      rd_config->log("caed",RDConfig::LogErr,"failed to start JACK server");
 | 
						|
    }
 | 
						|
    sleep(1);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Attempt to Connect to Jack Server
 | 
						|
  //
 | 
						|
  jackopts=JackNoStartServer;
 | 
						|
  if(station->jackServerName().isEmpty()) {
 | 
						|
    jack_client=jack_client_open(name,jackopts,&jackstat);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    jack_client=jack_client_open(name,jackopts,&jackstat,
 | 
						|
				 (const char *)station->jackServerName());
 | 
						|
  }
 | 
						|
  if(jack_client==NULL) {
 | 
						|
    if((jackstat&JackInvalidOption)!=0) {
 | 
						|
      fprintf (stderr, "invalid or unsupported JACK option\n");
 | 
						|
      rd_config->log("caed",prio,"invalid or unsupported JACK option");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackServerError)!=0) {
 | 
						|
      fprintf (stderr, "communication error with the JACK server\n");
 | 
						|
      rd_config->log("caed",prio,"communication error with the JACK server");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackNoSuchClient)!=0) {
 | 
						|
      fprintf (stderr, "requested JACK client does not exist\n");
 | 
						|
      rd_config->log("caed",prio,"requested JACK client does not exist");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackLoadFailure)!=0) {
 | 
						|
      fprintf (stderr, "unable to load internal JACK client\n");
 | 
						|
      rd_config->log("caed",prio,"unable to load internal JACK client");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackInitFailure)!=0) {
 | 
						|
      fprintf (stderr, "unable to initialize JACK client\n");
 | 
						|
      rd_config->log("caed",prio,"unable to initialize JACK client");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackShmFailure)!=0) {
 | 
						|
      fprintf (stderr, "unable to access JACK shared memory\n");
 | 
						|
      rd_config->log("caed",prio,"unable to access JACK shared memory");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackVersionError)!=0) {
 | 
						|
      fprintf (stderr, "JACK protocol version mismatch\n");
 | 
						|
      rd_config->log("caed",prio,"JACK protocol version mismatch");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackServerStarted)!=0) {
 | 
						|
      fprintf (stderr, "JACK server started\n");
 | 
						|
      rd_config->log("caed",prio,"JACK server started");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackServerFailed)!=0) {
 | 
						|
      fprintf (stderr, "unable to communication with JACK server\n");
 | 
						|
      rd_config->log("caed",prio,"unable to communicate with JACK server");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackNameNotUnique)!=0) {
 | 
						|
      fprintf (stderr, "JACK client name not unique\n");
 | 
						|
      rd_config->log("caed",prio,"JACK client name not unique");
 | 
						|
    }
 | 
						|
 | 
						|
    if((jackstat&JackFailure)!=0) {
 | 
						|
      fprintf (stderr, "JACK general failure\n");
 | 
						|
      rd_config->log("caed",prio,"JACK general failure");
 | 
						|
    }
 | 
						|
    jack_card=-1;
 | 
						|
    fprintf (stderr, "no connection to JACK server\n");
 | 
						|
    rd_config->log("caed",prio,"no connection to JACK server");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  jack_connected=true;
 | 
						|
  jack_set_process_callback(jack_client,JackProcess,0);
 | 
						|
  jack_set_sample_rate_callback(jack_client,JackSampleRate,0);
 | 
						|
  //jack_set_port_connect_callback(jack_client,JackPortConnectCB,this);
 | 
						|
#ifdef HAVE_JACK_INFO_SHUTDOWN
 | 
						|
  jack_on_info_shutdown(jack_client,JackInfoShutdown,0);
 | 
						|
#else
 | 
						|
  jack_on_shutdown(jack_client,JackShutdown,0);
 | 
						|
#endif  // HAVE_JACK_INFO_SHUTDOWN
 | 
						|
  rd_config->log("caed",RDConfig::LogDebug,"connected to JACK server");
 | 
						|
 | 
						|
  //
 | 
						|
  // Start JACK Clients
 | 
						|
  //
 | 
						|
  jack_client_start_timer=new QTimer(this);
 | 
						|
  connect(jack_client_start_timer,SIGNAL(timeout()),
 | 
						|
	  this,SLOT(jackClientStartData()));
 | 
						|
  jack_client_start_timer->start(6000,true);
 | 
						|
 | 
						|
  //
 | 
						|
  // Tell the database about us
 | 
						|
  //
 | 
						|
  if(jack_connected) {
 | 
						|
    station->setCardDriver(jack_card,RDStation::Jack);
 | 
						|
    station->setCardName(jack_card,"JACK Audio Connection Kit");
 | 
						|
    station->setCardInputs(jack_card,RD_MAX_PORTS);
 | 
						|
    station->setCardOutputs(jack_card,RD_MAX_PORTS);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize Data Structures
 | 
						|
  //
 | 
						|
  for(int i=0;i<RD_MAX_STREAMS;i++) {
 | 
						|
    for(int j=0;j<RD_MAX_PORTS;j++) {
 | 
						|
      jack_output_volume_db[j][i]=0; 
 | 
						|
      jack_samples_recorded[i]=0;
 | 
						|
    }
 | 
						|
    jack_st_conv[i]=NULL;
 | 
						|
  }
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    jack_input_volume_db[i]=0;
 | 
						|
    for(int j=0;j<RD_MAX_PORTS;j++) {
 | 
						|
      jack_passthrough_volume_db[j][i]=-10000;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  for(int i=0;i<RD_MAX_CARDS;i++) {
 | 
						|
    for(int j=0;j<RD_MAX_PORTS;j++) {
 | 
						|
      jack_input_mode[i][j]=0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  jack_card_process = jack_card; // populate variable used by callback process
 | 
						|
 | 
						|
  //
 | 
						|
  // Stop & Fade Timers
 | 
						|
  //
 | 
						|
  QSignalMapper *stop_mapper=new QSignalMapper(this);
 | 
						|
  connect(stop_mapper,SIGNAL(mapped(int)),this,SLOT(jackStopTimerData(int)));
 | 
						|
  QSignalMapper *fade_mapper=new QSignalMapper(this);
 | 
						|
  connect(fade_mapper,SIGNAL(mapped(int)),this,SLOT(jackFadeTimerData(int)));
 | 
						|
  QSignalMapper *record_mapper=new QSignalMapper(this);
 | 
						|
  connect(record_mapper,SIGNAL(mapped(int)),
 | 
						|
	  this,SLOT(jackRecordTimerData(int)));
 | 
						|
  for(int i=0;i<RD_MAX_STREAMS;i++) {
 | 
						|
    jack_stop_timer[i]=new QTimer(this);
 | 
						|
    stop_mapper->setMapping(jack_stop_timer[i],i);
 | 
						|
    connect(jack_stop_timer[i],SIGNAL(timeout()),stop_mapper,SLOT(map()));
 | 
						|
    jack_fade_timer[i]=new QTimer(this);
 | 
						|
    fade_mapper->setMapping(jack_fade_timer[i],i);
 | 
						|
    connect(jack_fade_timer[i],SIGNAL(timeout()),fade_mapper,SLOT(map()));
 | 
						|
  }
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    jack_record_timer[i]=new QTimer(this);
 | 
						|
    record_mapper->setMapping(jack_record_timer[i],i);
 | 
						|
    connect(jack_record_timer[i],SIGNAL(timeout()),record_mapper,SLOT(map()));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Register Ports
 | 
						|
  //
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    for(int j=0;j<2;j++) {
 | 
						|
      jack_output_port[i][j]=NULL;
 | 
						|
      jack_input_port[i][j]=NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  for(int i=0;i<station->jackPorts();i++) {
 | 
						|
    name=QString().sprintf("playout_%dL",i);
 | 
						|
    jack_output_port[i][0]=
 | 
						|
      jack_port_register(jack_client,(const char *)name,
 | 
						|
			 JACK_DEFAULT_AUDIO_TYPE,
 | 
						|
			 JackPortIsOutput|JackPortIsTerminal,0);
 | 
						|
    name=QString().sprintf("playout_%dR",i);
 | 
						|
    jack_output_port[i][1]=
 | 
						|
      jack_port_register(jack_client,(const char *)name,
 | 
						|
			 JACK_DEFAULT_AUDIO_TYPE,
 | 
						|
			 JackPortIsOutput|JackPortIsTerminal,0);
 | 
						|
    name=QString().sprintf("record_%dL",i);
 | 
						|
    jack_input_port[i][0]=
 | 
						|
      jack_port_register(jack_client,(const char *)name,
 | 
						|
			 JACK_DEFAULT_AUDIO_TYPE,
 | 
						|
			 JackPortIsInput|JackPortIsTerminal,0);
 | 
						|
    name=QString().sprintf("record_%dR",i);
 | 
						|
    jack_input_port[i][1]=
 | 
						|
      jack_port_register(jack_client,(const char *)name,
 | 
						|
			 JACK_DEFAULT_AUDIO_TYPE,
 | 
						|
			 JackPortIsInput|JackPortIsTerminal,0);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate Temporary Buffers
 | 
						|
  //
 | 
						|
  JackInitCallback();
 | 
						|
  jack_wave_buffer=new short[RINGBUFFER_SIZE];
 | 
						|
  jack_wave32_buffer=new int[RINGBUFFER_SIZE];
 | 
						|
  jack_wave24_buffer=new uint8_t[RINGBUFFER_SIZE];
 | 
						|
  jack_sample_buffer=new jack_default_audio_sample_t[RINGBUFFER_SIZE];
 | 
						|
 | 
						|
  //
 | 
						|
  // Join the Graph
 | 
						|
  //
 | 
						|
  if(jack_activate(jack_client)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  jack_sample_rate=jack_get_sample_rate(jack_client);
 | 
						|
  if(jack_sample_rate!=system_sample_rate) {
 | 
						|
    fprintf (stderr,"JACK sample rate mismatch!\n");
 | 
						|
    rd_config->log("caed",RDConfig::LogWarning,"JACK sample rate mismatch!");
 | 
						|
  }
 | 
						|
  jack_activated=true;
 | 
						|
  cae_driver[jack_card]=RDStation::Jack;
 | 
						|
  JackSessionSetup();
 | 
						|
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackFree()
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  for(unsigned i=0;i<jack_clients.size();i++) {
 | 
						|
    jack_clients[i]->kill();
 | 
						|
    delete jack_clients[i];
 | 
						|
  }
 | 
						|
  jack_clients.clear();
 | 
						|
  if(jack_activated) {
 | 
						|
    jack_deactivate(jack_client);
 | 
						|
  }
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackLoadPlayback(int card,QString wavename,int *stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if((*stream=GetJackOutputStream())<0) {
 | 
						|
    rd_config->log("caed",RDConfig::LogErr,QString().sprintf(
 | 
						|
            "Error: jackLoadPlayback(%s)   GetJackOutputStream():%d <0",
 | 
						|
            (const char *) wavename,
 | 
						|
            *stream) );
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_play_wave[*stream]=new RDWaveFile(wavename);
 | 
						|
  if(!jack_play_wave[*stream]->openWave()) {
 | 
						|
    rd_config->log("caed",RDConfig::LogNotice,QString().sprintf(
 | 
						|
            "Error: jackLoadPlayback(%s)   openWave() failed to open file",
 | 
						|
            (const char *) wavename) );
 | 
						|
    delete jack_play_wave[*stream];
 | 
						|
    jack_play_wave[*stream]=NULL;
 | 
						|
    FreeJackOutputStream(*stream);
 | 
						|
    *stream=-1;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  switch(jack_play_wave[*stream]->getFormatTag()) {
 | 
						|
  case WAVE_FORMAT_PCM:
 | 
						|
  case WAVE_FORMAT_VORBIS:
 | 
						|
    break;
 | 
						|
 | 
						|
  case WAVE_FORMAT_MPEG:
 | 
						|
    InitMadDecoder(card,*stream,jack_play_wave[*stream]);
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    rd_config->log("caed",RDConfig::LogNotice,
 | 
						|
	    QString().sprintf(
 | 
						|
	    "Error: jackLoadPlayback(%s)   getFormatTag()%d || getBistsPerSample()%d failed",
 | 
						|
	    (const char *) wavename,
 | 
						|
	    jack_play_wave[*stream]->getFormatTag(),
 | 
						|
	    jack_play_wave[*stream]->getBitsPerSample() ));
 | 
						|
    delete jack_play_wave[*stream];
 | 
						|
    jack_play_wave[*stream]=NULL;
 | 
						|
    FreeJackOutputStream(*stream);
 | 
						|
    *stream=-1;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_output_channels[*stream]=jack_play_wave[*stream]->getChannels();
 | 
						|
  jack_output_sample_rate[*stream]=jack_play_wave[*stream]->getSamplesPerSec();
 | 
						|
  jack_stopping[*stream]=false;
 | 
						|
  jack_offset[*stream]=0;
 | 
						|
  jack_output_pos[*stream]=0;
 | 
						|
  jack_eof[*stream]=false;
 | 
						|
  FillJackOutputStream(*stream);
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackUnloadPlayback(int card,int stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_STREAMS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if(jack_play_ring[stream]==NULL) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_playing[stream]=false;
 | 
						|
  switch(jack_play_wave[stream]->getFormatTag()) {
 | 
						|
  case WAVE_FORMAT_MPEG:
 | 
						|
    FreeMadDecoder(card,stream);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  jack_play_wave[stream]->closeWave();
 | 
						|
  delete jack_play_wave[stream];
 | 
						|
  jack_play_wave[stream]=NULL;
 | 
						|
  FreeJackOutputStream(stream);
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackPlaybackPosition(int card,int stream,unsigned pos)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  unsigned offset=0;
 | 
						|
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_STREAMS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_eof[stream]=false;
 | 
						|
  jack_play_ring[stream]->reset();
 | 
						|
 | 
						|
 | 
						|
  switch(jack_play_wave[stream]->getFormatTag()) {
 | 
						|
  case WAVE_FORMAT_PCM:
 | 
						|
  case WAVE_FORMAT_VORBIS:
 | 
						|
    offset=(unsigned)((double)jack_play_wave[stream]->getSamplesPerSec()*
 | 
						|
		      (double)jack_play_wave[stream]->getBlockAlign()*
 | 
						|
		      (double)pos/1000);
 | 
						|
    jack_offset[stream]=offset/jack_play_wave[stream]->getBlockAlign();
 | 
						|
    offset=jack_offset[stream]*jack_play_wave[stream]->getBlockAlign();
 | 
						|
    break;
 | 
						|
 | 
						|
  case WAVE_FORMAT_MPEG:
 | 
						|
    offset=(unsigned)((double)jack_play_wave[stream]->getSamplesPerSec()*
 | 
						|
		      (double)pos/1000);
 | 
						|
    jack_offset[stream]=offset/1152*1152;
 | 
						|
    offset=jack_offset[stream]/1152*jack_play_wave[stream]->getBlockAlign();
 | 
						|
    FreeMadDecoder(jack_card,stream);
 | 
						|
    InitMadDecoder(jack_card,stream,jack_play_wave[stream]);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  if(jack_offset[stream]>(int)jack_play_wave[stream]->getSampleLength()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_output_pos[stream]=0;
 | 
						|
  jack_play_wave[stream]->seekWave(offset,SEEK_SET);
 | 
						|
  FillJackOutputStream(stream);
 | 
						|
 | 
						|
  if(jack_playing[stream]) {
 | 
						|
    jack_stop_timer[stream]->stop();
 | 
						|
    jack_stop_timer[stream]->
 | 
						|
      start(jack_play_wave[stream]->getExtTimeLength()-pos,true);
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackPlay(int card,int stream,int length,int speed,bool pitch,
 | 
						|
			 bool rates)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if((stream <0) || (stream >= RD_MAX_STREAMS) || 
 | 
						|
     (jack_play_ring[stream]==NULL)||jack_playing[stream]) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if(speed!=RD_TIMESCALE_DIVISOR) {
 | 
						|
    jack_st_conv[stream]=new soundtouch::SoundTouch();
 | 
						|
    jack_st_conv[stream]->setTempo((float)speed/RD_TIMESCALE_DIVISOR);
 | 
						|
    jack_st_conv[stream]->setSampleRate(jack_output_sample_rate[stream]);
 | 
						|
    jack_st_conv[stream]->setChannels(jack_output_channels[stream]);
 | 
						|
  }
 | 
						|
  jack_playing[stream]=true;
 | 
						|
  if(length>0) {
 | 
						|
    jack_stop_timer[stream]->start(length,true);
 | 
						|
  }
 | 
						|
  statePlayUpdate(card,stream,1);
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackStopPlayback(int card,int stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if((stream <0) || (stream>=RD_MAX_STREAMS) || 
 | 
						|
     (jack_play_ring[stream]==NULL)||(!jack_playing[stream])) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_playing[stream]=false;
 | 
						|
  jack_stop_timer[stream]->stop();
 | 
						|
  statePlayUpdate(card,stream,2);
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackTimescaleSupported(int card)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackLoadRecord(int card,int stream,int coding,int chans,
 | 
						|
			       int samprate,int bitrate,QString wavename)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  jack_record_wave[stream]=new RDWaveFile(wavename);
 | 
						|
  switch(coding) {
 | 
						|
  case 0:  // PCM16
 | 
						|
    jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM);
 | 
						|
    jack_record_wave[stream]->setChannels(chans);
 | 
						|
    jack_record_wave[stream]->setSamplesPerSec(samprate);
 | 
						|
    jack_record_wave[stream]->setBitsPerSample(16);
 | 
						|
    break;
 | 
						|
 | 
						|
  case 4:  // PCM24
 | 
						|
    jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM);
 | 
						|
    jack_record_wave[stream]->setChannels(chans);
 | 
						|
    jack_record_wave[stream]->setSamplesPerSec(samprate);
 | 
						|
    jack_record_wave[stream]->setBitsPerSample(24);
 | 
						|
    break;
 | 
						|
 | 
						|
  case 2:  // MPEG Layer 2
 | 
						|
    if(!InitTwoLameEncoder(card,stream,chans,samprate,bitrate)) {
 | 
						|
      delete jack_record_wave[stream];
 | 
						|
      jack_record_wave[stream]=NULL;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_MPEG);
 | 
						|
    jack_record_wave[stream]->setChannels(chans);
 | 
						|
    jack_record_wave[stream]->setSamplesPerSec(samprate);
 | 
						|
    jack_record_wave[stream]->setBitsPerSample(16);
 | 
						|
    jack_record_wave[stream]->setHeadLayer(ACM_MPEG_LAYER2);
 | 
						|
    switch(chans) {
 | 
						|
    case 1:
 | 
						|
      jack_record_wave[stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL);
 | 
						|
      break;
 | 
						|
 | 
						|
    case 2:
 | 
						|
      jack_record_wave[stream]->setHeadMode(ACM_MPEG_STEREO);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      rd_config->log("caed",RDConfig::LogErr,QString().
 | 
						|
	sprintf("requested unsupported channel count %d, card: %d, stream: %d",
 | 
						|
		chans,card,stream));
 | 
						|
      delete jack_record_wave[stream];
 | 
						|
      jack_record_wave[stream]=NULL;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    jack_record_wave[stream]->setHeadBitRate(bitrate);
 | 
						|
    jack_record_wave[stream]->setMextChunk(true);
 | 
						|
    jack_record_wave[stream]->setMextHomogenous(true);
 | 
						|
    jack_record_wave[stream]->setMextPaddingUsed(false);
 | 
						|
    jack_record_wave[stream]->setMextHackedBitRate(true);
 | 
						|
    jack_record_wave[stream]->setMextFreeFormat(false);
 | 
						|
    jack_record_wave[stream]->
 | 
						|
      setMextFrameSize(144*jack_record_wave[stream]->getHeadBitRate()/
 | 
						|
		       jack_record_wave[stream]->getSamplesPerSec());
 | 
						|
    jack_record_wave[stream]->setMextAncillaryLength(5);
 | 
						|
    jack_record_wave[stream]->setMextLeftEnergyPresent(true);
 | 
						|
    if(chans>1) {
 | 
						|
      jack_record_wave[stream]->setMextRightEnergyPresent(true);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      jack_record_wave[stream]->setMextRightEnergyPresent(false);
 | 
						|
    }
 | 
						|
    jack_record_wave[stream]->setMextPrivateDataPresent(false);
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    rd_config->log("caed",RDConfig::LogErr,QString().
 | 
						|
	    sprintf("requested invalid audio encoding %d, card: %d, stream: %d",
 | 
						|
		    coding,card,stream));
 | 
						|
    delete jack_record_wave[stream];
 | 
						|
    jack_record_wave[stream]=NULL;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_record_wave[stream]->setBextChunk(true);
 | 
						|
  jack_record_wave[stream]->setLevlChunk(true);
 | 
						|
  if(!jack_record_wave[stream]->createWave()) {
 | 
						|
    delete jack_record_wave[stream];
 | 
						|
    jack_record_wave[stream]=NULL;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  chown((const char *)wavename,rd_config->uid(),rd_config->gid());
 | 
						|
  jack_input_channels[stream]=chans;
 | 
						|
  jack_record_ring[stream]=new RDRingBuffer(RINGBUFFER_SIZE);
 | 
						|
  jack_record_ring[stream]->reset();
 | 
						|
  jack_ready[stream]=true;
 | 
						|
  return true;
 | 
						|
 | 
						|
  /*
 | 
						|
  if ((stream <0) || (stream >=RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
    jack_record_wave[stream]=new RDWaveFile(wavename);
 | 
						|
  jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM);
 | 
						|
  jack_record_wave[stream]->setChannels(chans);
 | 
						|
  jack_record_wave[stream]->setSamplesPerSec(samprate);
 | 
						|
  jack_record_wave[stream]->setBitsPerSample(16);
 | 
						|
  jack_record_wave[stream]->setBextChunk(true);
 | 
						|
  jack_record_wave[stream]->setLevlChunk(true);
 | 
						|
  if(!jack_record_wave[stream]->createWave()) {
 | 
						|
    delete jack_record_wave[stream];
 | 
						|
    jack_record_wave[stream]=NULL;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  chown((const char *)wavename,rd_config->uid(),rd_config->gid());
 | 
						|
  jack_input_channels[stream]=chans; 
 | 
						|
  jack_record_ring[stream]=new RDRingBuffer(RINGBUFFER_SIZE);
 | 
						|
  jack_record_ring[stream]->reset();
 | 
						|
  jack_ready[stream]=true;
 | 
						|
  return true;
 | 
						|
  */
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackUnloadRecord(int card,int stream,unsigned *len)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_recording[stream]=false;
 | 
						|
  jack_ready[stream]=false;
 | 
						|
  EmptyJackInputStream(stream,true);
 | 
						|
  *len=jack_samples_recorded[stream];
 | 
						|
  jack_samples_recorded[stream]=0;
 | 
						|
  jack_record_wave[stream]->closeWave(*len);
 | 
						|
  delete jack_record_wave[stream];
 | 
						|
  jack_record_wave[stream]=NULL;
 | 
						|
  delete jack_record_ring[stream];
 | 
						|
  jack_record_ring[stream]=NULL;
 | 
						|
  FreeTwoLameEncoder(card,stream);
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackRecord(int card,int stream,int length,int thres)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if(!jack_ready[stream]) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_recording[stream]=true;
 | 
						|
  if(jack_input_vox[stream]==0.0) {
 | 
						|
    if(length>0) {
 | 
						|
      jack_record_timer[stream]->start(length,true);
 | 
						|
    }
 | 
						|
    stateRecordUpdate(card,stream,4);
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackStopRecord(int card,int stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if(!jack_recording[stream]) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  jack_recording[stream]=false;
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackSetInputVolume(int card,int stream,int level)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_STREAMS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if(level>-10000) {
 | 
						|
    jack_input_volume[stream]=
 | 
						|
      (jack_default_audio_sample_t)pow(10.0,(double)level/2000.0);
 | 
						|
    jack_input_volume_db[stream]=level;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    jack_input_volume[stream]=0.0;
 | 
						|
    jack_input_volume_db[stream]=-10000;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackSetOutputVolume(int card,int stream,int port,int level)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((stream <0) ||(stream >= RD_MAX_STREAMS) || 
 | 
						|
      (port <0) || (port >= RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if(level>-10000) {
 | 
						|
    jack_output_volume[port][stream]=
 | 
						|
      (jack_default_audio_sample_t)pow(10.0,(double)level/2000.0);
 | 
						|
    jack_output_volume_db[port][stream]=level;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    jack_output_volume[port][stream]=0.0;
 | 
						|
    jack_output_volume_db[port][stream]=-10000;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackFadeOutputVolume(int card,int stream,int port,int level,
 | 
						|
				     int length)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  int diff;
 | 
						|
  if ((stream <0) ||(stream >= RD_MAX_STREAMS) || 
 | 
						|
      (port <0) || (port >= RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if(jack_fade_timer[stream]->isActive()) {
 | 
						|
    jack_fade_timer[stream]->stop();
 | 
						|
  }
 | 
						|
  if(level>jack_output_volume_db[port][stream]) {
 | 
						|
    jack_fade_up[stream]=true;
 | 
						|
    diff=level-jack_output_volume_db[port][stream];
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    jack_fade_up[stream]=false;
 | 
						|
    diff=jack_output_volume_db[port][stream]-level;
 | 
						|
  }
 | 
						|
  jack_fade_volume_db[stream]=level;
 | 
						|
  jack_fade_port[stream]=port;
 | 
						|
  jack_fade_increment[stream]=diff*RD_JACK_FADE_INTERVAL/length;
 | 
						|
  jack_fade_timer[stream]->start(RD_JACK_FADE_INTERVAL);
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackSetInputLevel(int card,int port,int level)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackSetOutputLevel(int card,int port,int level)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackSetInputMode(int card,int stream,int mode)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  jack_input_mode[card][stream]=mode;
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackSetOutputMode(int card,int stream,int mode)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackSetInputVoxLevel(int card,int stream,int level)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackSetInputType(int card,int port,int type)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackGetInputStatus(int card,int port)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackGetInputMeters(int card,int port,short levels[2])
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  jack_default_audio_sample_t meter;
 | 
						|
  if ((port <0) || (port >= RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  for(int i=0;i<2;i++) {
 | 
						|
    meter=jack_input_meter[port][i]->average();
 | 
						|
    if(meter==0.0) {
 | 
						|
      levels[i]=-10000;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      levels[i]=(short)(2000.0*log10(meter));
 | 
						|
      if(levels[i]<-10000) {
 | 
						|
	levels[i]=-10000;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackGetOutputMeters(int card,int port,short levels[2])
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  jack_default_audio_sample_t meter;
 | 
						|
  if ((port <0) || (port >= RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  for(int i=0;i<2;i++) {
 | 
						|
    meter=jack_output_meter[port][i]->average();
 | 
						|
    if(meter==0.0) {
 | 
						|
      levels[i]=-10000;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      levels[i]=(short)(2000.0*log10(meter));
 | 
						|
      if(levels[i]<-10000) {
 | 
						|
	levels[i]=-10000;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool MainObject::jackGetStreamOutputMeters(int card,int stream,short levels[2])
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  jack_default_audio_sample_t meter;
 | 
						|
  if ((stream<0) || (stream>=RD_MAX_STREAMS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  for(int i=0;i<2;i++) {
 | 
						|
    meter=jack_stream_output_meter[stream][i]->average();
 | 
						|
    if(meter==0.0) {
 | 
						|
      levels[i]=-10000;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      levels[i]=(short)(2000.0*log10(meter));
 | 
						|
      if(levels[i]<-10000) {
 | 
						|
	levels[i]=-10000;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackGetOutputPosition(int card,unsigned *pos)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  for(int i=0;i<RD_MAX_STREAMS;i++) {
 | 
						|
    if(jack_play_wave[i]!=NULL) {
 | 
						|
      pos[i]=1000*((unsigned long long)jack_offset[i]+jack_output_pos[i])/
 | 
						|
	jack_play_wave[i]->getSamplesPerSec();
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      pos[i]=0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
bool MainObject::jackSetPassthroughLevel(int card,int in_port,int out_port,
 | 
						|
					int level)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((in_port <0) || (in_port >= RD_MAX_PORTS) || 
 | 
						|
      (out_port <0) || (out_port >= RD_MAX_PORTS)){
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if(level>-10000) {
 | 
						|
    jack_passthrough_volume[in_port][out_port]=
 | 
						|
      (jack_default_audio_sample_t)pow(10.0,(double)level/2000.0);
 | 
						|
    jack_passthrough_volume_db[in_port][out_port]=level;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    jack_passthrough_volume[in_port][out_port]=0.0;
 | 
						|
    jack_passthrough_volume_db[in_port][out_port]=-10000;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
#else
 | 
						|
  return false;
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackConnectPorts(const QString &out,const QString &in)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if(jack_card<0) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  jack_connect(jack_client,(const char *)in,(const char *)out);  
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::jackDisconnectPorts(const QString &out,const QString &in)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if(jack_card<0) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  jack_disconnect(jack_client,(const char *)in,(const char *)out);  
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int MainObject::GetJackOutputStream()
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  for(int i=0;i<RD_MAX_STREAMS;i++) {
 | 
						|
    if(jack_play_ring[i]==NULL) {
 | 
						|
      jack_play_ring[i]=new RDRingBuffer(RINGBUFFER_SIZE);
 | 
						|
      return i;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return -1;
 | 
						|
#else
 | 
						|
  return -1;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::FreeJackOutputStream(int stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_STREAMS)){
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  delete jack_play_ring[stream];
 | 
						|
  jack_play_ring[stream]=NULL;
 | 
						|
  if(jack_st_conv[stream]!=NULL) {
 | 
						|
    delete jack_st_conv[stream];
 | 
						|
    jack_st_conv[stream]=NULL;
 | 
						|
  }
 | 
						|
#else
 | 
						|
  return;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::EmptyJackInputStream(int stream,bool done)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_STREAMS)){
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  unsigned n=jack_record_ring[stream]->
 | 
						|
    read((char *)jack_sample_buffer,jack_record_ring[stream]->readSpace());
 | 
						|
  WriteJackBuffer(stream,jack_sample_buffer,n,done);
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
#ifdef JACK
 | 
						|
void MainObject::WriteJackBuffer(int stream,jack_default_audio_sample_t *buffer,
 | 
						|
				 unsigned len,bool done)
 | 
						|
{
 | 
						|
  ssize_t s;
 | 
						|
  unsigned char mpeg[2048];
 | 
						|
  unsigned frames;
 | 
						|
  unsigned n;
 | 
						|
 | 
						|
  frames=len/(sizeof(jack_default_audio_sample_t)*
 | 
						|
	      jack_record_wave[stream]->getChannels());
 | 
						|
  jack_samples_recorded[stream]+=frames;
 | 
						|
  switch(jack_record_wave[stream]->getFormatTag()) {
 | 
						|
  case WAVE_FORMAT_PCM:
 | 
						|
    switch(jack_record_wave[stream]->getBitsPerSample()) {
 | 
						|
    case 16:  // PCM16
 | 
						|
      n=len/sizeof(jack_default_audio_sample_t);
 | 
						|
      src_float_to_short_array(buffer,jack_wave_buffer,n);
 | 
						|
      jack_record_wave[stream]->writeWave(jack_wave_buffer,n*sizeof(short));
 | 
						|
      break;
 | 
						|
 | 
						|
    case 24:  // PCM24
 | 
						|
      n=len/sizeof(jack_default_audio_sample_t);
 | 
						|
      src_float_to_int_array(buffer,jack_wave32_buffer,n);
 | 
						|
      for(unsigned i=0;i<n;i++) {
 | 
						|
	for(unsigned j=0;j<3;j++) {
 | 
						|
	  jack_wave24_buffer[3*i+j]=((uint8_t *)jack_wave32_buffer)[4*i+j+1];
 | 
						|
	}
 | 
						|
      }
 | 
						|
      jack_record_wave[stream]->writeWave(jack_wave24_buffer,n*3);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
  case WAVE_FORMAT_MPEG:
 | 
						|
#ifdef HAVE_TWOLAME
 | 
						|
    for(unsigned i=0;i<frames;i+=1152) {
 | 
						|
      if((i+1152)>frames) {
 | 
						|
	n=frames-i;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
	n=1152;
 | 
						|
      }
 | 
						|
      if((s=twolame_encode_buffer_float32_interleaved(
 | 
						|
		 twolame_lameopts[jack_card][stream],
 | 
						|
		 buffer+i*jack_record_wave[stream]->getChannels(),
 | 
						|
		 n,mpeg,2048))>=0) {
 | 
						|
	jack_record_wave[stream]->writeWave(mpeg,s);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
	rd_config->log("caed",RDConfig::LogErr,QString().
 | 
						|
	   sprintf("TwoLAME encode error, card: %d, stream: %d",jack_card,
 | 
						|
		   stream));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if(done) {
 | 
						|
      if((s=twolame_encode_flush(twolame_lameopts[jack_card][stream],
 | 
						|
				 mpeg,2048))>=0) {
 | 
						|
	jack_record_wave[stream]->writeWave(mpeg,s);
 | 
						|
      }
 | 
						|
    }
 | 
						|
#endif  // HAVE_TWOLAME
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
#endif  // JACK
 | 
						|
 | 
						|
void MainObject::FillJackOutputStream(int stream)
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  int n=0;
 | 
						|
  unsigned mpeg_frames=0;
 | 
						|
  unsigned frame_offset=0;
 | 
						|
  int m=0;
 | 
						|
 | 
						|
  if ((stream <0) || (stream >= RD_MAX_STREAMS)){
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  int free=
 | 
						|
    jack_play_ring[stream]->writeSpace()/sizeof(jack_default_audio_sample_t)-1;
 | 
						|
  if((free<=0)||(jack_eof[stream]==true)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  switch(jack_play_wave[stream]->getFormatTag()) {
 | 
						|
  case WAVE_FORMAT_PCM:
 | 
						|
    switch(jack_play_wave[stream]->getBitsPerSample()) {
 | 
						|
    case 16:  // PMC16
 | 
						|
      free=(int)free/jack_output_channels[stream]*jack_output_channels[stream];
 | 
						|
      n=jack_play_wave[stream]->readWave(jack_wave_buffer,sizeof(short)*free)/
 | 
						|
	sizeof(short);
 | 
						|
      if((n!=free)&&(jack_st_conv[stream]==NULL)) {
 | 
						|
	jack_eof[stream]=true;
 | 
						|
	jack_stop_timer[stream]->stop();
 | 
						|
      }
 | 
						|
      src_short_to_float_array(jack_wave_buffer,jack_sample_buffer,n);
 | 
						|
      break;
 | 
						|
 | 
						|
    case 24:  // PMC24
 | 
						|
      free=(int)free/jack_output_channels[stream]*jack_output_channels[stream];
 | 
						|
      n=jack_play_wave[stream]->readWave(jack_wave24_buffer,3*free)/3;
 | 
						|
      if((n!=free)&&(jack_st_conv[stream]==NULL)) {
 | 
						|
	jack_eof[stream]=true;
 | 
						|
	jack_stop_timer[stream]->stop();
 | 
						|
      }
 | 
						|
      for(int i=0;i<n;i++) {
 | 
						|
	for(unsigned j=0;j<3;j++) {
 | 
						|
	  ((uint8_t *)jack_wave32_buffer)[4*i+j+1]=jack_wave24_buffer[3*i+j];
 | 
						|
	}
 | 
						|
      }
 | 
						|
      src_int_to_float_array(jack_wave32_buffer,jack_sample_buffer,n);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
  case WAVE_FORMAT_VORBIS:
 | 
						|
    free=(int)free/jack_output_channels[stream]*jack_output_channels[stream];
 | 
						|
    n=jack_play_wave[stream]->readWave(jack_wave_buffer,sizeof(short)*free)/
 | 
						|
      sizeof(short);
 | 
						|
    if((n!=free)&&(jack_st_conv[stream]==NULL)) {
 | 
						|
      jack_eof[stream]=true;
 | 
						|
      jack_stop_timer[stream]->stop();
 | 
						|
    }
 | 
						|
    src_short_to_float_array(jack_wave_buffer,jack_sample_buffer,n);
 | 
						|
    break;
 | 
						|
 | 
						|
  case WAVE_FORMAT_MPEG:
 | 
						|
#ifdef HAVE_MAD
 | 
						|
    mpeg_frames=free/(1152*jack_output_channels[stream]);
 | 
						|
    free=mpeg_frames*1152*jack_output_channels[stream];
 | 
						|
    for(unsigned i=0;i<mpeg_frames;i++) {
 | 
						|
      m=jack_play_wave[stream]->
 | 
						|
	readWave(mad_mpeg[jack_card][stream]+mad_left_over[jack_card][stream],
 | 
						|
		 mad_frame_size[jack_card][stream]);
 | 
						|
      if(m==mad_frame_size[jack_card][stream]) {
 | 
						|
	mad_stream_buffer(&mad_stream[jack_card][stream],
 | 
						|
			  mad_mpeg[jack_card][stream],
 | 
						|
			  m+mad_left_over[jack_card][stream]);
 | 
						|
	while(mad_frame_decode(&mad_frame[jack_card][stream],
 | 
						|
			    &mad_stream[jack_card][stream])==0) {
 | 
						|
	  mad_synth_frame(&mad_synth[jack_card][stream],
 | 
						|
			  &mad_frame[jack_card][stream]);
 | 
						|
	  n+=(jack_output_channels[stream]*
 | 
						|
	      mad_synth[jack_card][stream].pcm.length);
 | 
						|
	  for(int j=0;j<mad_synth[jack_card][stream].pcm.length;j++) {
 | 
						|
	    for(int k=0;k<mad_synth[jack_card][stream].pcm.channels;k++) {
 | 
						|
	      jack_sample_buffer[frame_offset+
 | 
						|
				 j*mad_synth[jack_card][stream].pcm.channels+k]=
 | 
						|
		(jack_default_audio_sample_t)
 | 
						|
		mad_f_todouble(mad_synth[jack_card][stream].pcm.samples[k][j]);
 | 
						|
	      
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	  frame_offset+=(mad_synth[jack_card][stream].pcm.length*
 | 
						|
			 mad_synth[jack_card][stream].pcm.channels);
 | 
						|
	}
 | 
						|
      }
 | 
						|
      else {  // End-of-file, read out last samples
 | 
						|
	memset(mad_mpeg[jack_card][stream]+mad_left_over[jack_card][stream],0,
 | 
						|
	       MAD_BUFFER_GUARD);
 | 
						|
	mad_stream_buffer(&mad_stream[jack_card][stream],
 | 
						|
			  mad_mpeg[jack_card][stream],
 | 
						|
			  MAD_BUFFER_GUARD+mad_left_over[jack_card][stream]);
 | 
						|
	if(mad_frame_decode(&mad_frame[jack_card][stream],
 | 
						|
			    &mad_stream[jack_card][stream])==0) {
 | 
						|
	  mad_synth_frame(&mad_synth[jack_card][stream],
 | 
						|
			  &mad_frame[jack_card][stream]);
 | 
						|
	  n+=(jack_output_channels[stream]*
 | 
						|
	      mad_synth[jack_card][stream].pcm.length);
 | 
						|
	  for(int j=0;j<mad_synth[jack_card][stream].pcm.length;j++) {
 | 
						|
	    for(int k=0;k<mad_synth[jack_card][stream].pcm.channels;k++) {
 | 
						|
	      jack_sample_buffer[frame_offset+
 | 
						|
				 j*mad_synth[jack_card][stream].pcm.channels+k]=
 | 
						|
		(jack_default_audio_sample_t)
 | 
						|
		mad_f_todouble(mad_synth[jack_card][stream].pcm.samples[k][j]);
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	}
 | 
						|
	jack_eof[stream]=true;
 | 
						|
	jack_stop_timer[stream]->stop();
 | 
						|
	continue;
 | 
						|
      }
 | 
						|
      mad_left_over[jack_card][stream]=
 | 
						|
	mad_stream[jack_card][stream].bufend-
 | 
						|
	mad_stream[jack_card][stream].next_frame;
 | 
						|
      memmove(mad_mpeg[jack_card][stream],
 | 
						|
	      mad_stream[jack_card][stream].next_frame,
 | 
						|
	      mad_left_over[jack_card][stream]);
 | 
						|
    }
 | 
						|
#endif  // HAVE_MAD
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  if(jack_st_conv[stream]==NULL) {
 | 
						|
    jack_play_ring[stream]->
 | 
						|
      write((char *)jack_sample_buffer,n*sizeof(jack_default_audio_sample_t));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    jack_st_conv[stream]->
 | 
						|
      putSamples(jack_sample_buffer,n/jack_output_channels[stream]);
 | 
						|
    free=jack_play_ring[stream]->writeSpace()/
 | 
						|
      (sizeof(jack_default_audio_sample_t)*jack_output_channels[stream])-1;
 | 
						|
    while((n=jack_st_conv[stream]->
 | 
						|
	   receiveSamples(jack_sample_buffer,free))>0) {
 | 
						|
      jack_play_ring[stream]->
 | 
						|
	write((char *)jack_sample_buffer,n*
 | 
						|
	      sizeof(jack_default_audio_sample_t)*
 | 
						|
	      jack_output_channels[stream]);
 | 
						|
      free=jack_play_ring[stream]->writeSpace()/
 | 
						|
	(sizeof(jack_default_audio_sample_t)*jack_output_channels[stream])-1;
 | 
						|
    }
 | 
						|
    if((jack_st_conv[stream]->numSamples()==0)&&
 | 
						|
       (jack_st_conv[stream]->numUnprocessedSamples()==0)) {
 | 
						|
      jack_eof[stream]=true;
 | 
						|
      jack_stop_timer[stream]->stop();
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::JackClock()
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  for(int i=0;i<RD_MAX_STREAMS;i++) {
 | 
						|
    if(jack_stopping[i]) {
 | 
						|
      jack_stopping[i]=false;
 | 
						|
      statePlayUpdate(jack_card,i,2);
 | 
						|
    }
 | 
						|
    if(jack_playing[i]&&((jack_clock_phase%4)==0)) {
 | 
						|
      FillJackOutputStream(i);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  jack_clock_phase++;
 | 
						|
  for(int i=0;i<RD_MAX_PORTS;i++) {
 | 
						|
    if(jack_recording[i]) {
 | 
						|
      EmptyJackInputStream(i,false);
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif  // JACK
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void MainObject::JackSessionSetup()
 | 
						|
{
 | 
						|
#ifdef JACK
 | 
						|
  int count=0;
 | 
						|
  RDProfile *profile=new RDProfile();
 | 
						|
  profile->setSource(RD_CONF_FILE);
 | 
						|
  bool src_ok=false;
 | 
						|
  bool dest_ok=false;
 | 
						|
  QString src_tag="Source1";
 | 
						|
  QString dest_tag="Destination1";
 | 
						|
  QString src=profile->stringValue("JackSession",src_tag,"",&src_ok);
 | 
						|
  QString dest=profile->stringValue("JackSession",dest_tag,"",&dest_ok);
 | 
						|
  while(src_ok&&dest_ok) {
 | 
						|
    if(jack_connect(jack_client,(const char *)src,(const char *)dest)!=0) {
 | 
						|
      rd_config->log("caed",RDConfig::LogNotice,QString().
 | 
						|
	      sprintf("unable to connect %s to %s",
 | 
						|
		      (const char *)src,(const char *)dest));
 | 
						|
    }
 | 
						|
    count++;
 | 
						|
    src_tag=QString().sprintf("Source%d",count+1);
 | 
						|
    dest_tag=QString().sprintf("Destination%d",count+1);
 | 
						|
    src=profile->stringValue("JackSession",src_tag,"",&src_ok);
 | 
						|
    dest=profile->stringValue("JackSession",dest_tag,"",&dest_ok);
 | 
						|
  }
 | 
						|
  delete profile;
 | 
						|
#endif  // JACK
 | 
						|
}
 |