Logo Search packages:      
Sourcecode: jackbeat version File versions  Download package

sequence.c

/*
 *   Jackbeat - JACK sequencer
 *    
 *   Copyright (c) 2004-2005 Olivier Guilyardi <olivier@samalyse.com>
 *    
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   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.
 */

#define SEQUENCE_MASK_ATTACK_DELAY 3.0 // Miliseconds

#include <jack/jack.h>
#include <samplerate.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <assert.h>
#include <math.h>
#include <unistd.h>
#include <config.h>

#include "sequence.h"
#include "error.h"

#ifdef MEMDEBUG
#include "memdebug.h"
#endif

#ifdef DMALLOC
#include "dmalloc.h"
#endif


/********************************
 *    Main data structures      *
 ********************************/

/* SEQUENCE-------------------------------------+
   |                                            |
   | TRACK[0]---------------+       TRACK[n]-+  |
   | |                      |       |        |  |
   | | > frame position     |       |        |  |
   | | > pattern ("beats")  |       |        |  |
   | |                      |       |        |  |
   | | SAMPLE-------------+ |       |        |  |
   | | | (see sample.h)   | |       |        |  |
   | | +------------------+ |       |        |  |
   | |                      | [...] |        |  |
   | | CHANNEL[0]---------+ |       |        |  |
   | | | > jack port      | |       |        |  |
   | | | > jack buffer    | |       |        |  |
   | | +------------------+ |       |        |  |
   | |                      |       |        |  |
   | |       [...]          |       |        |  |
   | |                      |       |        |  |
   | | CHANNEL[n]---------+ |       |        |  |
   | | | > jack port      | |       |        |  |
   | | | > jack buffer    | |       |        |  |
   | | +------------------+ |       |        |  |
   | |                      |       |        |  |
   | +----------------------+       +--------+  |
   |                                            |
   +--------------------------------------------+
*/

typedef struct sequence_track_t
{
  char *beats;
  char *mask;

  sample_t *sample;

  jack_port_t **channels;
  int channels_num;
  jack_nframes_t *frame_pos;
  float **buffers;

  int active_beat;
  int active_mask_beat;
  char name[256];

  char enabled;
  char lock;
  SRC_STATE *sr_converter;
  int sr_converter_type;
  float *sr_converter_buffer;
  double sr_converter_ratio;
  double pitch;
  double volume;
  double mask_envelope;
  int smoothing;
} sequence_track_t;


typedef enum sequence_status_t
{
  SEQUENCE_DISABLED,
  SEQUENCE_ENABLED,
} sequence_status_t;

struct sequence_t
{
  sequence_track_t *tracks;
  int tracks_num;
  int beats_num;
  int measure_len;
  float bpm;
  sequence_status_t status;
  int looping;
  int transport_aware;
  int transport_query;
  jack_nframes_t transport_pos_buf;
  jack_client_t *client;
  jack_nframes_t framerate;
  jack_nframes_t buffer_size;
  char name[32];
  int auto_connect;
  int msqid;
  int synced;
  int sr_converter_default_type;
};

/****************************************************************************
 * Type and macros for messages sent from the main loop to the audio thread *
 ****************************************************************************/

typedef struct sequence_msg_t
{
  long int type;
  char text[128];
} sequence_msg_t;

#define SEQUENCE_MSG_SIZE 128

#define SEQUENCE_MSG_SET_BPM 2
#define SEQUENCE_MSG_SET_TRANSPORT 4
#define SEQUENCE_MSG_SET_LOOPING 5
#define SEQUENCE_MSG_UNSET_LOOPING 6
#define SEQUENCE_MSG_START 7
#define SEQUENCE_MSG_STOP 8
#define SEQUENCE_MSG_REWIND 9
#define SEQUENCE_MSG_SET_SR_RATIO 10
#define SEQUENCE_MSG_SET_VOLUME 11
#define SEQUENCE_MSG_SET_SMOOTHING 12

#define SEQUENCE_MSG_NO_ACK -32

#define SEQUENCE_MSG_ACK 33

#define SEQUENCE_MSG_LOCK_TRACKS 34
#define SEQUENCE_MSG_UNLOCK_TRACKS 35
#define SEQUENCE_MSG_LOCK_SINGLE_TRACK 36
#define SEQUENCE_MSG_UNLOCK_SINGLE_TRACK 37
#define SEQUENCE_MSG_RESIZE 38
#define SEQUENCE_MSG_SET_SAMPLE 39
#define SEQUENCE_MSG_MUTE_TRACK 40
#define SEQUENCE_MSG_ENABLE_MASK 41
#define SEQUENCE_MSG_DISABLE_MASK 42
#define SEQUENCE_MSG_ACK_STOP 43
#define SEQUENCE_MSG_ACK_ENABLE 44
#define SEQUENCE_MSG_ACK_DISABLE 45


/*******************************
 *   Various type and macros   *
 *******************************/

#define SEQUENCE_NESTED 1
#define SEQUENCE_SILENT 2

typedef struct sequence_resize_data_t
{
  sequence_track_t *tracks;
  int tracks_num;
  int beats_num;
  int measure_len;
} sequence_resize_data_t;

int sequence_index = 0;

#define DEBUG(M, ...) { printf("SEQ %s  %s(): ",sequence->name, __func__); printf(M, ## __VA_ARGS__); printf("\n"); }
#define VDEBUG(M, ...) 

int dump_i;
char *dump_s;
#define DUMP(V,S) \
  { \
   dump_s = (char *)V; \
   for (dump_i=0; dump_i < S; dump_i++) printf("%.2X ", dump_s[dump_i]); \
   printf ("\n"); \
  }


/******************************************************
 *   Private functions running inside JACK's thread   *
 ******************************************************/

