JackAudioInterface.cpp 18.5 KB
Newer Older
jcaceres's avatar
jcaceres committed
1
2
//*****************************************************************
/*
jcaceres's avatar
jcaceres committed
3
  JackTrip: A System for High-Quality Audio Network Performance
jcaceres's avatar
jcaceres committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  over the Internet

  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
  SoundWIRE group at CCRMA, Stanford University.
  
  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:
  
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
*/
//*****************************************************************

32
33
/**
 * \file JackAudioInterface.cpp
jcaceres's avatar
jcaceres committed
34
35
 * \author Juan-Pablo Caceres
 * \date June 2008
36
37
 */

jcaceres's avatar
jcaceres committed
38

39
#include "JackAudioInterface.h"
jcaceres's avatar
more    
jcaceres committed
40
#include "globals.h"
41
#include <QTextStream>
jcaceres's avatar
more    
jcaceres committed
42
#include <cstdlib>
jcaceres's avatar
jcaceres committed
43
#include <cstring>
44
#include <cmath>
45

jcaceres's avatar
jcaceres committed
46
using std::cout; using std::cout;
jcaceres's avatar
more    
jcaceres committed
47
48
49
/// \todo Check that the RingBuffer Pointer have indeed been initialized before
/// computing anything

50

jcaceres's avatar
jcaceres committed
51
//*******************************************************************************
jcaceres's avatar
more    
jcaceres committed
52
53
54
JackAudioInterface::JackAudioInterface(int NumInChans, int NumOutChans,
				       audioBitResolutionT AudioBitResolution)
  : mNumInChans(NumInChans), mNumOutChans(NumOutChans), 
55
    mAudioBitResolution(AudioBitResolution*8), mBitResolutionMode(AudioBitResolution)
jcaceres's avatar
jcaceres committed
56
{
jcaceres's avatar
more    
jcaceres committed
57
58
  setupClient();
  setProcessCallback();
59
60
61
}


jcaceres's avatar
jcaceres committed
62
//*******************************************************************************
63
64
JackAudioInterface::~JackAudioInterface()
{
jcaceres's avatar
jcaceres committed
65
66
  delete[] mInputPacket;
  delete[] mOutputPacket;
67
68
69
70
71
72
  for (int i = 0; i < mNumInChans; i++) {
    delete[] mInProcessBuffer[i];
  }
  for (int i = 0; i < mNumOutChans; i++) {
    delete[] mOutProcessBuffer[i];
  }
73
74
75
}


