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

imidi.cc

/*
    Copyright (C) 2005-2006 Fons Adriaensen <fons.adriaensen@skynet.be>
    
    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.
*/


#include "imidi.h"



Imidi::Imidi (Lfq_u32 *qnote, const char *appid, U16 *chconf) :
    A_thread ("Imidi"),
    _qnote (qnote),
    _appid (appid),
    _emode (0),
    _group (0),
    _bank (0),
    _hold (63),
    _chbits (chconf)
{
}


Imidi::~Imidi (void)
{
}


void Imidi::terminate (void)
{
    snd_seq_event_t E;

    if (_handle)
    {   
      snd_seq_ev_clear (&E);
      snd_seq_ev_set_direct (&E);
      E.type = SND_SEQ_EVENT_USR0;
      E.source.port = _opport;
      E.dest.client = _client;
      E.dest.port   = _ipport;
      snd_seq_event_output_direct (_handle, &E);
    }
}


void Imidi::thr_main (void)
{
    open_midi ();
    proc_midi ();
    close_midi ();
    send_event (EV_EXIT, 1);
}


void Imidi::open_midi (void)
{
    snd_seq_client_info_t *C;
    M_midi_info *M;

    if (snd_seq_open (&_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0)
    {
        fprintf(stderr, "Error opening ALSA sequencer.\n");
        exit(1);
    }

    snd_seq_client_info_alloca (&C);
    snd_seq_get_client_info (_handle, C);
    _client = snd_seq_client_info_get_client (C);
    snd_seq_client_info_set_name (C, _appid);
    snd_seq_set_client_info (_handle, C);

    if ((_ipport = snd_seq_create_simple_port (_handle, "In",
        SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
        SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
    {
        fprintf(stderr, "Error creating sequencer input port.\n");
        exit(1);
    }

    if ((_opport = snd_seq_create_simple_port (_handle, "Out",
         SND_SEQ_PORT_CAP_WRITE,
         SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
    {
        fprintf(stderr, "Error creating sequencer output port.\n");
        exit(1);
    }

    M = new M_midi_info ();
    M->_client = _client;
    M->_ipport = _ipport;
    memcpy (M->_chbits, _chbits, 16);
    send_event (TO_MODEL, M);
}


void Imidi::close_midi (void)
{
    if (_handle) snd_seq_close (_handle);
}


void Imidi::proc_midi (void) 
{
    snd_seq_event_t  *E;
    int              c, d, f, m, n, p, t, v;

    while (true)
    {
      snd_seq_event_input(_handle, &E);
        c = E->data.note.channel;               
        t = E->type;

        m = _chbits [c] & 127;
        d = (_chbits [c] >>  8) & 7;
        f = (_chbits [c] >> 12) & 7;

      switch (t)
      { 
      case SND_SEQ_EVENT_NOTEON:
      case SND_SEQ_EVENT_NOTEOFF:
          n = E->data.note.note;
          v = E->data.note.velocity;
            if ((t == SND_SEQ_EVENT_NOTEON) && v)
          {
                // Note on.
              if (n < 36)
              {
                    if (f & 4)
                  {
                  if ((n >= 24) && (n < 34)) send_event (TO_MODEL, new M_ifc_preset (MT_IFC_PRRCL, -1, n - 24, 0, 0));
                  }
              }
                else if (n <= 96)
              {
                   if (m) qwrite (1, 0, n - 36, m & _hold);
            }
            }
            else
          {
                // Note off.
              if (n < 36)
              {
              }
                else if (n <= 96)
              {
                   if (m) qwrite (0, 0, n - 36, m & 63);
            }
          }
          break;

      case SND_SEQ_EVENT_CONTROLLER:
          p = E->data.control.param;
          v = E->data.control.value;

            switch (p)
          {
          case MIDICTL_SWELL:
            // Swell pedal
            if (f & 2)
            {
                    send_event (TO_MODEL, new M_ifc_dipar (SRC_MIDI_PAR, d, 0,
                                                           SWELL_MIN + v * (SWELL_MAX - SWELL_MIN) / 127.0f));
            }         
                break;

          case MIDICTL_TFREQ:
            // tremulant frequency
            if (f & 2)
            {
                    send_event (TO_MODEL, new M_ifc_dipar (SRC_MIDI_PAR, d, 1,
                                                           TFREQ_MIN + v * (TFREQ_MAX - TFREQ_MIN) / 127.0f));
            }         
                break;

          case MIDICTL_TMODD:
            // tremulant amplitude
            if (f & 2)
            {
                    send_event (TO_MODEL, new M_ifc_dipar (SRC_MIDI_PAR, d, 2,
                                                           TMODD_MIN + v * (TMODD_MAX - TMODD_MIN) / 127.0f));
            }         
                break;

          case MIDICTL_IFELM:
            // stop control
            if (f & 4)
            {
                    if (v & 64)
                {
                  _emode = (v >> 4) & 3;
                        _group = v & 7; 
                        if (! _emode) send_event (TO_MODEL, new M_ifc_ifelm (MT_IFC_GRCLR, _group, 0));
                }
                    else if (_emode)
                {
                        send_event (TO_MODEL, new M_ifc_ifelm (MT_IFC_ELCLR + _emode - 1, _group, v & 31));
                }
            }         
                break;

            case 32:
                // Set preset bank.
            if (f & 4)
            {
                if (v < NBANK) _bank = v;
            }
                break;

          case 64:
            // Hold pedal
                if (m & 64)
            {
                    if (v & 64)
                    {
                    _hold = 127;
                    qwrite (3, m, 0, 64);
                }
                    else
                {
                    _hold = 63;
                        qwrite (2, 64, 0, 64);  
                }                    
            }                    
                break;

          case 120:
            // All sound off, accepted on control channels only.
            // Clears all keyboards, including held notes.
            if (f & 4) qwrite (2, 127, 0, 127);
            break;

            case 123:
            // All notes off, accepted on channels controlling
            // a keyboard. Does not clear held notes. 
            if (m) qwrite (2, m, 0, m);
                break;
          }
          break;

      case SND_SEQ_EVENT_PGMCHANGE:
          v = E->data.control.value;
            if (f & 4)
          {
                // Load preset.
            send_event (TO_MODEL, new M_ifc_preset (MT_IFC_PRRCL, _bank, v, 0, 0));
          }
          break;

      case SND_SEQ_EVENT_USR0:
          if (E->source.client == _client) return;
      }
    }
}


Generated by  Doxygen 1.6.0   Back to index