/* Initialize jack audio data buffers for a given track. */
static void
sequence_get_buffers (sequence_t * sequence, int track,
                      jack_nframes_t nframes)
{
  int j;
  sequence_track_t *t = sequence->tracks + track;
  for (j = 0; j < t->channels_num; j++)
    t->buffers[j] = (float *) jack_port_get_buffer (t->channels[j], nframes);
}

/* Copies nframes frames from a given track's sample to the corresponding jack audio
   buffers, and increases the internal track pointer (frame_pos) accordingly.
   If there's not enough sample data, this function will zero-fill the
   remaining space in the jack buffers */
static int
sequence_copy_sample_data (sequence_t * sequence, int track,
                           jack_nframes_t nframes, char mask,
                           long unsigned int offset_next)
{
  int j, k;
  //char ret = 1;
  SRC_DATA src_data;
  int src_error;
  float *filtered_data;
  jack_nframes_t nframes_avail;
  jack_nframes_t nframes_used;
  jack_nframes_t nframes_filtered;
  jack_nframes_t nframes_required;

  sequence_track_t *t = sequence->tracks + track;

  // What we have to produce and what is available
  nframes_required = nframes;
  nframes_avail = (*(t->frame_pos) < t->sample->frames)
    ? t->sample->frames - *(t->frame_pos) : 0;

  // Performing sample rate conversion
  /*
  if (nframes_avail && nframes_required)
   {
   */
  if (t->sr_converter_type == SEQUENCE_SINC)
   {
    if (*(t->frame_pos) == 0) src_reset (t->sr_converter);
    src_data.data_in = t->sample->data + *(t->frame_pos) * t->channels_num;
    filtered_data = src_data.data_out = t->sr_converter_buffer;
    src_data.input_frames = nframes_avail;
    src_data.output_frames = nframes_required;
    src_data.src_ratio = t->sr_converter_ratio;
    src_data.end_of_input = nframes_avail ? 0 : 1;
    //src_set_ratio (t->sr_converter, t->sr_converter_ratio);
    src_error = src_process (t->sr_converter, &src_data);
    if (src_error)
     {
      DEBUG ("FATAL: Failed to convert the sample rate : %s", 
             src_strerror (src_error));
      exit (1);
     }
    nframes_filtered = src_data.output_frames_gen;
    nframes_used = src_data.input_frames_used;
   }
  else
   {
    for (j=0, k=0; (j < nframes_required) && (k < nframes_avail); j++)
     {
      memcpy (t->sr_converter_buffer + j * t->channels_num,
              t->sample->data + (*(t->frame_pos) + k) * t->channels_num,
              t->channels_num * sizeof (float));
      k = (double) j / t->sr_converter_ratio;
     }
    nframes_filtered = j;
    nframes_used = k;
    filtered_data = t->sr_converter_buffer;
   }
    /*
   } 
  else 
   {
    nframes_filtered = 0;
    nframes_used = 0;
    filtered_data = NULL;
    ret = 0;
   }
 */
  double mask_env_interval = ((double) sequence->framerate * ((double) SEQUENCE_MASK_ATTACK_DELAY / 1000));
  double mask_env_delta = (double) 1 / mask_env_interval;
  double mask_env = t->mask_envelope;  
 
  // Filling jack buffers
  for (j = 0; j < t->channels_num; j++)
    {
      mask_env = t->mask_envelope;
      for (k = 0 ; k < nframes_filtered ; k++)
       {
        if (mask && ((offset_next == 0) || (offset_next - k >
                                            mask_env_interval)))
         {
          if ((*(t->frame_pos) == 0)) mask_env = 1;
          else if (mask_env < 1)
           {
            mask_env += mask_env_delta;
            if (mask_env > 1) mask_env = 1;
           }
         }
        else
         {
          if ((*(t->frame_pos) == 0)) mask_env = 0;
          else if (mask_env > 0) 
           {
            mask_env -= mask_env_delta;
            if (mask_env < 0) mask_env = 0;
           }
         }
          
        t->buffers[j][k] = filtered_data[k * t->channels_num + j] * t->volume * mask_env;
       }
      for (k = nframes_filtered; k < nframes_required; k++) t->buffers[j][k] = 0;

      /*
      if (mask)
       {
        for (k = 0 ; k < nframes_filtered ; k++)
          t->buffers[j][k] = filtered_data[k * t->channels_num + j] * t->volume;
        memset (t->buffers[j] + nframes_filtered, 0, (nframes_required - nframes_filtered) * sizeof (float));
       }
      else
       {
        memset (t->buffers[j], 0, nframes_required * sizeof (float));
       }
       */
      t->buffers[j] += nframes_required;
    }
  t->mask_envelope = mask_env;

  // Increasing this track's frame counter
  *(t->frame_pos) += nframes_used;

  // Returning 1 if we played some sample data, 0 otherwise
  return nframes_filtered;
}

/* zero-fills jack buffers with a length of n frames, for a given track */
static void
sequence_zero_fill (sequence_t * sequence, int track, jack_nframes_t nframes)
{
  int j, k;
  sequence_track_t *t = sequence->tracks + track;

  for (j = 0; j < t->channels_num; j++)
    {
      for (k = 0; k < nframes; k++) t->buffers[j][k] = 0;
      // memset (t->buffers[j], 0, nframes * sizeof (float));
    }
}

static int
sequence_msg_ack (sequence_t * sequence)
{
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_ACK;
  msg.text[0] = '\0';
  return (msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
                  IPC_NOWAIT) == 0);
}