jcaceres's avatar
jcaceres committed
76
//*******************************************************************************
jcaceres's avatar
jcaceres committed
77
void JackAudioInterface::setupClient()
78
{
jcaceres's avatar
jcaceres committed
79
  // \todo Get this name from global variable
jcaceres's avatar
jcaceres committed
80
  const char* client_name = "JackTrip";//APP_NAME;
81
82
83
84
  const char* server_name = NULL;
  jack_options_t options = JackNoStartServer;
  jack_status_t status;

jcaceres's avatar
jcaceres committed
85
  // Try to connect to the server
jcaceres's avatar
more    
jcaceres committed
86
87
  /// \todo Write better warning messages. This following line displays very
  /// verbose message, check how to desable them.
88
89
90
  mClient = jack_client_open (client_name, options, &status, server_name);
  if (mClient == NULL) {
    fprintf (stderr, "jack_client_open() failed, "
jcaceres's avatar
more    
jcaceres committed
91
    	     "status = 0x%2.0x\n", status);
92
93
    if (status & JackServerFailed) {
      fprintf (stderr, "Unable to connect to JACK server\n");
jcaceres's avatar
more    
jcaceres committed
94
      std::cerr << "ERROR: Maybe the JACK server is not running?" << std::endl;
jcaceres's avatar
jcaceres committed
95
      std::cerr << gPrintSeparator << std::endl;
96
    }
jcaceres's avatar
more    
jcaceres committed
97
    std::exit(1);
98
99
100
101
102
103
104
105
106
  }
  if (status & JackServerStarted) {
    fprintf (stderr, "JACK server started\n");
  }
  if (status & JackNameNotUnique) {
    client_name = jack_get_client_name(mClient);
    fprintf (stderr, "unique name `%s' assigned\n", client_name);
  }

jcaceres's avatar
jcaceres committed
107
108
  // Set function to call if Jack shuts down
  jack_on_shutdown (mClient, this->jackShutdown, 0);
109

jcaceres's avatar
jcaceres committed
110
  // Create input and output channels
jcaceres's avatar
More    
jcaceres committed
111
  createChannels();
jcaceres's avatar
jcaceres committed
112
113

  // Allocate buffer memory to read and write
jcaceres's avatar
More    
jcaceres committed
114
115
116
  mSizeInBytesPerChannel = getSizeInBytesPerChannel();
  int size_input  = mSizeInBytesPerChannel * getNumInputChannels();
  int size_output = mSizeInBytesPerChannel * getNumOutputChannels();
jcaceres's avatar
jcaceres committed
117
118
  mInputPacket = new int8_t[size_input];
  mOutputPacket = new int8_t[size_output];
119

120
  // Buffer size member
121
  mNumFrames = getBufferSizeInSamples(); 
122
123
124
125
126
127
128
129
130

  // Initialize Buffer array to read and write audio
  mInBuffer.resize(mNumInChans);
  mOutBuffer.resize(mNumOutChans);

  // Initialize and asign memory for ProcessPlugins Buffers
  mInProcessBuffer.resize(mNumInChans);
  mOutProcessBuffer.resize(mNumOutChans);

131
  int nframes = getBufferSizeInSamples();
132
133
134
135
136
137
138
139
140
141
  for (int i = 0; i < mNumInChans; i++) {
    mInProcessBuffer[i] = new sample_t[nframes];
    // set memory to 0
    std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * nframes);
  }
  for (int i = 0; i < mNumOutChans; i++) {
    mOutProcessBuffer[i] = new sample_t[nframes];
    // set memory to 0
    std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
  }
142
143
144
}


jcaceres's avatar
jcaceres committed
145
//*******************************************************************************
146
147
148
149
150
151
152
void JackAudioInterface::createChannels()
{
  //Create Input Ports
  mInPorts.resize(mNumInChans);
  for (int i = 0; i < mNumInChans; i++) 
    {
      QString inName;
jcaceres's avatar
more    
jcaceres committed
153
      QTextStream (&inName) << "send_" << i+1;
154
155
156
157
158
159
160
161
162
163
      mInPorts[i] = jack_port_register (mClient, inName.toLatin1(),
					JACK_DEFAULT_AUDIO_TYPE,
					JackPortIsInput, 0);
    }

  //Create Output Ports
  mOutPorts.resize(mNumOutChans);
  for (int i = 0; i < mNumInChans; i++) 
    {
      QString outName;
jcaceres's avatar
more    
jcaceres committed
164
      QTextStream (&outName) << "receive_" << i+1;
jcaceres's avatar
jcaceres committed
165
      mOutPorts[i] = jack_port_register (mClient, outName.toLatin1(),
166
167
168
169
170
171
					JACK_DEFAULT_AUDIO_TYPE,
					 JackPortIsOutput, 0);
    }
}


jcaceres's avatar
jcaceres committed
172
//*******************************************************************************
jcaceres's avatar
jcaceres committed
173
uint32_t JackAudioInterface::getSampleRate() const 
174
175
176
177
178
{
  return jack_get_sample_rate(mClient);
}


jcaceres's avatar
jcaceres committed
179
180
181
182
//*******************************************************************************
JackAudioInterface::samplingRateT JackAudioInterface::getSampleRateType() const
{
  uint32_t rate = jack_get_sample_rate(mClient);
jcaceres's avatar
jcaceres committed
183

jcaceres's avatar
jcaceres committed
184
185
  if      ( rate == 22050 ) {
    return JackAudioInterface::SR22; }
jcaceres's avatar
jcaceres committed
186
187
  else if ( rate == 32000 ) {
    return JackAudioInterface::SR32; }
jcaceres's avatar
jcaceres committed
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  else if ( rate == 44100 ) {
    return JackAudioInterface::SR44; }
  else if ( rate == 48000 ) {
    return JackAudioInterface::SR48; }
  else if ( rate == 88200 ) {
    return JackAudioInterface::SR88; }
  else if ( rate == 96000 ) {
    return JackAudioInterface::SR96; }
  else if ( rate == 19200 ) {
    return JackAudioInterface::SR192; }

  return JackAudioInterface::UNDEF;
}


