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

seqdriver.cpp

#include <stdio.h>
#include <stdlib.h>
#include <qstring.h>
#include <qsocketnotifier.h>
#include <alsa/asoundlib.h>
#include "midiarp.h"
#include "main.h"
#include "seqdriver.h"

SeqDriver::SeqDriver(QPtrList<MidiArp> *p_midiArpList, QWidget *parent, const char *name) : QWidget(parent, name) {

  midiArpList = p_midiArpList; 
  portCount = 0;
  discardUnmatched = false;
  portUnmatched = 0;
  if (snd_seq_open(&seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
    fprintf(stderr, "Error opening ALSA sequencer.\n");
    exit(1);  }
  snd_seq_set_client_name(seq_handle, "QMidiArp");
  clientid = snd_seq_client_id(seq_handle);
  if ((portid_in = snd_seq_create_simple_port(seq_handle, "QMidiArp",
                                        SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
                                        SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
    fprintf(stderr, "Error creating sequencer port.\n");
    exit(1);
  }
  snd_seq_set_client_pool_output(seq_handle, SEQPOOL);                                     
  tempo = 100;
  grooveTick = 0;
  grooveVelocity = 0;
  grooveLength = 0;
  runArp = false;
  startQueue = false;
  runQueueIfArp = true;
  initArpQueue();
  setQueueTempo(100);
}

SeqDriver::~SeqDriver(){
}

void SeqDriver::registerPorts(int num) {

  int l1;

  portCount = num;
  for (l1 = 0; l1 < portCount; l1++) {
    if ((portid_out[l1] = snd_seq_create_simple_port(seq_handle, "QMidiArp",
                                   SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
                                   SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
      fprintf(stderr, "Error creating sequencer port.\n");
      exit(1);
    }
  }                                    
  initSeqNotifier();
}

void SeqDriver::initSeqNotifier() {

  int alsaEventFd = 0;

  struct pollfd pfd[1];
  snd_seq_poll_descriptors(seq_handle, pfd, 1, POLLIN);
  alsaEventFd = pfd[0].fd;
  seqNotifier = new QSocketNotifier(alsaEventFd, QSocketNotifier::Read);
  QObject::connect(seqNotifier, SIGNAL(activated(int)),
                   this, SLOT(procEvents(int)));
}


int SeqDriver::getPortCount() {

  return(portCount);
}

void SeqDriver::procEvents(int fd) {

  int l1, l2;
  snd_seq_event_t *evIn, evOut;
  int note[MAXCHORD], velocity[MAXCHORD];
  int length;
  snd_seq_tick_time_t noteTick, nextEchoTick;
  bool unmatched, foundEcho, isNew;

  do {
    snd_seq_event_input(seq_handle, &evIn);
    if (runArp && ((evIn->type == SND_SEQ_EVENT_ECHO) || startQueue)) {
      tick = get_tick();
      startQueue = false;
      nextEchoTick = 0;
      foundEcho = false;
      
      for (l1 = 0; l1 < midiArpList->count(); l1++) {
        midiArpList->at(l1)->newRandomValues();
        midiArpList->at(l1)->getCurrentNote(tick, &noteTick, note, velocity, &length, &isNew);
        if (isNew && velocity[0]) {
          l2 = 0;
          while(note[l2] >= 0) {
            snd_seq_ev_clear(&evOut);
            snd_seq_ev_set_note(&evOut, 0, note[l2], velocity[l2], length);
            evOut.data.control.channel = midiArpList->at(l1)->channelOut;
            snd_seq_ev_schedule_tick(&evOut, queue_id,  0, noteTick);
            snd_seq_ev_set_subs(&evOut);  
            snd_seq_ev_set_source(&evOut, portid_out[midiArpList->at(l1)->portOut]);
            snd_seq_event_output_direct(seq_handle, &evOut);
            l2++;
          } 
        } 
        midiArpList->at(l1)->getNextNote(tick, &noteTick, note, velocity, &length, &isNew);
        if (isNew) {
          if (!foundEcho) {
            foundEcho = true;
            nextEchoTick = noteTick;
          } else {
            if (noteTick < nextEchoTick) {
              nextEchoTick = noteTick;
            }
          }
        } 
      }            
      snd_seq_ev_clear(evIn);
      evIn->type = SND_SEQ_EVENT_ECHO;
      snd_seq_ev_schedule_tick(evIn, queue_id,  0, nextEchoTick);
      snd_seq_ev_set_dest(evIn, clientid, portid_in);
      snd_seq_event_output_direct(seq_handle, evIn);
      
    } else {
      emit midiEvent(evIn);
      unmatched = true;
      if ((evIn->type == SND_SEQ_EVENT_NOTEON) || (evIn->type == SND_SEQ_EVENT_NOTEOFF)) {
        for (l1 = 0; l1 < midiArpList->count(); l1++) {
          if (midiArpList->at(l1)->isArp(evIn)) {
            unmatched = false;
            if ((evIn->type == SND_SEQ_EVENT_NOTEON) && (evIn->data.note.velocity > 0)) {
              midiArpList->at(l1)->addNote(evIn);
            } else {
              midiArpList->at(l1)->removeNote(evIn);  
            }  
          }  
        }
      }
      if (!discardUnmatched && unmatched) {
        snd_seq_ev_set_subs(evIn);  
        snd_seq_ev_set_direct(evIn);
        snd_seq_ev_set_source(evIn, portid_out[portUnmatched]);
        snd_seq_event_output_direct(seq_handle, evIn);
      }
    }  
  } while (snd_seq_event_input_pending(seq_handle, 0) > 0);  
}

void SeqDriver::setDiscardUnmatched(bool on) {

  discardUnmatched = on;
}

void SeqDriver::setPortUnmatched(int id) {

  portUnmatched = id;
}

void SeqDriver::initArpQueue() {

  queue_id = snd_seq_alloc_queue(seq_handle);
}

void SeqDriver::setQueueTempo(int bpm) {

  snd_seq_queue_tempo_t *queue_tempo;
  int msec_tempo;
  
  snd_seq_queue_tempo_malloc(&queue_tempo);
  msec_tempo = (int)(6e7 / (double)bpm);
  snd_seq_queue_tempo_set_tempo(queue_tempo, msec_tempo);
  snd_seq_queue_tempo_set_ppq(queue_tempo, TICKS_PER_QUARTER);
  snd_seq_set_queue_tempo(seq_handle, queue_id, queue_tempo);
  snd_seq_queue_tempo_free(queue_tempo);
  tempo = bpm;
}

snd_seq_tick_time_t SeqDriver::get_tick() {

  snd_seq_queue_status_t *status;
  snd_seq_tick_time_t current_tick;
      
  snd_seq_queue_status_malloc(&status);
  snd_seq_get_queue_status(seq_handle, queue_id, status);
  current_tick = snd_seq_queue_status_get_tick_time(status);
  snd_seq_queue_status_free(status);
  return(current_tick);
}

void SeqDriver::runQueue(bool on) {

  runQueueIfArp = on;
}

void SeqDriver::setQueueStatus(bool run) {

  int l1;
  snd_seq_event_t evOut;

  if (run) {
    runArp = true;
    startQueue = true;
    snd_seq_start_queue(seq_handle, queue_id, NULL);
    snd_seq_drain_output(seq_handle);
    tick = get_tick();
    snd_seq_ev_clear(&evOut);
    evOut.type = SND_SEQ_EVENT_NOTEOFF;
    evOut.data.note.note = 0;
    evOut.data.note.velocity = 0;
    snd_seq_ev_schedule_tick(&evOut, queue_id,  0, tick);
    snd_seq_ev_set_dest(&evOut, clientid, portid_in);
    snd_seq_event_output_direct(seq_handle, &evOut);
    for (l1 = 0; l1 < midiArpList->count(); l1++) {
      midiArpList->at(l1)->initArpTick(tick);
    }
  } else {
    runArp = false;
//    snd_seq_drop_output(seq_handle);
   
    snd_seq_remove_events_t *remove_ev;

    snd_seq_remove_events_malloc(&remove_ev);
    snd_seq_remove_events_set_queue(remove_ev, queue_id);
    snd_seq_remove_events_set_condition(remove_ev, SND_SEQ_REMOVE_OUTPUT | SND_SEQ_REMOVE_IGNORE_OFF);
    snd_seq_remove_events(seq_handle, remove_ev);
    snd_seq_remove_events_free(remove_ev);

    snd_seq_stop_queue(seq_handle, queue_id, NULL);
  }  
}

void SeqDriver::setGrooveTick(int val) {

  int l1;
  
  grooveTick = val;
  for (l1 = 0; l1 < midiArpList->count(); l1++) {
    midiArpList->at(l1)->newGrooveValues(grooveTick, grooveVelocity, grooveLength);
  }
}

void SeqDriver::setGrooveVelocity(int val) {

  int l1;

  grooveVelocity = val;
  for (l1 = 0; l1 < midiArpList->count(); l1++) {
    midiArpList->at(l1)->newGrooveValues(grooveTick, grooveVelocity, grooveLength);
  }
}

void SeqDriver::setGrooveLength(int val) {

  int l1;

  grooveLength = val;
  for (l1 = 0; l1 < midiArpList->count(); l1++) {
    midiArpList->at(l1)->newGrooveValues(grooveTick, grooveVelocity, grooveLength);
  }
}

void SeqDriver::sendGroove() {

  int l1;

  for (l1 = 0; l1 < midiArpList->count(); l1++) {
    midiArpList->at(l1)->newGrooveValues(grooveTick, grooveVelocity, grooveLength);
  }
}

Generated by  Doxygen 1.6.0   Back to index