static void
sequence_receive_messages (sequence_t * sequence)
{
  sequence_msg_t msg;
  sequence_track_t *t;
  int i,j;
  sample_t *samq;
  float f;

  if (!sequence->synced)
    {
      DEBUG ("We are not synced at startup. Trying to send ACK.")
      sequence->synced = sequence_msg_ack (sequence);
      DEBUG ("synced status : %d", sequence->synced)
    }
  if (sequence->synced)
    {
      if (msgrcv
          (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
           SEQUENCE_MSG_RESIZE, IPC_NOWAIT) != -1)
        {
          sscanf (msg.text, "tracks=%p tracks_num=%d beats_num=%d measure_len=%d",
                  &(sequence->tracks), 
                  &(sequence->tracks_num),
                  &(sequence->beats_num),
                  &(sequence->measure_len));
          DEBUG ("Resize data received and stored (tracks_num=%d, beats_num=%d, measure_len=%d)",sequence->tracks_num, sequence->beats_num, sequence->measure_len);
          sequence->synced = sequence_msg_ack (sequence);
          DEBUG ("synced status : %d", sequence->synced);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_LOCK_TRACKS, IPC_NOWAIT) != -1)
        {
          int *tl;
          sscanf (msg.text, "tracks=%p", &tl);
          while (*tl != -1)
            sequence->tracks[*(tl++)].lock = 1;
          DEBUG ("Tracks locks data received and stored")
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_UNLOCK_TRACKS, IPC_NOWAIT) != -1)
        {
          int *tl;
          sscanf (msg.text, "tracks=%p", &tl);
          while (*tl != -1)
            sequence->tracks[*(tl++)].lock = 0;
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_LOCK_SINGLE_TRACK, IPC_NOWAIT) != -1)
        {
          int st;
          sscanf (msg.text, "track=%d", &st);
          sequence->tracks[st].lock = 1;
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_UNLOCK_SINGLE_TRACK, IPC_NOWAIT) != -1)
        {
          int st;
          sscanf (msg.text, "track=%d", &st);
          sequence->tracks[st].lock = 0;
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_SET_SAMPLE, IPC_NOWAIT) != -1)
        {
          sscanf (msg.text, "track=%d sample=%p", &i, &samq); 
          t = sequence->tracks + i;
          t->sample = samq;
          *(t->frame_pos) = t->sample->frames;
          t->lock = 0;
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_MUTE_TRACK, IPC_NOWAIT) != -1)
        {
          sscanf (msg.text, "track=%d mute=%d", &i, &j);
          sequence->tracks[i].enabled = j;
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_ENABLE_MASK, IPC_NOWAIT) != -1)
        {
          char *mask;
          sscanf (msg.text, "mask=%p track=%d", &mask, &i);
          sequence->tracks[i].mask = mask;
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_DISABLE_MASK, IPC_NOWAIT) != -1)
        {
          sscanf (msg.text, "track=%d", &i);
          sequence->tracks[i].mask = NULL;
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_ACK_STOP, IPC_NOWAIT) != -1)
        {
          sequence->status = SEQUENCE_DISABLED;
          if (sequence->transport_query) jack_transport_stop (sequence->client);
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_ACK_ENABLE, IPC_NOWAIT) != -1)
        {
          sequence->status = SEQUENCE_ENABLED;
          sequence->synced = sequence_msg_ack (sequence);
        }
      else
        if (msgrcv
            (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
             SEQUENCE_MSG_ACK_DISABLE, IPC_NOWAIT) != -1)
        {
          sequence->status = SEQUENCE_DISABLED;
          sequence->synced = sequence_msg_ack (sequence);
        }

      if (sequence->synced)
        {
          while (msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
                         SEQUENCE_MSG_NO_ACK, IPC_NOWAIT) != -1)
            switch (msg.type)
              {
              case SEQUENCE_MSG_SET_BPM:
                sscanf (msg.text, "bpm=%f", &(sequence->bpm));
                DEBUG ("Setting bpm to %f", sequence->bpm);
                break;
              case SEQUENCE_MSG_SET_TRANSPORT:
                sscanf (msg.text, "aware=%d query=%d",
                        &(sequence->transport_aware),
                        &(sequence->transport_query));
                break;
              case SEQUENCE_MSG_SET_LOOPING:
                sequence->looping = 1;
                break;
              case SEQUENCE_MSG_UNSET_LOOPING:
                sequence->looping = 0;
                break;
              case SEQUENCE_MSG_START:
                sequence->status = SEQUENCE_ENABLED;
                if (sequence->transport_query)
                  jack_transport_start (sequence->client);
                break;
              case SEQUENCE_MSG_STOP:
                sequence->status = SEQUENCE_DISABLED;
                if (sequence->transport_query)
                  jack_transport_stop (sequence->client);
                break;
              case SEQUENCE_MSG_REWIND:
                jack_transport_locate (sequence->client, 0);
                break;
              case SEQUENCE_MSG_SET_SR_RATIO:
                sscanf (msg.text, "track=%d ratio=%f", &i, &f);
                t = sequence->tracks + i;
                t->sr_converter_ratio = f;
                break;
              case SEQUENCE_MSG_SET_VOLUME:
                sscanf (msg.text, "track=%d volume=%f", &i, &f);
                sequence->tracks[i].volume = f;
                break;
              case SEQUENCE_MSG_SET_SMOOTHING:
                sscanf (msg.text, "track=%d status=%d", &i, &j);
                sequence->tracks[i].smoothing = j;
                break;
              }
        }
    }
}