jcaceres's avatar
jcaceres committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//*******************************************************************************
int JackAudioInterface::getSampleRateFromType(samplingRateT rate_type)
{
  int sample_rate = 0;
  switch (rate_type)
    {
    case SR22 :
      sample_rate = 22050;
      return sample_rate;
      break;
    case SR32 :
      sample_rate = 32000;
      return sample_rate;
      break;
    case SR44 :
      sample_rate = 44000;
      return sample_rate;
      break;
    case SR48 :
      sample_rate = 48000;
      return sample_rate;
      break;
    case SR88 :
      sample_rate = 88200;
      return sample_rate;
      break;
    case SR96 :
      sample_rate = 96000;
      return sample_rate;
      break;
    case SR192 :
      sample_rate = 192000;
      return sample_rate;
      break;
    default:
      return sample_rate;
      break;
    }

  return sample_rate;
}
jcaceres's avatar
jcaceres committed
244

jcaceres's avatar
jcaceres committed
245
//*******************************************************************************
246
uint32_t JackAudioInterface::getBufferSizeInSamples() const 
247
248
249
250
{
  return jack_get_buffer_size(mClient);
}

jcaceres's avatar
jcaceres committed
251

jcaceres's avatar
jcaceres committed
252
//*******************************************************************************
jcaceres's avatar
more    
jcaceres committed
253
int JackAudioInterface::getAudioBitResolution() const
jcaceres's avatar
jcaceres committed
254
{
jcaceres's avatar
more    
jcaceres committed
255
256
257
258
  return mAudioBitResolution;
}


jcaceres's avatar
jcaceres committed
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
//*******************************************************************************
int JackAudioInterface::getNumInputChannels() const
{
  return mNumInChans;
}


//*******************************************************************************
int JackAudioInterface::getNumOutputChannels() const
{
  return mNumOutChans;
}


//*******************************************************************************
jcaceres's avatar
More    
jcaceres committed
274
size_t JackAudioInterface::getSizeInBytesPerChannel() const
jcaceres's avatar
jcaceres committed
275
{
276
  return (getBufferSizeInSamples() * getAudioBitResolution()/8);
jcaceres's avatar
jcaceres committed
277
278
}

jcaceres's avatar
more    
jcaceres committed
279
280
281
282
283
284
285
//*******************************************************************************
int JackAudioInterface::setProcessCallback()
{
  std::cout << "Setting JACK Process Callback..." << std::endl;
  if ( int code = 
       jack_set_process_callback(mClient, JackAudioInterface::wrapperProcessCallback, this)
       )
jcaceres's avatar
jcaceres committed
286
    {
jcaceres's avatar
more    
jcaceres committed
287
      std::cerr << "Could not set the process callback" << std::endl;
jcaceres's avatar
jcaceres committed
288
      return(code);
jcaceres's avatar
more    
jcaceres committed
289
      std::exit(1);
jcaceres's avatar
jcaceres committed
290
    }
jcaceres's avatar
more    
jcaceres committed
291
  std::cout << "SUCCESS" << std::endl;
jcaceres's avatar
jcaceres committed
292
  std::cout << gPrintSeparator << std::endl;
jcaceres's avatar
jcaceres committed
293
294
295
296
  return(0);
}


jcaceres's avatar
jcaceres committed
297
//*******************************************************************************
jcaceres's avatar
more    
jcaceres committed
298
int JackAudioInterface::startProcess() const
jcaceres's avatar
jcaceres committed
299
300
301
302
303
{
  //Tell the JACK server that we are ready to roll.  Our
  //process() callback will start running now.
  if ( int code = (jack_activate(mClient)) ) 
    {
jcaceres's avatar
more    
jcaceres committed
304
      std::cerr << "Cannot activate client" << std::endl;
jcaceres's avatar
jcaceres committed
305
306
307
308
309
310
    return(code);
    }
  return(0);
}