static int
sequence_do_process (sequence_t *sequence, jack_nframes_t position,
                     jack_nframes_t nframes)
{
  int i;
  int current_beat;
  int previous_beat;
  int current_offset;
  jack_nframes_t beat_duration; // should be a double ?
  jack_nframes_t footer = 0;
//  jack_nframes_t shift = 0;
  int beat_trigger = 0;
//  char reset = 0;
  int played_something = 0;

  
  beat_duration =
    60 * sequence->framerate / sequence->bpm / sequence->measure_len;

  current_beat = position / beat_duration;
  current_offset = position % beat_duration;

  if (sequence->looping) 
   {
    if (current_offset == 0) beat_trigger = 1;
    else if (current_offset + nframes > beat_duration)
      {
        current_beat++;
        footer = beat_duration - current_offset;
        current_offset = 0;
        beat_trigger = 1;
      }
    
    if (current_beat >= sequence->beats_num)
      current_beat = current_beat % sequence->beats_num;
   }
  else if (current_beat < sequence->beats_num && current_offset == 0)
   {
      beat_trigger = 1;
   }
  else if (current_offset + nframes > beat_duration && current_beat <
           (sequence->beats_num - 1))
    {
      current_beat++;
      footer = beat_duration - current_offset;
      current_offset = 0;
      beat_trigger = 1;
    }

  sequence_track_t *t;
  char mask;
  for (i = 0; i < sequence->tracks_num; i++)
    {
      t = sequence->tracks + i;
      if (!(t->lock) && (sequence->status == SEQUENCE_ENABLED))
        {
          sequence_get_buffers (sequence, i, nframes);
          if (t->sample != NULL)
            {
              if (beat_trigger)
                {
                  previous_beat = (current_beat > 0) 
                   ? current_beat - 1 : sequence->beats_num - 1;
                  mask = (t->mask) ? t->mask[previous_beat] : 1;
                  if (sequence_copy_sample_data (sequence, i, footer, 
                                                 mask & t->enabled, footer)) 
                    played_something = 1;
                  

                  if (t->beats[current_beat])
                    {
                      *(t->frame_pos) = 0;
                      t->active_beat = current_beat;
                    }
                }
             
              // Looking up next active beat
              int dist;
              if ((!t->smoothing) || t->active_beat == -1) dist = -1;
              else
               {
                for (dist = 1; 
                     (current_beat + dist < sequence->beats_num) 
                      && (!t->beats[current_beat + dist]);
                     dist++)
                  ;
                if (current_beat + dist == sequence->beats_num)
                 {
                  if (!sequence->looping) dist = -1;
                  else
                   {
                    for ( ; (dist <= sequence->beats_num) 
                              && (!t->beats[current_beat + dist - sequence->beats_num]);
                          dist++)
                      ;
                    if (!t->beats[current_beat + dist - sequence->beats_num])
                      dist = -1;
                   }
                 }
               }
              
              long unsigned int offset_next = 0;
              if (dist != -1)
               {
                offset_next = beat_duration - current_offset + (dist - 1) * beat_duration; 
                
               }
              //if (t->enabled) DEBUG("Smoothing : ofs: %ld/ cb: %d / co: %d / ab: %d", offset_next, current_beat, current_offset, t->active_beat);
                   
              if ((t->active_beat != -1) && (!t->beats[t->active_beat])) 
               {
                *(t->frame_pos) = t->sample->frames;
                if (t->sr_converter != NULL) src_reset (t->sr_converter);
               }
              
              mask = (t->mask != NULL) ? t->mask[current_beat] : 1;
              if (!sequence_copy_sample_data
                  (sequence, i, nframes - footer, mask & t->enabled, offset_next)) 
                t->active_beat = -1;
              else played_something = 1;
              t->active_mask_beat = ((t->active_beat != -1) && t->mask && mask
                                     && (current_beat < sequence->beats_num)) ? current_beat : -1;
            }
          else
            sequence_zero_fill (sequence, i, nframes);
        }
    }

  return (played_something || (current_beat < sequence->beats_num)) ? 1 : 0;
}

static int
sequence_process (jack_nframes_t nframes, void *data)
{
  int i;
  jack_position_t info;
  sequence_t *sequence = (sequence_t *) data;
  sequence_receive_messages (sequence);

  if (!sequence->tracks_num) return 0;
  
  if ((jack_transport_query (sequence->client,
                            &info) == JackTransportRolling)
      && sequence->status == SEQUENCE_ENABLED)
   {
    sequence_do_process (sequence, info.frame, nframes);
   }
  else
   {
     // FIXME: What if a track is locked ?
     for (i=0; i < sequence->tracks_num; i++)
       if ((sequence->tracks+i)->channels_num)
        {
          sequence_get_buffers (sequence, i, nframes);
          sequence_zero_fill (sequence, i, nframes);
        }
   }
  return 0;
}

/******************************************************
 *   Private functions running inside the main loop   *
 *   (these are called by the public functions)       *
 ******************************************************/

static void
sequence_init (sequence_t * sequence)
{
  sequence->tracks = NULL;
  sequence->tracks_num = 0;
  sequence->beats_num = 0;
  sequence->measure_len = 0;
  sequence->bpm = 100;
  sequence->status = SEQUENCE_DISABLED;
  sequence->looping = 1;
  sequence->transport_aware = 1;
  sequence->transport_query = 1;
  sequence->transport_pos_buf = 0;
  sequence->client = NULL;
  sequence->framerate = 0;
  sequence->name[0] = '\0';
  sequence->auto_connect = 1;
  sequence->msqid = 0;
  sequence->synced = 1;
  sequence->sr_converter_default_type = SEQUENCE_LINEAR;
}

static void
sequence_track_init (sequence_track_t *track)
{
  track->beats = NULL;
  track->mask = NULL;
  track->sample = NULL;
  track->channels = NULL;
  track->channels_num = 1;
  track->frame_pos = NULL;
  track->buffers = NULL;
  track->active_beat = -1;
  track->active_mask_beat = -1;
  track->name[0] = '\0';
  track->enabled = 1;
  track->lock = 0;
  track->sr_converter = NULL;
  track->sr_converter_type = -1;
  track->sr_converter_buffer = NULL;
  track->sr_converter_ratio = 1;
  track->pitch = 0;
  track->volume = 1;
  track->mask_envelope = 1;
  track->smoothing = 1;
}

static void
sequence_connect_playback (sequence_t * sequence, sequence_track_t *track)
{
  const char **ports;
  int i;
  const char **c = NULL;

  if ((ports = jack_get_ports (sequence->client, NULL, NULL,
                               JackPortIsPhysical | JackPortIsInput)))
    {
      for (i = 0;
           i < 2 && i < track->channels_num && ports[i]
           && !(c =
                jack_port_get_connections (track->channels[i])); 
           i++);
      if (c)
        {
          free (c);
          return;
        }
      for (i = 0;
           i < 2 && i < track->channels_num && ports[i]; i++)
        {
          jack_connect (sequence->client,
                        jack_port_name (track->channels[i]),
                        ports[i]);
        }
      free (ports);
    }

}

/*********************************
 *       Public functions        *
 *********************************/

//void sequence_resize (sequence_t * sequence, int tracks_num, int beats_num, int measure_len);

sequence_t *
sequence_new (char *name, int *error) 
{
  sequence_t *sequence;

  sequence = calloc (1, sizeof (sequence_t));
  DEBUG ("index: %d", sequence_index); 
  sequence_init (sequence);
  DEBUG ("name : %s", name);
  strcpy (sequence->name, name);

  /* Creating message queue */
  errno = 0;
  /*
  key_t k;
  if ((k = ftok (".", ++sequence_index)) == -1)
    {
      perror (NULL);
      DEBUG ("Cant get IPC key (path: \".\", index: %d)", sequence_index)
      free (sequence);
      *error = ERR_SEQUENCE_INTERNAL;
      return NULL;
    }
  else 
    {
      DEBUG("Got IPC key %d (path: \".\", index: %d)", k, sequence_index)
    }
    */

  if ((sequence->msqid = msgget (IPC_PRIVATE, IPC_CREAT | 0666)) == -1)
    {
      DEBUG ("Cant init message queue (errno: %d)", errno)
      perror (NULL);
      free (sequence);
      *error = ERR_SEQUENCE_MSQ;
      return NULL;
    }
  DEBUG ("Created message queue %d", sequence->msqid);

  /* Emptying message queue */
  sequence_msg_t msg;
  while (msgrcv (sequence->msqid, &msg, SEQUENCE_MSG_SIZE, 0, IPC_NOWAIT) !=
         -1);

  /* Creating JACK client */
  DEBUG ("Initializing JACK");
  if ((sequence->client = jack_client_new (sequence->name)) == 0)
    {
      fprintf (stderr, "jack server not running?\n");
      sequence_destroy (sequence);
      *error = ERR_SEQUENCE_JACK_CONNECT;
      return NULL;
    }

  jack_set_process_callback (sequence->client, sequence_process,
                             (void *) sequence);

  sequence->buffer_size = jack_get_buffer_size (sequence->client);
  
  if (jack_activate (sequence->client))
    {
      fprintf (stderr, "cannot activate client\n");
      sequence_destroy (sequence);
      *error = ERR_SEQUENCE_JACK_ACTIVATE;
      return NULL;
    }
  sequence->framerate = jack_get_sample_rate (sequence->client);
  DEBUG ("Jack Framerate : %d", sequence->framerate);

  sequence_resize (sequence, 4, 16, 4, 0);
  
  return sequence;
}

void
sequence_rewind (sequence_t * sequence)
{
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_REWIND;
  msg.text[0] = '\0';
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}

void
sequence_start (sequence_t * sequence)
{
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_START;
  msg.text[0] = '\0';
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}

void
sequence_stop (sequence_t * sequence)
{
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_STOP;
  msg.text[0] = '\0';
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}

void
sequence_destroy (sequence_t * sequence)
{
  int i;
  sequence_track_t *t;
  if (sequence->client != NULL)
   {
    jack_deactivate (sequence->client);
    jack_client_close (sequence->client);
   }
  // FIXME: May need to sync in here
  if (sequence->msqid) msgctl (sequence->msqid, IPC_RMID, NULL);
  for (i=0; i < sequence->tracks_num; i++)
   {
    t = sequence->tracks + i;
    free (t->beats);
    if (t->mask) free (t->mask);
    free (t->channels);
    free (t->frame_pos);
    free (t->buffers);
   }
  if (sequence->tracks != NULL) free (sequence->tracks);
  free (sequence);
}