jcaceres's avatar
jcaceres committed
311
//*******************************************************************************
jcaceres's avatar
jcaceres committed
312
313
314
315
int JackAudioInterface::stopProcess() const
{
  if ( int code = (jack_client_close(mClient)) )
    {
jcaceres's avatar
more    
jcaceres committed
316
      std::cerr << "Cannot disconnect client" << std::endl;
jcaceres's avatar
jcaceres committed
317
318
319
320
321
322
      return(code);
    }
  return(0);
}


jcaceres's avatar
jcaceres committed
323
//*******************************************************************************
jcaceres's avatar
jcaceres committed
324
void JackAudioInterface::jackShutdown (void*)
325
{
jcaceres's avatar
more    
jcaceres committed
326
327
328
  std::cout << "The Jack Server was shut down!" << std::endl;
  std::cout << "Exiting program..." << std::endl;
  std::exit(1);
329
}
jcaceres's avatar
jcaceres committed
330
331
332


//*******************************************************************************
333
334
335
void JackAudioInterface::setRingBuffers
(const std::tr1::shared_ptr<RingBuffer> InRingBuffer,
 const std::tr1::shared_ptr<RingBuffer> OutRingBuffer)
jcaceres's avatar
jcaceres committed
336
337
338
339
340
341
{
  mInRingBuffer = InRingBuffer;
  mOutRingBuffer = OutRingBuffer;
}


jcaceres's avatar
more    
jcaceres committed
342
//*******************************************************************************
jcaceres's avatar
jcaceres committed
343
344
345
// Before sending and reading to Jack, we have to round to the sample resolution
// that the program is using. Jack uses 32 bits (gJackBitResolution in globals.h)
// by default
346
void JackAudioInterface::computeNetworkProcessFromNetwork()
jcaceres's avatar
more    
jcaceres committed
347
{
jcaceres's avatar
More    
jcaceres committed
348
  /// \todo cast *mInBuffer[i] to the bit resolution
349
  //cout << mNumFrames << endl;
350
  // Output Process (from NETWORK to JACK)
jcaceres's avatar
jcaceres committed
351
  // ----------------------------------------------------------------
352
  // Read Audio buffer from RingBuffer (read from incoming packets)
jcaceres's avatar
More    
jcaceres committed
353
354
355
  mOutRingBuffer->readSlotNonBlocking(  mOutputPacket );
  // Extract separate channels to send to Jack
  for (int i = 0; i < mNumOutChans; i++) {
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
    //--------
    // This should be faster for 32 bits
    //std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
    //		mSizeInBytesPerChannel);
    //--------
    sample_t* tmp_sample = mOutBuffer[i]; //sample buffer for channel i
    for (int j = 0; j < mNumFrames; j++) {
      //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
      // Change the bit resolution on each sample
      //cout << tmp_sample[j] << endl;
      fromBitToSampleConversion(&mOutputPacket[(i*mSizeInBytesPerChannel) 
					       + (j*mBitResolutionMode)],
				&tmp_sample[j],
				mBitResolutionMode);
    }
jcaceres's avatar
jcaceres committed
371
  }
372
373
}

374

375
376
377
//*******************************************************************************
void JackAudioInterface::computeNetworkProcessToNetwork()
{
378
379
380
381
  // Input Process (from JACK to NETWORK)
  // ----------------------------------------------------------------
  // Concatenate  all the channels from jack to form packet
  for (int i = 0; i < mNumInChans; i++) {  
382
383
384
385
386
387
    //--------
    // This should be faster for 32 bits
    //std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
    //		mSizeInBytesPerChannel);
    //--------
    sample_t* tmp_sample = mInBuffer[i]; //sample buffer for channel i
388
389
    sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
    sample_t tmp_result;
390
391
392
    for (int j = 0; j < mNumFrames; j++) {
      //std::memcpy(&tmp_sample[j], &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*4)], 4);
      // Change the bit resolution on each sample
393
394
395
396

      // Add the input jack buffer to the buffer resulting from the output process
      tmp_result = tmp_sample[j] + tmp_process_sample[j];
      fromSampleToBitConversion(&tmp_result,
397
398
399
400
				&mInputPacket[(i*mSizeInBytesPerChannel)
					      + (j*mBitResolutionMode)],
				mBitResolutionMode);
    }
401
402
403
  }
  // Send Audio buffer to RingBuffer (these goes out as outgoing packets)
  mInRingBuffer->insertSlotNonBlocking( mInputPacket );
jcaceres's avatar
more    
jcaceres committed
404
405
406
407
}