void
sequence_resize (sequence_t * sequence, int tracks_num, int beats_num,
                 int measure_len, int duplicate_beats)
{
  int i, j;
  char s[128];
  sequence_msg_t msg;
  
  /* Asks the audio thread to avoid playing (lock) tracks whose jack ports are
     about to be unregistered */
  if (tracks_num < sequence->tracks_num)
    {
      int *tl = calloc (sequence->tracks_num - tracks_num + 1, sizeof (int));
      for (i = tracks_num, j = 0; i < sequence->tracks_num; i++)
        tl[j++] = i;
      tl[j] = -1;
      DEBUG("Requiring tracks locks")
      msg.type = SEQUENCE_MSG_LOCK_TRACKS;
      sprintf (msg.text, "tracks=%p", tl);
      msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
      msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
              SEQUENCE_MSG_ACK, 0);
      DEBUG("Tracks locks ack'ed. Freeing temporary data.")
      free (tl);
    }

  /* Duplicates all tracks data so that we don't interfer with the audio thread */
  sequence_track_t *new_tracks = calloc (tracks_num, sizeof
                                         (sequence_track_t));
  int tn = (sequence->tracks_num > tracks_num) ? tracks_num :
    sequence->tracks_num;
  memcpy (new_tracks, sequence->tracks, tn * sizeof (sequence_track_t));

  /* Unregister jack ports and wipes associated tracks data if tracks_num decreases. */
  sequence_track_t *t;
  for (i = tracks_num; i < sequence->tracks_num; i++)
    {
      t = sequence->tracks + i;
      for (j = 0; j < t->channels_num; j++)
        jack_port_unregister (sequence->client, t->channels[j]);
      free (t->frame_pos);
      free (t->channels);
      free (t->buffers);
      if (t->sr_converter != NULL)
       {
        src_delete (t->sr_converter);
        t->sr_converter = NULL;
        free (t->sr_converter_buffer);
        t->sr_converter_buffer = NULL;
       }
    }

  /* Register jack ports and allocate new tracks data if tracks_num increases */
  for (i = sequence->tracks_num; i < tracks_num; i++)
    {
      DEBUG("Initializing track %d",i);
      t = new_tracks + i;
      sequence_track_init (t);
      t->channels = calloc (t->channels_num, sizeof (jack_port_t *));
      t->buffers = calloc (t->channels_num, sizeof (float *));
      t->frame_pos = malloc (sizeof (jack_nframes_t));
      *(t->frame_pos) = 0;
      sprintf (t->name, "track%d", i);
      t->mask = NULL;
      for (j = 0; j < t->channels_num; j++)
        {
          if (t->channels_num == 1)
            strcpy (s, t->name);
          else
          sprintf (s, "%s_%d", t->name, j + 1);
          t->channels[j] =
            jack_port_register (sequence->client, s, JACK_DEFAULT_AUDIO_TYPE,
                                JackPortIsOutput, 0);
        }
      if (sequence->auto_connect) sequence_connect_playback (sequence, t);
    }

  /* Resize beats memory */
  for (i = 0; i < tracks_num; i++)
    {
      (new_tracks + i)->beats = calloc (beats_num, 1);
      if (i < sequence->tracks_num)
       {
        if (sequence->tracks[i].mask)
         {
          (new_tracks + i)->mask = calloc (beats_num, 1);
          memset ((new_tracks + i)->mask, 1, beats_num);
         }
        if (sequence->beats_num > beats_num)
         {
          memcpy ((new_tracks + i)->beats, (sequence->tracks + i)->beats, beats_num);
          if (sequence->tracks[i].mask)
            memcpy ((new_tracks + i)->mask, (sequence->tracks + i)->mask, beats_num);
         }
        else
         {
          if (duplicate_beats)
           {
            int bn;
            for (j=0; j < beats_num; j += sequence->beats_num)
             {
              bn = (beats_num - j) < sequence->beats_num 
                 ? beats_num - j
                 : sequence->beats_num;
              memcpy ((new_tracks + i)->beats + j, 
                      (sequence->tracks + i)->beats, bn);
              if (sequence->tracks[i].mask)
                memcpy ((new_tracks + i)->mask + j, (sequence->tracks + i)->mask, bn);
             }
           }
          else
            memcpy ((new_tracks + i)->beats, (sequence->tracks + i)->beats, 
                    sequence->beats_num);
            if (sequence->tracks[i].mask)
              memcpy ((new_tracks + i)->mask, (sequence->tracks + i)->mask, 
                      sequence->beats_num);
         }
       }
    }

  /* Packs all that and sends it to the audio thread */
  sprintf (msg.text, "tracks=%p tracks_num=%d beats_num=%d measure_len=%d",
            new_tracks, tracks_num, beats_num, measure_len);

  DEBUG("Sending resize message of length : %d",strlen(msg.text));
  sequence_track_t *old_tracks = sequence->tracks;
  int old_tracks_num = sequence->tracks_num;

  msg.type = SEQUENCE_MSG_RESIZE;
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
  msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, SEQUENCE_MSG_ACK,
          0);

  /* Cleans up old data */
  DEBUG("Cleaning up old tracks data at %p", old_tracks);
  if (old_tracks)
    {
      for (i = 0; i < old_tracks_num; i++)
       {
        free ((old_tracks + i)->beats);
        if (old_tracks[i].mask) free ((old_tracks + i)->mask);
       }
      free (old_tracks);
    }
  
  DUMP(sequence->tracks->beats, sequence->beats_num);
}

char *
sequence_get_name (sequence_t * sequence)
{
  return sequence->name;
}

void
sequence_set_transport (sequence_t * sequence, char respond, char query)
{
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_SET_TRANSPORT;
  sprintf (msg.text, "aware=%d query=%d", respond, query); 
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}

int
sequence_is_playing (sequence_t * sequence)
{
  jack_position_t t;

  return (sequence->status == SEQUENCE_ENABLED &&
          (!sequence->transport_aware ||
           jack_transport_query (sequence->client,
                                 &t) == JackTransportRolling));
}

int
sequence_get_active_beat (sequence_t * sequence, int track)
{
  return sequence->tracks[track].active_beat;
}

int
sequence_get_active_mask_beat (sequence_t * sequence, int track)
{
  return sequence->tracks[track].active_mask_beat;
}

void
sequence_unset_looping (sequence_t * sequence)
{
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_UNSET_LOOPING;
  msg.text[0] = '\0';
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}

int
sequence_is_looping (sequence_t * sequence)
{
  return sequence->looping;
}

void
sequence_set_looping (sequence_t * sequence)
{
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_SET_LOOPING;
  msg.text[0] = '\0';
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}