//*******************************************************************************
408
int JackAudioInterface::processCallback(jack_nframes_t nframes)
jcaceres's avatar
more    
jcaceres committed
409
{
410
  // Get input and output buffers from JACK
411
  //-------------------------------------------------------------------
jcaceres's avatar
more    
jcaceres committed
412
  for (int i = 0; i < mNumInChans; i++) {
413
    // Input Ports are READ ONLY
jcaceres's avatar
more    
jcaceres committed
414
415
416
    mInBuffer[i] = (sample_t*) jack_port_get_buffer(mInPorts[i], nframes);
  }
  for (int i = 0; i < mNumOutChans; i++) {
417
    // Output Ports are WRITABLE
jcaceres's avatar
more    
jcaceres committed
418
419
    mOutBuffer[i] = (sample_t*) jack_port_get_buffer(mOutPorts[i], nframes);
  }
jcaceres's avatar
more    
jcaceres committed
420
  //-------------------------------------------------------------------
jcaceres's avatar
cleanup    
jcaceres committed
421
422
  // TEST: Loopback
  // To test, uncomment and send audio to client input. The same audio
jcaceres's avatar
jcaceres committed
423
  // should come out as output in the first channel
jcaceres's avatar
jcaceres committed
424
  //memcpy (mOutBuffer[0], mInBuffer[0], sizeof(sample_t) * nframes);
jcaceres's avatar
jcaceres committed
425
  //memcpy (mOutBuffer[1], mInBuffer[1], sizeof(sample_t) * nframes);
jcaceres's avatar
more    
jcaceres committed
426
  //-------------------------------------------------------------------
427

428
429
430
  // Allocate the Process Callback
  //-------------------------------------------------------------------
  // 1) First, process incoming packets
431
  // ----------------------------------
432
433
  computeNetworkProcessFromNetwork();

434

435
  // 2) Dynamically allocate ProcessPlugin processes
436
  // -----------------------------------------------
jcaceres's avatar
jcaceres committed
437
  // The processing will be done in order of allocation
438

439
440
  ///\todo Implement for more than one process plugin, now it just works propertely with one.
  /// do it chaining outputs to inputs in the buffers. May need a tempo buffer
441
442
443
444
445
446
447
448
449
450
451
452
453
  for (int i = 0; i < mNumInChans; i++) {
    std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * nframes);
    std::memcpy(mInProcessBuffer[i], mOutBuffer[i], sizeof(sample_t) * nframes);
  }
  for (int i = 0; i < mNumOutChans; i++) {
    std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * nframes);
  }

  for (int i = 0; i < mProcessPlugins.size(); i++) {
    //mProcessPlugins[i]->compute(nframes, mOutBuffer.data(), mInBuffer.data());
    mProcessPlugins[i]->compute(nframes, mInProcessBuffer.data(), mOutProcessBuffer.data());
  }

454

455
  // 3) Finally, send packets to peer
456
  // --------------------------------
457
  computeNetworkProcessToNetwork();
458

jcaceres's avatar
more    
jcaceres committed
459
460
461
  return 0;
}

jcaceres's avatar
jcaceres committed
462
463
464
465
466
467

//*******************************************************************************
int JackAudioInterface::wrapperProcessCallback(jack_nframes_t nframes, void *arg) 
{
  return static_cast<JackAudioInterface*>(arg)->processCallback(nframes);
}
jcaceres's avatar
jcaceres committed
468
469
470


//*******************************************************************************
jcaceres's avatar
more    
jcaceres committed
471
472
// This function quantize from 32 bit to a lower bit resolution
// 24 bit is not working yet
473
474
475
void JackAudioInterface::fromSampleToBitConversion(const sample_t* const input,
						   int8_t* output,
						   const audioBitResolutionT targetBitResolution)