void
sequence_set_auto_connect (sequence_t * sequence, char status)
{
  sequence->auto_connect = status;
}

char
sequence_is_auto_connecting (sequence_t * sequence)
{
  return sequence->auto_connect;
}

float
sequence_get_bpm (sequence_t * sequence)
{
  return sequence->bpm;
}

void
sequence_set_bpm (sequence_t * sequence, float bpm)
{
  DEBUG("Setting bpm to : %f", bpm);
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_SET_BPM;
  sprintf (msg.text, "bpm=%f", bpm);
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}

void
sequence_set_beat (sequence_t * sequence, int track, int beat, char status)
{
  DEBUG ("sequence: %p, track: %d, beat:%d, status: %d", sequence, track,
         beat, status)
  sequence->tracks[track].beats[beat] = status;
}

int
sequence_get_tracks_num (sequence_t * sequence)
{
  return sequence->tracks_num;
}

int
sequence_get_beats_num (sequence_t * sequence)
{
  return sequence->beats_num;
}

int
sequence_get_measure_len (sequence_t * sequence)
{
  return sequence->measure_len;
}

char
sequence_get_beat (sequence_t * sequence, int track, int beat)
{
  return (sequence->tracks + track)->beats[beat];
}

char *
sequence_get_track_name (sequence_t * sequence, int track)
{
  return (sequence->tracks + track)->name;
}

int
sequence_track_name_exists (sequence_t *sequence, char *name)
{
  int i;
  for (i=0; i < sequence->tracks_num; i++)
   {
    if (!strcmp ((sequence->tracks + i)->name, name))
      return 1;
   }
  return 0;
}

sample_t *
sequence_get_sample (sequence_t * sequence, int track)
{
  return (sequence->tracks + track)->sample;
}

void
sequence_set_sample (sequence_t * sequence, int track, sample_t * sample)
{
  sequence_msg_t msg;
  sequence_track_t *t = sequence->tracks + track;
  char s[128];
  int j, sr_converter_error;
  if (t->channels_num != sample->channels_num)
    {
      msg.type = SEQUENCE_MSG_LOCK_SINGLE_TRACK;
      sprintf (msg.text, "track=%d", track);
      msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
      msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE,
              SEQUENCE_MSG_ACK, 0);
      if (t->channels_num) {
        for (j = 0; j < t->channels_num; j++)
          jack_port_unregister (sequence->client, t->channels[j]);
        free (t->channels);
        free (t->buffers);
      }
      t->channels_num = sample->channels_num;
      t->channels = calloc (t->channels_num, sizeof (jack_port_t *));
      t->buffers = calloc (t->channels_num, sizeof (float *));
      for (j = 0; j < t->channels_num; j++)
        {
          if (t->channels_num == 1)
            strcpy (s, t->name);
          else
            sprintf (s, "%s_%d", t->name, j + 1);
          t->channels[j] =
            jack_port_register (sequence->client, s, JACK_DEFAULT_AUDIO_TYPE,
                                JackPortIsOutput, 0);
        }
      if (t->sr_converter != NULL) 
       {
        src_delete (t->sr_converter);
        t->sr_converter = NULL;
        free (t->sr_converter_buffer);
        t->sr_converter_buffer = NULL;
       }
    }
  
  if (t->sr_converter_type == -1) 
    t->sr_converter_type = sequence->sr_converter_default_type;
  
  if (t->sr_converter_type == SEQUENCE_SINC)
   {
    if (t->sr_converter == NULL) 
     {
      DEBUG("Creating SR converter for %d channels", t->channels_num);
      t->sr_converter = src_new (SRC_SINC_FASTEST, t->channels_num,
                                   &sr_converter_error);
      if (t->sr_converter == NULL)
       {
        DEBUG ("FATAL: Cannot create the sample rate converter : %s", 
               src_strerror (sr_converter_error));
        exit(1);
       }
     }
    else 
     {
      sr_converter_error = src_reset (t->sr_converter);
      if (sr_converter_error)
        DEBUG ("Cannot reset the sample rate converter : %s", 
               src_strerror (sr_converter_error));
     }
   }
  if (t->sr_converter_buffer == NULL)
    t->sr_converter_buffer = calloc (sequence->buffer_size * t->channels_num,
                                     sizeof (float));
  t->sr_converter_ratio = (double) sequence->framerate 
                          / (double) sample->framerate 
                          / pow (2, t->pitch / 12);
                                 
  msg.type = SEQUENCE_MSG_SET_SAMPLE;
  sprintf (msg.text, "track=%d sample=%p", track, sample);
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
  msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, SEQUENCE_MSG_ACK,
          0);
  if (sequence->auto_connect) sequence_connect_playback (sequence, t);
}

void
sequence_set_track_name (sequence_t * sequence, int track, char *name)
{
  int j;
  char s[128];
  sequence_track_t *t = sequence->tracks + track;
  strcpy (t->name, name);
  for (j = 0; j < t->channels_num; j++)
    {
      if (t->channels_num == 1)
        strcpy (s, t->name);
      else
        sprintf (s, "%s_%d", t->name, j + 1);
      jack_port_set_name (t->channels[j], s);
    }
}

int
sequence_get_sample_usage (sequence_t * sequence, sample_t * sample)
{
  int i;
  int r = 0;
  for (i = 0; i < sequence->tracks_num; i++) 
   {
    if ((sequence->tracks + i)->sample) {
      DEBUG ("Track %d has sample : %s", i, (sequence->tracks +
                                           i)->sample->name);
    }
    if ((sequence->tracks + i)->sample == sample) r++;
   }
  DEBUG ("Usage for sample \"%s\" is : %d", sample->name, r);
  return r;
}