jcaceres's avatar
jcaceres committed
476
{
jcaceres's avatar
More    
jcaceres committed
477
  int8_t tmp_8;
478
  uint8_t tmp_u8; // unsigned to quantize the remainder in 24bits
479
480
481
482
  int16_t tmp_16;
  sample_t tmp_sample;
  sample_t tmp_sample16;
  sample_t tmp_sample8;
jcaceres's avatar
jcaceres committed
483
484
485
  switch (targetBitResolution)
    {
    case BIT8 : 
486
      // 8bit integer between -128 to 127
487
488
489
490
491
      tmp_sample = floor( (*input) * 128.0 ); // 2^7 = 128.0
      tmp_8 = static_cast<int8_t>(tmp_sample);
      std::memcpy(output, &tmp_8, 1); // 8bits = 1 bytes
      break;
    case BIT16 :
492
      // 16bit integer between -32768 to 32767
493
494
495
496
497
      tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
      tmp_16 = static_cast<int16_t>(tmp_sample);
      std::memcpy(output, &tmp_16, 2); // 16bits = 2 bytes
      break;
    case BIT24 :
498
499
500
      // To convert to 24 bits, we first quantize the number to 16bit
      tmp_sample = (*input) * 32768.0; // 2^15 = 32768.0
      tmp_sample16 = floor(tmp_sample);
501
502
      tmp_16 = static_cast<int16_t>(tmp_sample16);

503
504
505
506
507
      // Then we compute the remainder error, and quantize that part into an 8bit number
      // Note that this remainder is always positive, so we use an unsigned integer
      tmp_sample8 = floor ((tmp_sample - tmp_sample16)  //this is a positive number, between 0.0-1.0
			   * 256.0);
      tmp_u8 = static_cast<uint8_t>(tmp_sample8);
508

509
510
      // Finally, we copy the 16bit number in the first 2 bytes,
      // and the 8bit number in the third bite
511
      std::memcpy(output, &tmp_16, 2); // 16bits = 2 bytes
512
      std::memcpy(output+2, &tmp_u8, 1); // 8bits = 1 bytes
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
      break;
    case BIT32 :
      std::memcpy(output, input, 4); // 32bit = 4 bytes
      break;
    }
}


//*******************************************************************************
void JackAudioInterface::fromBitToSampleConversion(const int8_t* const input,
						   sample_t* output,
						   const audioBitResolutionT sourceBitResolution)
{
  int8_t tmp_8;
  uint8_t tmp_u8;
  int16_t tmp_16;
  sample_t tmp_sample;
  sample_t tmp_sample16;
  sample_t tmp_sample8;
  switch (sourceBitResolution)
    {
    case BIT8 : 
      tmp_8 = *input;
      tmp_sample = static_cast<sample_t>(tmp_8) / 128.0;
      std::memcpy(output, &tmp_sample, 4); // 4 bytes
jcaceres's avatar
jcaceres committed
538
539
      break;
    case BIT16 :
540
541
542
      tmp_16 = *( reinterpret_cast<const int16_t*>(input) ); // *((int16_t*) input);
      tmp_sample = static_cast<sample_t>(tmp_16) / 32768.0;
      std::memcpy(output, &tmp_sample, 4); // 4 bytes
jcaceres's avatar
jcaceres committed
543
544
      break;
    case BIT24 :
545
      // We first extract the 16bit and 8bit number from the 3 bytes
546
      tmp_16 = *( reinterpret_cast<const int16_t*>(input) );
547
548
549
      tmp_u8 = *( reinterpret_cast<const uint8_t*>(input+2) );

      // Then we recover the number
jcaceres's avatar
more    
jcaceres committed
550
      tmp_sample16 = static_cast<sample_t>(tmp_16);
551
552
553
      tmp_sample8 = static_cast<sample_t>(tmp_u8) / 256.0;
      tmp_sample =  (tmp_sample16 +  tmp_sample8) / 32768.0;
      std::memcpy(output, &tmp_sample, 4); // 4 bytes
jcaceres's avatar
jcaceres committed
554
555
      break;
    case BIT32 :
556
      std::memcpy(output, input, 4); // 4 bytes
jcaceres's avatar
jcaceres committed
557
558
559
      break;
    }
}
560
561
562
563
564


//*******************************************************************************
void JackAudioInterface::appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin)
{
jcaceres's avatar
jcaceres committed
565
566
567
  /// \todo check that channels in ProcessPlugins are less or same that jack channels
  if ( plugin->getNumInputs() ) {
  }
568
569
  mProcessPlugins.append(plugin);
}