sequence_track_type_t
sequence_get_track_type (sequence_t * sequence, int track)
{
  sequence_track_type_t r;
  sequence_track_t *t = (sequence->tracks + track);
  if (t->sample)
    r = SAMPLE;
  else
    r = EMPTY;
  return r;
}


void
sequence_mute_track (sequence_t * sequence, char status, int track)
{
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_MUTE_TRACK;
  sprintf (msg.text, "track=%d mute=%d", track, (status) ? 0 : 1);
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
  msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, SEQUENCE_MSG_ACK,
          0);
}

char
sequence_track_is_muted (sequence_t * sequence, int track)
{
  DEBUG("track %d is %s", track, (sequence->tracks[track].enabled) ? "not muted" : "muted");
  return (!sequence->tracks[track].enabled);
}

jack_nframes_t 
sequence_get_framerate (sequence_t *sequence)
{
  return sequence->framerate;
}

void
sequence_enable_mask (sequence_t *sequence, int track)
{
  if (!sequence->tracks[track].mask)
   {
    char *mask = calloc (sequence->beats_num, 1);
    memset (mask, 1, sequence->beats_num);
  
    sequence_msg_t msg;
    msg.type = SEQUENCE_MSG_ENABLE_MASK;
    sprintf (msg.text, "mask=%p track=%d", mask, track);
    msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
    msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, SEQUENCE_MSG_ACK,
            0);
   }
}

void
sequence_disable_mask (sequence_t *sequence, int track)
{
  if (sequence->tracks[track].mask)
   {
    char *old_mask = sequence->tracks[track].mask;
  
    sequence_msg_t msg;
    msg.type = SEQUENCE_MSG_DISABLE_MASK;
    sprintf (msg.text, "track=%d", track);
    msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
    msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, SEQUENCE_MSG_ACK,
            0);
    free (old_mask);
   }
}

void
sequence_set_mask_beat (sequence_t * sequence, int track, int beat, char status)
{
  DEBUG ("(mask)sequence: %p, track: %d, beat:%d, status: %d", sequence, track,
         beat, status)
  if (sequence->tracks[track].mask)
    sequence->tracks[track].mask[beat] = status;
}

char
sequence_get_mask_beat (sequence_t * sequence, int track, int beat)
{
  return sequence->tracks[track].mask[beat];
}

int
sequence_is_enabled_mask (sequence_t *sequence, int track)
{
  return (sequence->tracks[track].mask) ? 1 : 0;
}

void
sequence_set_pitch (sequence_t *sequence, int track, double pitch)
{
  DEBUG ("Setting pitch on track %d to : %f", track, pitch);
  sequence_msg_t msg;
  sequence->tracks[track].pitch = pitch;
  if (sequence->tracks[track].sample != NULL)
   {
    double ratio = (double) sequence->framerate 
                   / (double) sequence->tracks[track].sample->framerate 
                   / pow (2, pitch / 12);
    msg.type = SEQUENCE_MSG_SET_SR_RATIO;
    sprintf (msg.text, "track=%d ratio=%f", track, ratio);
    msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
   }
}

double
sequence_get_pitch (sequence_t *sequence, int track)
{
  return sequence->tracks[track].pitch;
}

void
sequence_set_volume (sequence_t *sequence, int track, double volume)
{
  DEBUG ("Setting volume on track %d to : %f", track, volume);
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_SET_VOLUME;
  sprintf (msg.text, "track=%d volume=%f", track, volume);
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}

double
sequence_get_volume (sequence_t *sequence, int track)
{
  return sequence->tracks[track].volume;
}

void
sequence_set_smoothing (sequence_t *sequence, int track, int status)
{
  DEBUG ("Setting smoothing on track %d to : %d", track, status);
  sequence_msg_t msg;
  msg.type = SEQUENCE_MSG_SET_SMOOTHING;
  sprintf (msg.text, "track=%d status=%d", track, status);
  msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
}

int
sequence_get_smoothing (sequence_t *sequence, int track)
{
  return sequence->tracks[track].smoothing;
}


void 
sequence_set_resampler_type (sequence_t * sequence, int type)
{
  if (type == -1) return;
  DEBUG ("Setting resampler type to : %d", type);
  sequence_msg_t msg;
  int restart = 0;
  if (sequence->status == SEQUENCE_ENABLED)
   {
    msg.type = SEQUENCE_MSG_ACK_DISABLE;
    msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
    msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, SEQUENCE_MSG_ACK,
            0);
    restart = 1;
   }

  sequence->sr_converter_default_type = type;
  int i;
  for (i=0; i < sequence->tracks_num; i++)
   {
    sequence_track_t *t = sequence->tracks + i;
    t->sr_converter_type = type;
    int sr_converter_error;
    if (t->sr_converter != NULL) 
     {
      DEBUG ("Destroying SR converter on track %d", i);
      src_delete (t->sr_converter);
      t->sr_converter = NULL;
     }
    if (type == SEQUENCE_SINC)
     {
      DEBUG ("Creating SR converter of type %d with %d channel(s) on track %d",
             SRC_SINC_FASTEST, t->channels_num, i);
      t->sr_converter = src_new (SRC_SINC_FASTEST, t->channels_num, &sr_converter_error);
     }
   }

  //sequence_rewind (sequence);
  if (restart)
   {
    msg.type = SEQUENCE_MSG_ACK_ENABLE;
    msgsnd (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, 0);
    msgrcv (sequence->msqid, (void *) &msg, SEQUENCE_MSG_SIZE, SEQUENCE_MSG_ACK,
            0);
   }
  
}

int
sequence_get_resampler_type (sequence_t *sequence)
{
  return sequence->sr_converter_default_type;
}

Generated by  Doxygen 1.6.0   Back to index