Exemplo n.º 1
0
bool MidiPort::sendEvent(const MidiPlayEvent& ev, bool forceSend)
{
	if (ev.type() == ME_CONTROLLER)
	{
		//TODO: This is where PC are added
		//      printf("current sustain %d %d %d\n", hwCtrlState(ev.channel(),CTRL_SUSTAIN), CTRL_SUSTAIN, ev.dataA());

		// Added by T356.
		int da = ev.dataA();
		int db = ev.dataB();
		db = limitValToInstrCtlRange(da, db);


		// Removed by T356.
		//
		//  optimize controller settings
		//
		if (!setHwCtrlState(ev.channel(), da, db))
		{
			if (debugMsg)
				printf("setHwCtrlState failed\n");
			if (!forceSend)
				return false;
		}
	}
	else if (ev.type() == ME_PITCHBEND)
	{
		int da = limitValToInstrCtlRange(CTRL_PITCH, ev.dataA());

		if (!setHwCtrlState(ev.channel(), CTRL_PITCH, da)) 
		{
			if(!forceSend)
				return false;
		}
	}
	else if (ev.type() == ME_PROGRAM)
	{
		if (!setHwCtrlState(ev.channel(), CTRL_PROGRAM, ev.dataA()))
		{
			if(!forceSend)
				return false;
		}
	}


	if (!_device)
	{
		if (debugMsg)
			printf("no device for this midi port\n");
		return true;
	}
	//printf("MidiPort::sendEvent\n");
	return _device->putEvent(ev);
}
Exemplo n.º 2
0
bool MidiJackDevice::putEvent(const MidiPlayEvent& ev)
{
    if (!_writeEnable || !_out_client_jackport)
        return false;

#ifdef JACK_MIDI_DEBUG
    printf("MidiJackDevice::putEvent time:%d type:%d ch:%d A:%d B:%d\n", ev.time(), ev.type(), ev.channel(), ev.dataA(), ev.dataB());
#endif

    bool rv = eventFifo.put(ev);
    if (rv)
        printf("MidiJackDevice::putEvent: port overflow\n");

    return rv;
}
Exemplo n.º 3
0
bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
{
    if (midiOutputTrace)
    {
        printf("MidiOut: midiAlsa: ");
        e.dump();
    }
    int chn = e.channel();
    int a = e.dataA();
    int b = e.dataB();

    snd_seq_event_t event;
    memset(&event, 0, sizeof (event));
    event.queue = SND_SEQ_QUEUE_DIRECT;
    event.source = losPort;
    event.dest = adr;

    switch (e.type())
    {
        case ME_NOTEON:
            snd_seq_ev_set_noteon(&event, chn, a, b);
            break;
        case ME_NOTEOFF:
            snd_seq_ev_set_noteoff(&event, chn, a, 0);
            break;
        case ME_PROGRAM:
            snd_seq_ev_set_pgmchange(&event, chn, a);
            break;
        case ME_CONTROLLER:
#if 1
            snd_seq_ev_set_controller(&event, chn, a, b);
#else
        {
            int a = e.dataA();
            int b = e.dataB();
            int chn = e.channel();
            if (a < CTRL_14_OFFSET)
            { // 7 Bit Controller
                snd_seq_ev_set_controller(&event, chn, a, b);
            }
            else if (a < CTRL_RPN_OFFSET)
            { // 14 bit high resolution controller
                int ctrlH = (a >> 8) & 0x7f;
                int ctrlL = a & 0x7f;
                a = (ctrlH << 7) + ctrlL;
                snd_seq_ev_set_controller(&event, chn, a, b);
                event.type = SND_SEQ_EVENT_CONTROL14;
            }
            else if (a < CTRL_NRPN_OFFSET)
            { // RPN 7-Bit Controller
                int ctrlH = (a >> 8) & 0x7f;
                int ctrlL = a & 0x7f;
                a = (ctrlH << 7) + ctrlL;
                b <<= 7;
                snd_seq_ev_set_controller(&event, chn, a, b);
                event.type = SND_SEQ_EVENT_REGPARAM;
            }
Exemplo n.º 4
0
bool MetronomeSynthIF::putEvent(const MidiPlayEvent& ev)
{
    if (ev.dataA() == MusECore::measureSound) {
        if (MusEGlobal::clickSamples == MusEGlobal::origSamples) {
            data = defaultClickEmphasis;
            len  = defaultClickEmphasisLength;
        }
        else {
              data = defaultKlick3;
              len  = defaultKlick3Length;
        }
        volume = MusEGlobal::measClickVolume;
    }
    else if (ev.dataA() == MusECore::beatSound) {
        if (MusEGlobal::clickSamples == MusEGlobal::origSamples) {
            data = defaultClick;
            len  = defaultClickLength;
        } else {
            data = defaultKlick1;
            len  = defaultKlick1Length;
        }
        volume = MusEGlobal::beatClickVolume;
    }
    else if (ev.dataA() == MusECore::accent1Sound) {
             data = defaultKlick4;
             len  = defaultKlick4Length;
             volume = MusEGlobal::accent1ClickVolume;
             if (MusEGlobal::clickSamples == MusEGlobal::origSamples) {
                 volume=0.0;
             }
    }
    else if (ev.dataA() == MusECore::accent2Sound) {
             data = defaultKlick2;
             len  = defaultKlick2Length;
             volume = MusEGlobal::accent2ClickVolume;
             if (MusEGlobal::clickSamples == MusEGlobal::origSamples) {
                 volume=0.0;
             }
    }


    pos = 0;
    return false;
}
Exemplo n.º 5
0
void Organ::processMessages()
{
  //Process messages from the gui
  //
  //  get and process all pending events from the
  //  synthesizer GUI
  //
  while (gui->fifoSize()) 
  {
    MidiPlayEvent ev = gui->readEvent();
    if (ev.type() == ME_CONTROLLER) 
    {
      // process local?
      setController(ev.dataA(), ev.dataB());
      sendEvent(ev);
    }
    else
      printf("Organ::process(): unknown event\n");
  }
}
Exemplo n.º 6
0
bool VstSynthIF::putEvent(const MidiPlayEvent& ev)
      {
      if (midiOutputTrace)
            ev.dump();
      AEffect* plugin = _fst->plugin;
      static struct VstEvents events;
      static struct VstMidiEvent event;
      events.numEvents = 1;
      events.reserved  = 0;
      events.events[0] = (VstEvent*)(&event);

      event.type         = kVstMidiType;
      event.byteSize     = 24;
      event.deltaFrames  = 0;
      event.flags        = 0;
      event.detune       = 0;
      event.noteLength   = 0;
      event.noteOffset   = 0;
      event.reserved1    = 0;
      event.reserved2    = 0;
      event.noteOffVelocity = 0;
      switch (ev.type()) {
            case ME_PITCHBEND:
                  {
                  int a = ev.dataA() + 8192;
                  int b = a >> 7;
                  event.midiData[0]  = (ev.type() | ev.channel()) & 0xff;
                  event.midiData[1]  = a & 0x7f;
                  event.midiData[2]  = b & 0x7f;
                  event.midiData[3]  = 0;
                  }
                  break;

            case ME_CONTROLLER:
            case ME_NOTEON:
            default:
                  event.midiData[0]  = (ev.type() | ev.channel()) & 0xff;
                  event.midiData[1]  = ev.dataA() & 0xff;
                  event.midiData[2]  = ev.dataB() & 0xff;
                  event.midiData[3]  = 0;
                  break;
            }
      int rv = plugin->dispatcher(plugin, effProcessEvents, 0, 0, &events, 0.0f);
      return false;
      }
Exemplo n.º 7
0
bool MidiDevice::putEvent(const MidiPlayEvent& ev)
      {
      if(!_writeEnable)
        //return true;
        return false;
        
      unsigned t = ev.time();
      int port = ev.port();
      
      if (ev.type() == ME_CONTROLLER) {
            int a = ev.dataA();
            int b = ev.dataB();
            int chn = ev.channel();
            if (a == CTRL_PITCH) {
                  return putMidiEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, b, 0));
                  }
            if ((a | 0xff) == CTRL_POLYAFTER) {
                  return putMidiEvent(MidiPlayEvent(t, port, chn, ME_POLYAFTER, a & 0x7f, b & 0x7f));
                  }
            if (a == CTRL_AFTERTOUCH) {
                  return putMidiEvent(MidiPlayEvent(t, port, chn, ME_AFTERTOUCH, b, 0));
                  }
            if (a == CTRL_PROGRAM) {
                        int hb = (b >> 16) & 0xff;
                        int lb = (b >> 8) & 0xff;
                        int pr = b & 0x7f;
                        if (hb != 0xff)
                              putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb));
                        if (lb != 0xff)
                              putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LBANK, lb));
                        return putMidiEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, pr, 0));
                  }
Exemplo n.º 8
0
void MidiInstrument::reset(int portNo, MidiType)
{
    MidiPort* port = &midiPorts[portNo];
    MidiPlayEvent ev;
    ev.setType(0x90);
    ev.setPort(portNo);
    ev.setTime(0);
    for (int chan = 0; chan < kMaxMidiChannels; ++chan)
    {
        ev.setChannel(chan);
        for (int pitch = 0; pitch < 128; ++pitch)
        {
            ev.setA(pitch);
            ev.setB(0);
            port->sendEvent(ev);
        }
    }
}
Exemplo n.º 9
0
bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
{
    int chn = event.channel();
    unsigned t = event.time();
    int a = event.dataA();
    int b = event.dataB();
    // Perhaps we can find use for this value later, together with the Jack midi LOS port(s).
    // No big deal if not. Not used for now.
    int port = event.port();

    // TODO: No sub-tick playback resolution yet, with external sync.
    // Just do this 'standard midi 64T timing thing' for now until we figure out more precise external timings.
    // Does require relatively short audio buffers, in order to catch the resolution, but buffer <= 256 should be OK...
    // Tested OK so far with 128.
    if (t == 0 /*|| extSyncFlag.value()*/)
        t = audio->getFrameOffset() + audio->pos().frame();

#ifdef JACK_MIDI_DEBUG
    //printf("MidiJackDevice::processEvent time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
#endif

    //Send to monitor thread for processing
    monitorOutputEvent(event);

    if (event.type() == ME_PROGRAM)
    {
        // don't output program changes for GM drum channel
        int hb = (a >> 16) & 0xff;
        int lb = (a >> 8) & 0xff;
        int pr = a & 0x7f;

        //TODO: NOTE this is where program changes are sent we can later debug this to diagnose the dropped events
        if (hb != 0xff)
        {
            if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)))
                return false;
        }
        if (lb != 0xff)
        {
            if(!queueEvent(MidiPlayEvent(t + 1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))
                return false;
        }
        //sleep(1);
        if(!queueEvent(MidiPlayEvent(t + 2, port, chn, ME_PROGRAM, pr, 0)))
            return false;
    }
Exemplo n.º 10
0
void MidiInstrument::reset(int portNo, MType)
{
    MidiPlayEvent ev;
    ev.setType(0x90);
    MidiPort* port = &midiPorts[portNo];
    if (port == 0)
        return;
    ev.setPort(portNo);
    for (int chan = 0; chan < MIDI_CHANNELS; ++chan)
    {
        ev.setChannel(chan);
        for (int pitch = 0; pitch < 128; ++pitch)
        {
            ev.setA(pitch);
            ev.setB(0);
            port->sendEvent(ev);
        }
    }
}
Exemplo n.º 11
0
bool Mess::processEvent(const MidiPlayEvent& ev)
      {
      switch(ev.type()) {
            case ME_NOTEON:
                  return playNote(ev.channel(), ev.dataA(), ev.dataB());
            case ME_NOTEOFF:
                  return playNote(ev.channel(), ev.dataA(), 0);
            case ME_SYSEX:
	            return sysex(ev.len(), ev.data());
            case ME_CONTROLLER:
                  return setController(ev.channel(), ev.dataA(), ev.dataB());
            case ME_PITCHBEND:       // Tim.
                  return setController(ev.channel(), CTRL_PITCH, ev.dataA());
            }
      return false;
      }
Exemplo n.º 12
0
bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
{
    if (!_out_client_jackport) // p3.3.55
        return false;
    void* pb = jack_port_get_buffer(_out_client_jackport, segmentSize); // p3.3.55

    int frameOffset = audio->getFrameOffset();
    unsigned pos = audio->pos().frame();
    int ft = e.time() - frameOffset - pos;

    if (ft < 0)
        ft = 0;
    if (ft >= (int) segmentSize)
    {
        if(debugMsg)
            printf("MidiJackDevice::queueEvent: Event time:%d out of range. offset:%d ft:%d (seg=%d)\n", e.time(), frameOffset, ft, segmentSize);
        if (ft > (int) segmentSize)
            ft = segmentSize - 1;
    }

#ifdef JACK_MIDI_DEBUG
    printf("MidiJackDevice::queueEvent time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB());
#endif

    switch (e.type())
    {
        case ME_NOTEON:
        case ME_NOTEOFF:
        case ME_POLYAFTER:
        case ME_CONTROLLER:
        case ME_PITCHBEND:
        {
#ifdef JACK_MIDI_DEBUG
            printf("MidiJackDevice::queueEvent note on/off polyafter controller or pitch\n");
#endif

            unsigned char* p = jack_midi_event_reserve(pb, ft, 3);
            if (p == 0)
            {
                #ifdef JACK_MIDI_DEBUG
                fprintf(stderr, "MidiJackDevice::queueEvent NOTE CONTROL PAT or PB: buffer overflow, stopping until next cycle\n");
                #endif
                return false;
            }
            p[0] = e.type() | e.channel();
            p[1] = e.dataA();
            p[2] = e.dataB();
        }
            break;

        case ME_PROGRAM:
        case ME_AFTERTOUCH:
        {
#ifdef JACK_MIDI_DEBUG
            printf("MidiJackDevice::queueEvent program or aftertouch\n");
#endif

            unsigned char* p = jack_midi_event_reserve(pb, ft, 2);
            if (p == 0)
            {
                #ifdef JACK_MIDI_DEBUG
                fprintf(stderr, "MidiJackDevice::queueEvent PROG or AT: buffer overflow, stopping until next cycle\n");
                #endif
                return false;
            }
            p[0] = e.type() | e.channel();
            p[1] = e.dataA();
        }
            break;
        case ME_SYSEX:
        {
#ifdef JACK_MIDI_DEBUG
            printf("MidiJackDevice::queueEvent sysex\n");
#endif

            const unsigned char* data = e.data();
            int len = e.len();
            unsigned char* p = jack_midi_event_reserve(pb, ft, len + 2);
            if (p == 0)
            {
                fprintf(stderr, "MidiJackDevice::queueEvent ME_SYSEX: buffer overflow, sysex too big, event lost\n");
                return true;
            }
            p[0] = 0xf0;
            p[len + 1] = 0xf7;
            memcpy(p + 1, data, len);
        }
            break;
        case ME_SONGPOS:
        case ME_CLOCK:
        case ME_START:
        case ME_CONTINUE:
        case ME_STOP:
            if(debugMsg)
                printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type());
            return true;
            break;
    }

    return true;
}
Exemplo n.º 13
0
void FluidSynthGui::processEvent(const MidiPlayEvent& ev)
      {
      //Sysexes sent from the client
      if (ev.type() == ME_SYSEX) {
            byte* data = ev.data();
            switch (*data) {
                  case FS_LASTDIR_CHANGE:
                        lastdir = QString((const char*)data+1);
                        break;
                  case FS_ERROR: {
                        char* msg = (char*) (data+1);
                        
                        printf("OOMidi: fluidsynth error: %s\n", msg);
                        
                        break;
                        }
                  case FS_SEND_SOUNDFONTDATA: {
                        int chunk_len;
                        int filename_len;

                        int count = (int)*(data+1); //Number of elements
                        byte* cp = data+2; //Point to beginning of first chunk
                        sfListView->clear(); //Clear the listview
                        stack.clear(); //Clear the stack since we're starting over again

                        while (count) {
                              FluidGuiSoundFont font;
                              filename_len = strlen((const char*)cp) + 1;
                              font.name = (const char*)cp;
                              font.id = *(cp + filename_len);
                              chunk_len = filename_len + FS_SFDATALEN;
                              stack.push_front(font);
                              cp += chunk_len; //Move to next chunk
                              count--;
                              }
                        updateSoundfontListView();
                        updateChannelListView();
                        break;
                        }
                  case FS_SEND_CHANNELINFO: {
                        byte* chptr = (data+1);
                        for (int i=0; i< FS_MAX_NR_OF_CHANNELS; i++) {
                              byte id = *chptr;
                              byte channel = *(chptr+1);
                              channels[channel] = id;
                              chptr+=2;
                              }
                        updateChannelListView();

                        break;
                        }
                  case FS_SEND_DRUMCHANNELINFO: {
                        byte* drumchptr = (data+1);
                        for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) {
                              drumchannels[i] = *drumchptr;
                              drumchptr++;
                              }
                        updateChannelListView();
                        break;
                        }
                  default:
                        if (FS_DEBUG)
                              printf("FluidSynthGui::processEvent() : Unknown Sysex received: %d\n", ev.type());
                        break;
                  }
            }
            //Controllers sent from the client:
      else
            if(ev.type() == ME_CONTROLLER) {
                  int id = ev.dataA();
                  int val = ev.dataB();
                  switch (id) {
                        case FS_GAIN: {
                              bool sb = Gain->signalsBlocked();
                              Gain->blockSignals(true);
                              // Update Gain-slider without causing it to respond to it's own signal (and send another msg to the synth)
                              Gain->setValue(val);
                              Gain->blockSignals(sb);
                              break;
                              }
                        case FS_REVERB_ON: {
                              bool sb = Reverb->signalsBlocked();
                              Reverb->blockSignals(true);
                              Reverb->setChecked(val);
                              Reverb->blockSignals(sb);
                              break;
                              }
                        case FS_REVERB_LEVEL: {
                              bool sb = ReverbLevel->signalsBlocked();
                              ReverbLevel->blockSignals(true);
                              ReverbLevel->setValue(val);
                              ReverbLevel->blockSignals(sb);
                              break;
                              }
                        case FS_REVERB_DAMPING: {
                              bool sb = ReverbDamping->signalsBlocked();
                              ReverbDamping->blockSignals(true);
                              ReverbDamping->setValue(val);
                              ReverbDamping->blockSignals(sb);
                              break;
                              }
                        case FS_REVERB_ROOMSIZE: {
                              bool sb = ReverbRoomSize->signalsBlocked();
                              ReverbRoomSize->blockSignals(true);
                              ReverbRoomSize->setValue(val);
                              ReverbRoomSize->blockSignals(sb);
                              break;
                              }
                        case FS_REVERB_WIDTH: {
                              bool sb = ReverbWidth->signalsBlocked();
                              ReverbWidth->blockSignals(true);
                              ReverbWidth->setValue(val);
                              ReverbWidth->blockSignals(sb);
                              break;
                              }
                        case FS_CHORUS_ON: {
                              Chorus->blockSignals(true);
                              Chorus->setChecked(val);
                              Chorus->blockSignals(false);
                              break;
                              }
                        case FS_CHORUS_SPEED: {
                              ChorusSpeed->blockSignals(true);
                              ChorusSpeed->setValue(val);
                              ChorusSpeed->blockSignals(false);
                              break;
                              }
                        case FS_CHORUS_NUM: {
                              ChorusNumber->blockSignals(true);
                              ChorusNumber->setValue(val);
                              ChorusNumber->blockSignals(false);
                              break;
                              }
                        case FS_CHORUS_TYPE: {
                              ChorusType->blockSignals(true);
                              ChorusType->setCurrentIndex(val);
                              ChorusType->blockSignals(false);
                              break;
                              }
                        case FS_CHORUS_DEPTH: {
                              ChorusDepth->blockSignals(true);
                              ChorusDepth->setValue(val);
                              ChorusDepth->blockSignals(false);
                              break;
                              }
                        case FS_CHORUS_LEVEL: {
                              ChorusLevel->blockSignals(true);
                              ChorusLevel->setValue(val);
                              ChorusLevel->blockSignals(false);
                              break;
                              }
                        default:
                              if (FS_DEBUG)
                                    printf("FluidSynthGui::processEvent() : Unknown controller sent to gui: %x\n",id);
                              break;
                        }
                  }
      else
            if (FS_DEBUG)
                  printf("FluidSynthGui::processEvent - unknown event of type %dreceived from synth.\n", ev.type());
      }
Exemplo n.º 14
0
Arquivo: midi.cpp Projeto: faesong/oom
void Audio::processMidi()
{
	midiBusy = true;
	//
	// TODO: syntis should directly write into recordEventList
	//
	for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
	{
		MidiDevice* md = *id;

		MPEventList* playEvents = md->playEvents();
		//
		// erase already played events:
		//
		iMPEvent nextPlayEvent = md->nextPlayEvent();
		playEvents->erase(playEvents->begin(), nextPlayEvent);

		// klumsy hack for synti devices:
		if (md->isSynti())
		{
			SynthI* s = (SynthI*) md;
			while (s->eventsPending())
			{
				MidiRecordEvent ev = s->receiveEvent();
				md->recordEvent(ev);
			}
		}

		// Is it a Jack midi device?
		//MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
		//if(mjd)
		//  mjd->collectMidiEvents();
		md->collectMidiEvents();

		// Take snapshots of the current sizes of the recording fifos,
		//  because they may change while here in process, asynchronously.
		md->beforeProcess();
	}

	MPEventList* playEvents = metronome->playEvents();
	iMPEvent nextPlayEvent = metronome->nextPlayEvent();
	playEvents->erase(playEvents->begin(), nextPlayEvent);

	// p3.3.25
	bool extsync = extSyncFlag.value();

	for (iMidiTrack t = song->midis()->begin(); t != song->midis()->end(); ++t)
	{
		MidiTrack* track = *t;
		int port = track->outPort();
		MidiDevice* md = midiPorts[port].device();

		// Changed by Tim. p3.3.8
		//if(md == 0)
		//  continue;
		//MPEventList* playEvents = md->playEvents();
		//if (playEvents == 0)
		//    continue;
		//if (!track->isMute())
		MPEventList* playEvents = 0;
		if (md)
		{
			playEvents = md->playEvents();

			// only add track events if the track is unmuted
			if (!track->isMute())
			{
				if (isPlaying() && (curTickPos < nextTickPos))
					collectEvents(track, curTickPos, nextTickPos);
			}
		}

		//
		//----------midi recording
		//
		if (track->recordFlag())
		{
			//int portMask    = track->inPortMask();
			// p3.3.38 Removed
			//unsigned int portMask = track->inPortMask();
			//int channelMask = track->inChannelMask();

			MPEventList* rl = track->mpevents();
			MidiPort* tport = &midiPorts[port];

			// p3.3.38
			//for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
			//{
			RouteList* irl = track->inRoutes();
			for (ciRoute r = irl->begin(); r != irl->end(); ++r)
			{
				//if(!r->isValid() || (r->type != Route::ALSA_MIDI_ROUTE && r->type != Route::JACK_MIDI_ROUTE))
				//if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE))
				if (!r->isValid() || (r->type != Route::MIDI_PORT_ROUTE)) // p3.3.49
					continue;

				int devport = r->midiPort; // p3.3.49
				if (devport == -1)
					continue;

				//MidiDevice* dev = *id;
				//MidiDevice* dev = r->device;
				MidiDevice* dev = midiPorts[devport].device(); // p3.3.49
				if (!dev)
					continue;


				// p3.3.50 Removed
				//int channel = r->channel;
				// NOTE: TODO: Special for input device sysex 'channel' marked as -1, ** IF we end up going with that method **.
				// This would mean having a separate 'System' channel listed in the routing popups.
				// The other alternative is to accept sysex from a device as long as ANY regular channel is routed from it,
				//  this does not require a 'System' channel listed in the routing popups.
				// But that requires more code below... Done.
				//if(channel == -1)
				//channel = MIDI_CHANNELS; // Special channel '17'
				//  continue;

				//int devport = dev->midiPort();

				// record only from ports marked in portMask:
				//if (devport == -1 || !(portMask & (1 << devport)))
				//if (devport == -1)
				//      continue;

				//MREventList* el = dev->recordEvents();
				//MidiFifo& rf = dev->recordEvents();


				int channelMask = r->channel; // p3.3.50
				if (channelMask == -1 || channelMask == 0)
					continue;
				for (int channel = 0; channel < MIDI_CHANNELS; ++channel) // p3.3.50
				{
					if (!(channelMask & (1 << channel)))
						continue;

					if (!dev->sysexFIFOProcessed())
					{
						// Set to the sysex fifo at first.
						MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);
						// Get the frozen snapshot of the size.
						int count = dev->tmpRecordCount(MIDI_CHANNELS);

						for (int i = 0; i < count; ++i)
						{
							MidiPlayEvent event(rf.peek(i));

							//unsigned time = event.time() + segmentSize*(segmentCount-1);
							//unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1));
							//unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
							//event.setTime(time);
							//if(!extsync)
							//  event.setTime(event.time() + segmentSize*(segmentCount-1));

							event.setPort(port);

							// dont't echo controller changes back to software
							// synthesizer:
							if (!dev->isSynti() && md && track->recEcho())
								playEvents->add(event);

							// If syncing externally the event time is already in units of ticks, set above.
							if (!extsync)
							{
								//time = tempomap.frame2tick(event.time());
								//event.setTime(time);  // set tick time
								event.setTime(tempomap.frame2tick(event.time())); // set tick time
							}

							if (recording)
								rl->add(event);
						}

						dev->setSysexFIFOProcessed(true);
					}

					// Set to the sysex fifo at first.
					///MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);
					// Get the frozen snapshot of the size.
					///int count = dev->tmpRecordCount(MIDI_CHANNELS);

					// Iterate once for sysex fifo (if needed), once for channel fifos.
					///for(int sei = 0; sei < 2; ++sei)
					{
						// If on first pass, do sysex fifo.
						/*
						if(sei == 0)
						{
						  // Ignore any further channel routes on this device if already done here.
						  if(dev->sysexFIFOProcessed())
							continue;
						  // Go ahead and set this now.
						  dev->setSysexFIFOProcessed(true);
						  // Allow it to fall through with the sysex fifo and count...
						}
						else
						{
						  // We're on the second pass, do channel fifos.
						  rf = dev->recordEvents(channel);
						  // Get the frozen snapshot of the size.
						  count = dev->tmpRecordCount(channel);
						}
						 */

						MidiFifo& rf = dev->recordEvents(channel);
						int count = dev->tmpRecordCount(channel);

						//for (iMREvent ie = el->begin(); ie != el->end(); ++ie)
						for (int i = 0; i < count; ++i)
						{
							MidiPlayEvent event(rf.peek(i));

							//int channel = ie->channel();
							///int channel = event.channel();

							int defaultPort = devport;
							///if (!(channelMask & (1 << channel)))
							///{
							///      continue;
							///}

							//MidiPlayEvent event(*ie);
							int drumRecPitch = 0; //prevent compiler warning: variable used without initialization
							MidiController *mc = 0;
							int ctl = 0;

							//Hmmm, hehhh...
							// TODO: Clean up a bit around here when it comes to separate events for rec & for playback.
							// But not before 0.7 (ml)

							int prePitch = 0, preVelo = 0;

							event.setChannel(track->outChannel());

							if (event.isNote() || event.isNoteOff())
							{
								//
								// apply track values
								//

								//Apply drum inkey:
								if (track->type() == Track::DRUM)
								{
									int pitch = event.dataA();
									//Map note that is played according to drumInmap
									drumRecPitch = drumMap[(unsigned int) drumInmap[pitch]].enote;
									devport = drumMap[(unsigned int) drumInmap[pitch]].port;
									event.setPort(devport);
									channel = drumMap[(unsigned int) drumInmap[pitch]].channel;
									event.setA(drumMap[(unsigned int) drumInmap[pitch]].anote);
									event.setChannel(channel);
								}
								else
								{ //Track transpose if non-drum
									prePitch = event.dataA();
									int pitch = prePitch + track->transposition;
									if (pitch > 127)
										pitch = 127;
									if (pitch < 0)
										pitch = 0;
									event.setA(pitch);
								}

								if (!event.isNoteOff())
								{
									preVelo = event.dataB();
									int velo = preVelo + track->velocity;
									velo = (velo * track->compression) / 100;
									if (velo > 127)
										velo = 127;
									if (velo < 1)
										velo = 1;
									event.setB(velo);
								}
							}
								// Added by T356.
							else if (event.type() == ME_CONTROLLER)
							{
								//printf("11111111111111111111111111111111111111111111111111111\n");
								if (track->type() == Track::DRUM)
								{
									//printf("2222222222222222222222222222222222222222222222222222222222\n");
									ctl = event.dataA();
									// Regardless of what port the event came from, is it a drum controller event
									//  according to the track port's instrument?
									mc = tport->drumController(ctl);
									if (mc)
									{

										//printf("333333333333333333333333333333333333333333333333\n");
										int pitch = ctl & 0x7f;
										ctl &= ~0xff;
										int dmindex = drumInmap[pitch] & 0x7f;
										//Map note that is played according to drumInmap
										drumRecPitch = drumMap[dmindex].enote;
										devport = drumMap[dmindex].port;
										event.setPort(devport);
										channel = drumMap[dmindex].channel;
										event.setA(ctl | drumMap[dmindex].anote);
										event.setChannel(channel);
									}
								}
							}

							// p3.3.25
							// OOMidi uses a fixed clocks per quarternote of 24.
							// At standard 384 ticks per quarternote for example,
							// 384/24=16 for a division of 16 sub-frames (16 OOMidi 'ticks').
							// That is what we'll use if syncing externally.
							//unsigned time = event.time() + segmentSize*(segmentCount-1);
							//unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1));
							// p3.3.34
							// Oops, use the current tick.
							//unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
							//event.setTime(time);
							// p3.3.35
							// If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent().
							// TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice.
							// p3.3.36
							//if(!extsync)
							//  event.setTime(event.time() + segmentSize*(segmentCount-1));

							// dont't echo controller changes back to software
							// synthesizer:

							if (!dev->isSynti())
							{
								//printf("444444444444444444444444444444444444444444444444444444\n");
								//Check if we're outputting to another port than default:
								if (devport == defaultPort)
								{

									//printf("5555555555555555555555555555555555555555555\n");
									event.setPort(port);
									if (md && track->recEcho())
										playEvents->add(event);
								}
								else
								{
									//printf("66666666666666666666666666666666666666\n");
									// Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent??
									MidiDevice* mdAlt = midiPorts[devport].device();
									if (mdAlt && track->recEcho())
										mdAlt->playEvents()->add(event);
								}
								// Shall we activate meters even while rec echo is off? Sure, why not...
								if (event.isNote() && event.dataB() > track->activity())
									track->setActivity(event.dataB());
							}

							// p3.3.25
							// If syncing externally the event time is already in units of ticks, set above.
							if (!extsync)
							{
								//printf("7777777777777777777777777777777777777777777\n");
								// p3.3.35
								//time = tempomap.frame2tick(event.time());
								//event.setTime(time);  // set tick time
								event.setTime(tempomap.frame2tick(event.time())); // set tick time
							}

							// Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml)
							if (recording)
							{
								//printf("888888888888888888888888888888888888888888888888\n");
								// In these next steps, it is essential to set the recorded event's port
								//  to the track port so buildMidiEventList will accept it. Even though
								//  the port may have no device "<none>".
								//
								if (track->type() == Track::DRUM)
								{
									//printf("99999999999999999999999999999999999999999999999999\n");
									// Is it a drum controller event?
									if (mc)
									{
										//printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
										MidiPlayEvent drumRecEvent = event;
										drumRecEvent.setA(ctl | drumRecPitch);
										// In this case, preVelo is simply the controller value.
										drumRecEvent.setB(preVelo);
										drumRecEvent.setPort(port); //rec-event to current port
										drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
										rl->add(drumRecEvent);
									}
									else
									{
										//printf("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n");

										MidiPlayEvent drumRecEvent = event;
										drumRecEvent.setA(drumRecPitch);
										drumRecEvent.setB(preVelo);
										// Changed by T356.
										// Tested: Events were not being recorded for a drum map entry pointing to a
										//  different port. This must have been wrong - buildMidiEventList would ignore this.
										//drumRecEvent.setPort(devport);
										drumRecEvent.setPort(port); //rec-event to current port

										drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
										rl->add(drumRecEvent);
									}
								}
								else
								{
									//printf("ccccccccccccccccccccccccccccccccccccccccccccc\n");
									// Restore record-pitch to non-transposed value since we don't want the note transposed twice next
									MidiPlayEvent recEvent = event;
									if (prePitch)
										recEvent.setA(prePitch);
									if (preVelo)
										recEvent.setB(preVelo);
									recEvent.setPort(port);
									recEvent.setChannel(track->outChannel());

									rl->add(recEvent);
								}
							}
						}
					}
				}
			}
		}
		// Added by Tim. p3.3.8
		if (md)
		{
			//printf("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\n");

			md->setNextPlayEvent(playEvents->begin());
		}
	}

	//
	// clear all recorded events in midiDevices
	// process stuck notes
	//
	for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
	{
		//printf("--------------------------aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
		MidiDevice* md = *id;

		///md->recordEvents()->clear();
		// By T356. Done processing this rec buffer, now flip to the other one.
		///md->flipRecBuffer();
		// We are done with the 'frozen' recording fifos, remove the events.
		md->afterProcess();

		MPEventList* stuckNotes = md->stuckNotes();
		MPEventList* playEvents = md->playEvents();

		iMPEvent k;
		for (k = stuckNotes->begin(); k != stuckNotes->end(); ++k)
		{
			if (k->time() >= nextTickPos)
				break;
			MidiPlayEvent ev(*k);

			// p3.3.25
			//int frame = tempomap.tick2frame(k->time()) + frameOffset;
			if (extsync)
			{
				ev.setTime(k->time());
			}
			else
			{
				int frame = tempomap.tick2frame(k->time()) + frameOffset;
				ev.setTime(frame);
			}

			// p3.3.25
			//ev.setTime(frame);

			playEvents->add(ev);
		}
		stuckNotes->erase(stuckNotes->begin(), k);
		md->setNextPlayEvent(playEvents->begin());
	}

	//---------------------------------------------------
	//    insert metronome clicks
	//---------------------------------------------------

	MidiDevice* md = 0;
	if (midiClickFlag)
		md = midiPorts[clickPort].device();
	if (song->click() && (isPlaying() || state == PRECOUNT))
	{
		MPEventList* playEvents = 0;
		MPEventList* stuckNotes = 0;
		if (md)
		{
			playEvents = md->playEvents();
			stuckNotes = md->stuckNotes();
		}
		int bar, beat;
		unsigned tick;
		bool isMeasure = false;
		while (midiClick < nextTickPos)
		{
			if (isPlaying())
			{
				///sigmap.tickValues(midiClick, &bar, &beat, &tick);
				AL::sigmap.tickValues(midiClick, &bar, &beat, &tick);
				isMeasure = beat == 0;
			}
			else if (state == PRECOUNT)
			{
				isMeasure = (clickno % clicksMeasure) == 0;
			}
			// p3.3.25
			//int frame = tempomap.tick2frame(midiClick) + frameOffset;
			int evtime = extsync ? midiClick : tempomap.tick2frame(midiClick) + frameOffset;

			// p3.3.25
			//MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON,
			MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON,
					beatClickNote, beatClickVelo);

			if (md)
			{
				// p3.3.25
				//MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON,
				MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON,
						beatClickNote, beatClickVelo);

				if (isMeasure)
				{
					ev.setA(measureClickNote);
					ev.setB(measureClickVelo);
				}
				playEvents->add(ev);
			}
			if (audioClickFlag)
			{
				// p3.3.25
				//MidiPlayEvent ev1(frame, 0, 0, ME_NOTEON, 0, 0);
				MidiPlayEvent ev1(evtime, 0, 0, ME_NOTEON, 0, 0);

				ev1.setA(isMeasure ? 0 : 1);
				metronome->playEvents()->add(ev1);
			}
			if (md)
			{
				ev.setB(0);
				// p3.3.25
				// Removed. Why was this here?
				//frame = tempomap.tick2frame(midiClick+20) + frameOffset;
				//
				// Does it mean this should be changed too?
				// No, stuck notes are in units of ticks, not frames like (normal, non-external) play events...
				ev.setTime(midiClick + 10);

				if (md)
					stuckNotes->add(ev);
			}

			if (isPlaying())
				///midiClick = sigmap.bar2tick(bar, beat+1, 0);
				midiClick = AL::sigmap.bar2tick(bar, beat + 1, 0);
			else if (state == PRECOUNT)
			{
				midiClick += ticksBeat;
				if (clickno)
					--clickno;
				else
					state = START_PLAY;
			}
		}
		if (md)
			md->setNextPlayEvent(playEvents->begin());
		if (audioClickFlag)
			metronome->setNextPlayEvent(metronome->playEvents()->begin());
	}

	if (state == STOP)
	{
		//---------------------------------------------------
		//    end all notes
		//---------------------------------------------------

		for (iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
		{
			MidiDevice* md = *imd;
			MPEventList* playEvents = md->playEvents();
			MPEventList* stuckNotes = md->stuckNotes();
			for (iMPEvent k = stuckNotes->begin(); k != stuckNotes->end(); ++k)
			{
				MidiPlayEvent ev(*k);
				ev.setTime(0); // play now
				playEvents->add(ev);
			}
			stuckNotes->clear();
		}
	}


	// p3.3.36
	//int tickpos = audio->tickPos();
	//bool extsync = extSyncFlag.value();
	//
	// Special for Jack midi devices: Play all Jack midi events up to curFrame.
	//
	for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
	{
		(*id)->processMidi();

		/*
		int port = md->midiPort();
		MidiPort* mp = port != -1 ? &midiPorts[port] : 0;
		MPEventList* el = md->playEvents();
		if (el->empty())
			  continue;
		iMPEvent i = md->nextPlayEvent();
		for(; i != el->end(); ++i)
		{
		  // If syncing to external midi sync, we cannot use the tempo map.
		  // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames.
		  //if(i->time() > curFrame)
		  if(i->time() > (extsync ? tickpos : curFrame))
		  {
			//printf("  curT %d  frame %d\n", i->time(), curFrame);
			break; // skip this event
		  }

		  if(mp)
		  {
			if(mp->sendEvent(*i))
			  break;
		  }
		  else
		  {
			if(md->putEvent(*i))
			  break;
		  }
		}
		md->setNextPlayEvent(i);
		 */
	}

	midiBusy = false;
}
Exemplo n.º 15
0
Arquivo: midi.cpp Projeto: faesong/oom
void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
		int div, bool addSysexMeta, bool doLoops)
{
	int hbank = 0xff;
	int lbank = 0xff;
	int rpnh = -1;
	int rpnl = -1;
	int datah = 0;
	int datal = 0;
	int dataType = 0; // 0 : disabled, 0x20000 : rpn, 0x30000 : nrpn

	EventList mel;

	for (iMPEvent i = el->begin(); i != el->end(); ++i)
	{
		MidiPlayEvent ev = *i;
		if (!addSysexMeta && (ev.type() == ME_SYSEX || ev.type() == ME_META))
			continue;
		if (!(ev.type() == ME_SYSEX || ev.type() == ME_META
				|| ((ev.channel() == track->outChannel()) && (ev.port() == track->outPort()))))
			continue;
		unsigned tick = ev.time();
		// Added by Tim. p3.3.8

		// Added by T356.
		if (doLoops)
		{
			if (tick >= song->lPos().tick() && tick < song->rPos().tick())
			{
				int loopn = ev.loopNum();
				int loopc = audio->loopCount();
				int cmode = song->cycleMode(); // CYCLE_NORMAL, CYCLE_MIX, CYCLE_REPLACE
				// If we want REPLACE and the event was recorded in a previous loop,
				//  just ignore it. This will effectively ignore ALL previous loop events inside
				//  the left and right markers, regardless of where recording was started or stopped.
				// We want to keep any loop 0 note-offs from notes which crossed over the left marker.
				// To avoid more searching here, just keep ALL note-offs from loop 0, and let code below
				//  sort out and keep which ones had note-ons.
				if (!(ev.isNoteOff() && loopn == 0))
				{
					if (cmode == Song::CYCLE_REPLACE && loopn < loopc)
					{
						// Added by Tim. p3.3.8
						//printf("buildMidiEventList: CYCLE_REPLACE t:%d type:%d A:%d B:%d ln:%d lc:%d\n", tick, ev.type(), ev.dataA(), ev.dataB(), loopn, loopc);

						continue;
					}
					// If we want NORMAL, same as REPLACE except keep all events from the previous loop
					//  from rec stop position to right marker (and beyond).
					if (cmode == Song::CYCLE_NORMAL)
					{
						// Not sure of accuracy here. Adjust? Adjusted when used elsewhere?
						unsigned endRec = audio->getEndRecordPos().tick();
						if ((tick < endRec && loopn < loopc) || (tick >= endRec && loopn < (loopc - 1)))
						{
							// Added by Tim. p3.3.8
							//printf("buildMidiEventList: CYCLE_NORMAL t:%d type:%d A:%d B:%d ln:%d lc:%d\n", tick, ev.type(), ev.dataA(), ev.dataB(), loopn, loopc);

							continue;
						}
					}
				}
			}
		}

		Event e;
		switch (ev.type())
		{
			case ME_NOTEON:
				e.setType(Note);

				if (track->type() == Track::DRUM)
				{
					int instr = drumInmap[ev.dataA()];
					e.setPitch(instr);
				}
				else
				{
					e.setPitch(ev.dataA());
				}

				e.setVelo(ev.dataB());
				e.setLenTick(0);
				break;
			case ME_NOTEOFF:
				e.setType(Note);
				if (track->type() == Track::DRUM)
				{
					int instr = drumInmap[ev.dataA()];
					e.setPitch(instr);
				}
				else
					e.setPitch(ev.dataA());
				e.setVelo(0);
				e.setVeloOff(ev.dataB());
				e.setLenTick(0);
				break;
			case ME_POLYAFTER:
				e.setType(PAfter);
				e.setA(ev.dataA());
				e.setB(ev.dataB());
				break;
			case ME_CONTROLLER:
			{
				int val = ev.dataB();
				switch (ev.dataA())
				{
					case CTRL_HBANK:
						hbank = val;
						break;

					case CTRL_LBANK:
						lbank = val;
						break;

					case CTRL_HDATA:
						datah = val;
						// check if a CTRL_LDATA follows
						// e.g. wie have a 14 bit controller:
					{
						iMPEvent ii = i;
						++ii;
						bool found = false;
						for (; ii != el->end(); ++ii)
						{
							MidiPlayEvent ev = *ii;
							if (ev.type() == ME_CONTROLLER)
							{
								if (ev.dataA() == CTRL_LDATA)
								{
									// handle later
									found = true;
								}
								break;
							}
						}
						if (!found)
						{
							if (rpnh == -1 || rpnl == -1)
							{
								printf("parameter number not defined, data 0x%x\n", datah);
							}
							else
							{
								int ctrl = dataType | (rpnh << 8) | rpnl;
								e.setType(Controller);
								e.setA(ctrl);
								e.setB(datah);
							}
						}
					}
						break;

					case CTRL_LDATA:
						datal = val;

						if (rpnh == -1 || rpnl == -1)
						{
							printf("parameter number not defined, data 0x%x 0x%x, tick %d, channel %d\n",
									datah, datal, tick, track->outChannel());
							break;
						}
						// assume that the sequence is always
						//    CTRL_HDATA - CTRL_LDATA
						// eg. that LDATA is always send last

						e.setType(Controller);
						// 14 Bit RPN/NRPN
						e.setA((dataType + 0x30000) | (rpnh << 8) | rpnl);
						e.setB((datah << 7) | datal);
						break;

					case CTRL_HNRPN:
						rpnh = val;
						dataType = 0x30000;
						break;

					case CTRL_LNRPN:
						rpnl = val;
						dataType = 0x30000;
						break;

					case CTRL_HRPN:
						rpnh = val;
						dataType = 0x20000;
						break;

					case CTRL_LRPN:
						rpnl = val;
						dataType = 0x20000;
						break;

					default:
						e.setType(Controller);
						int ctl = ev.dataA();
						e.setA(ctl);

						if (track->type() == Track::DRUM)
						{
							// Is it a drum controller event, according to the track port's instrument?
							MidiController *mc = midiPorts[track->outPort()].drumController(ctl);
							if (mc)
								// Store an index into the drum map.
								e.setA((ctl & ~0xff) | drumInmap[ctl & 0x7f]);
						}

						e.setB(val);
						break;
				}
			}
				break;

			case ME_PROGRAM:
				e.setType(Controller);
				e.setA(CTRL_PROGRAM);
				e.setB((hbank << 16) | (lbank << 8) | ev.dataA());
				break;

			case ME_AFTERTOUCH:
				e.setType(CAfter);
				e.setA(ev.dataA());
				break;

			case ME_PITCHBEND:
				e.setType(Controller);
				e.setA(CTRL_PITCH);
				e.setB(ev.dataA());
				break;

			case ME_SYSEX:
				e.setType(Sysex);
				e.setData(ev.data(), ev.len());
				break;

			case ME_META:
			{
				const unsigned char* data = ev.data();
				switch (ev.dataA())
				{
					case 0x01: // Text
						if (track->comment().isEmpty())
							track->setComment(QString((const char*) data));
						else
							track->setComment(track->comment() + "\n" + QString((const char*) data));
						break;
					case 0x03: // Sequence-/TrackName
						track->setName(QString((char*) data));
						break;
					case 0x6: // Marker
					{
						unsigned ltick = CALC_TICK(tick); //(tick * config.division + div/2) / div;
						song->addMarker(QString((const char*) (data)), ltick, false);
					}
						break;
					case 0x5: // Lyrics
					case 0x8: // text
					case 0x9:
					case 0xa:
						break;

					case 0x0f: // Track Comment
						track->setComment(QString((char*) data));
						break;
					case 0x51: // Tempo
					{
						unsigned tempo = data[2] + (data[1] << 8) + (data[0] << 16);
						unsigned ltick = CALC_TICK(tick); // (unsigned(tick) * unsigned(config.division) + unsigned(div/2)) / unsigned(div);
						// After ca 10 mins 32 bits will not be enough... This expression has to be changed/factorized or so in some "sane" way...
						tempomap.addTempo(ltick, tempo);
					}
						break;
					case 0x58: // Time Signature
					{
						int timesig_z = data[0];
						int n = data[1];
						int timesig_n = 1;
						for (int i = 0; i < n; i++)
							timesig_n *= 2;
						int ltick = CALC_TICK(tick); //(tick * config.division + div/2) / div;
						///sigmap.add(ltick, timesig_z, timesig_n);
						AL::sigmap.add(ltick, AL::TimeSignature(timesig_z, timesig_n));
					}
						break;
					case 0x59: // Key Signature
						// track->scale.set(data[0]);
						// track->scale.setMajorMinor(data[1]);
						break;
					default:
						printf("unknown Meta 0x%x %d\n", ev.dataA(), ev.dataA());
				}
			}
				break;
		} // switch(ev.type()
		if (!e.empty())
		{
			e.setTick(tick);
			// Added by Tim. p3.3.8
			//printf("buildMidiEventList: mel adding t:%d type:%d A:%d B:%d C:%d\n", tick, e.type(), e.dataA(), e.dataB(), e.dataC());

			mel.add(e);
		}
	} // i != el->end()

	//---------------------------------------------------
	//    resolve NoteOff events
	//---------------------------------------------------

	//      for (iEvent i = mel.begin(); i != mel.end(); ++i) {
	//            Event event = i->second;
	//            if (event.isNote())
	//                  event.setLenTick(0);
	//            }

	// Added by Tim. p3.3.8

	// The loop is a safe way to delete while iterating.
	bool loop;
	do
	{
		loop = false;

		for (iEvent i = mel.begin(); i != mel.end(); ++i)
		{
			Event ev = i->second;
			if (ev.isNote())
			{
				if (ev.isNoteOff())
				{
					iEvent k;
					bool found = false;
					for (k = i; k != mel.end(); ++k)
					{
						Event event = k->second;
						if (event.tick() > ev.tick())
							break;
						if (event.isNoteOff(ev))
						{
							ev.setLenTick(1);
							ev.setVelo(event.velo());
							ev.setVeloOff(0);
							// Added by Tim. p3.3.8
							//printf("buildMidiEventList: found note off: event t:%d len:%d type:%d A:%d B:%d C:%d  ev t:%d len:%d type:%d A:%d B:%d C:%d\n", event.tick(), event.lenTick(), event.type(), event.dataA(), event.dataB(), event.dataC(), ev.tick(), ev.lenTick(), ev.type(), ev.dataA(), ev.dataB(), ev.dataC());

							found = true;
							break;
						}
					}
					if (!found)
					{
						printf("NOTE OFF without Note ON tick %d type %d  %d %d\n",
								ev.tick(), ev.type(), ev.pitch(), ev.velo());
					}
					else
					{
						mel.erase(k);

						// Changed by Tim. p3.3.8
						//continue;
						loop = true;
						break;

					}
				}
				// Added by Tim. p3.3.8

				// If the event length is not zero, it means the event and its
				//  note on/off have already been taken care of. So ignore it.
				if (ev.lenTick() != 0)
				{
					continue;
				}

				iEvent k;
				for (k = mel.lower_bound(ev.tick()); k != mel.end(); ++k)
				{
					Event event = k->second;
					if (ev.isNoteOff(event))
					{
						int t = k->first - i->first;
						if (t <= 0)
						{
							if (debugMsg)
							{
								printf("Note len is (%d-%d)=%d, set to 1\n",
										k->first, i->first, k->first - i->first);
								ev.dump();
								event.dump();
							}
							t = 1;
						}
						ev.setLenTick(t);
						ev.setVeloOff(event.veloOff());
						// Added by Tim. p3.3.8
						//printf("buildMidiEventList: set len and velOff: event t:%d len:%d type:%d A:%d B:%d C:%d  ev t:%d len:%d type:%d A:%d B:%d C:%d\n", event.tick(), event.lenTick(), event.type(), event.dataA(), event.dataB(), event.dataC(), ev.tick(), ev.lenTick(), ev.type(), ev.dataA(), ev.dataB(), ev.dataC());

						break;
					}
				}
				if (k == mel.end())
				{
					printf("-no note-off! %d pitch %d velo %d\n",
							ev.tick(), ev.pitch(), ev.velo());
					//
					// switch off at end of measure
					//
					int endTick = song->roundUpBar(ev.tick() + 1);
					ev.setLenTick(endTick - ev.tick());
				}
				else
				{
					mel.erase(k);
					// Added by Tim. p3.3.8
					loop = true;
					break;

				}
			}
		}
	} while (loop);

	// DEBUG: any note offs left?

	// Removed by Tim. p3.3.8
	//for (iEvent i = mel.begin(); i != mel.end(); ++i) {
	//      Event ev  = i->second;
	//      if (ev.isNoteOff()) {
	//            printf("+extra note-off! %d pitch %d velo %d\n",
	//                     i->first, ev.pitch(), ev.velo());
	//                  ev.dump();
	//            }
	//      }

	for (iEvent i = mel.begin(); i != mel.end(); ++i)
	{
		Event ev = i->second;
		if (ev.isNoteOff())
		{
			printf("+extra note-off! %d pitch %d velo %d\n",
					i->first, ev.pitch(), ev.velo());
			//                  ev.dump();
			continue;
		}
		int tick = CALC_TICK(ev.tick()); //(ev.tick() * config.division + div/2) / div;
		if (ev.isNote())
		{
			int lenTick = CALC_TICK(ev.lenTick()); //(ev.lenTick() * config.division + div/2) / div;
			ev.setLenTick(lenTick);
		}
		ev.setTick(tick);
		del->add(ev);
	}
}
Exemplo n.º 16
0
bool LOS::importMidi(const QString name, bool merge)/*{{{*/
{
    bool popenFlag;
    FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag);
    if (fp == 0)
        return true;
    MidiFile mf(fp);
    bool rv = mf.read();
    popenFlag ? pclose(fp) : fclose(fp);
    if (rv)
    {
        QString s(tr("reading midifile\n  "));
        s += name;
        s += tr("\nfailed: ");
        s += mf.error();
        QMessageBox::critical(this, QString("LOS"), s);
        return rv;
    }
    //
    //  evaluate song Type (GM, XG, GS, unknown)
    //
    MType t = song->midiType();
    if (!merge)
    {
        t = mf.mtype();
        song->setMType(t);
    }
    MidiInstrument* instr = 0;
    for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i)
    {
        MidiInstrument* mi = *i;
        if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MIDI_TYPE_GM)))
                || ((mi->iname() == "GS") && (t == MT_GS))
                || ((mi->iname() == "XG") && (t == MT_XG)))
        {
            instr = mi;
            break;
        }
    }
    if (instr == 0)
    {
        // the standard instrument files (GM, GS, XG) must be present
        printf("no instrument, type %d\n", t);
        return true;
        //abort();
    }

    MidiFileTrackList* etl = mf.trackList();
    int division = mf.division();

    //
    // create MidiTrack and copy events to ->events()
    //    - combine note on/off events
    //    - calculate tick value for internal resolution
    //
    for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t)
    {
        MPEventList* el = &((*t)->events);
        if (el->empty())
            continue;
        //
        // if we split the track, SYSEX and META events go into
        // the first target track

        bool first = true;
        // somewhat silly and slooow:
        for (int port = 0; port < kMaxMidiPorts; ++port)
        {
            for (int channel = 0; channel < kMaxMidiChannels; ++channel)
            {
                //
                // check if there are any events for port/channel in track:
                //
                iMPEvent i;
                for (i = el->begin(); i != el->end(); ++i)
                {
                    MidiPlayEvent ev = *i;
                    if (ev.type() != ME_SYSEX && ev.type() != ME_META
                            && ev.channel() == channel && ev.port() == port)
                        break;
                }
                if (i == el->end())
                    continue;
                MidiTrack* track = new MidiTrack();
                if ((*t)->isDrumTrack)
                {
                    track->setType(Track::DRUM);
                }

                track->setOutChannel(channel);
                track->setOutPort(port);

                MidiPort* mport = &midiPorts[track->outPort()];
                // this overwrites any instrument set for this port:
                mport->setInstrument(instr);

                EventList* mel = track->events();
                //buildMidiEventList(mel, el, track, division, first);
                // Don't do loops.
                buildMidiEventList(mel, el, track, division, first, false);
                first = false;

                // Hmm. buildMidiEventList already takes care of this.
                // But it seems to work. How? Must test.
                if (channel == 9 && song->midiType() != MT_UNKNOWN)
                {
                    track->setType(Track::DRUM);
                    //
                    // remap drum pitch with drumInmap
                    //
                    EventList* tevents = track->events();
                    for (iEvent i = tevents->begin(); i != tevents->end(); ++i)
                    {
                        Event ev = i->second;
                        if (ev.isNote())
                        {
                            int pitch = drumInmap[ev.pitch()];
                            ev.setPitch(pitch);
                        }
                        else
                            if (ev.type() == Controller)
                        {
                            int ctl = ev.dataA();
                            MidiController *mc = mport->drumController(ctl);
                            if (mc)
                                ev.setA((ctl & ~0xff) | drumInmap[ctl & 0x7f]);
                        }
                    }
                }

                processTrack(track);

                song->insertTrack(track, -1);
            }
        }
        if (first)
        {
            //
            // track does only contain non-channel messages
            // (SYSEX or META)
            //
            MidiTrack* track = new MidiTrack();
            track->setOutChannel(0);
            track->setOutPort(0);
            EventList* mel = track->events();
            //buildMidiEventList(mel, el, track, division, true);
            // Do SysexMeta. Don't do loops.
            buildMidiEventList(mel, el, track, division, true, false);
            processTrack(track);
            song->insertTrack(track, -1);
        }
    }

    if (!merge)
    {
        TrackList* tl = song->tracks();
        if (!tl->empty())
        {
            Track* track = tl->front();
            track->setSelected(true);
        }
        song->initLen();

        int z, n;
        ///sigmap.timesig(0, z, n);
        sigmap.timesig(0, z, n);

        int tempo = tempomap.tempo(0);
        transport->setTimesig(z, n);
        transport->setTempo(tempo);

        bool masterF = !tempomap.empty();
        song->setMasterFlag(masterF);
        transport->setMasterFlag(masterF);

        song->updatePos();

        composer->reset();
        ///composer->setMode(int(song->midiType())); // p4.0.7 Tim
    }
    else
    {
        song->initLen();
    }

    return false;
}/*}}}*/
Exemplo n.º 17
0
bool LOS::importMidi(const QString name, bool merge)/*{{{*/
{
    bool popenFlag;
    FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag);
    if (fp == 0)
        return true;
    MidiFile mf(fp);
    bool rv = mf.read();
    popenFlag ? pclose(fp) : fclose(fp);
    if (rv)
    {
        QString s(tr("reading midifile\n  "));
        s += name;
        s += tr("\nfailed: ");
        s += mf.error();
        QMessageBox::critical(this, QString("LOS"), s);
        return rv;
    }
    //
    //  evaluate song Type (GM, XG, GS, unknown)
    //
    MType t = song->midiType();
    if (!merge)
    {
        t = mf.mtype();
        song->setMType(t);
    }
    MidiInstrument* instr = 0;
    for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i)
    {
        MidiInstrument* mi = *i;
        if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MIDI_TYPE_GM)))
                || ((mi->iname() == "GS") && (t == MT_GS))
                || ((mi->iname() == "XG") && (t == MT_XG)))
        {
            instr = mi;
            break;
        }
    }
    if (instr == 0)
    {
        // the standard instrument files (GM, GS, XG) must be present
        printf("no instrument, type %d\n", t);
        return true;
        //abort();
    }

    MidiFileTrackList* etl = mf.trackList();
    int division = mf.division();

    //
    // create MidiTrack and copy events to ->events()
    //    - combine note on/off events
    //    - calculate tick value for internal resolution
    //
    int mPort = getFreeMidiPort();
    for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t)
    {
        MPEventList* el = &((*t)->events);
        if (el->empty())
            continue;
        //
        // if we split the track, SYSEX and META events go into
        // the first target track

        bool first = true;
        // somewhat silly and slooow:
        QList<QPair<int, int> > eventChannelList;
        if(mPort >= 0 && mPort < kMaxMidiPorts)
        {
            for (int channel = 0; channel < kMaxMidiChannels; ++channel)
            {
                //
                // check if there are any events for port/channel in track:
                //
                iMPEvent i;
                for (i = el->begin(); i != el->end(); ++i)
                {
                    MidiPlayEvent ev = *i;
                    if (ev.type() != ME_SYSEX && ev.type() != ME_META && ev.channel() == channel)
                        break;
                }
                if (i == el->end())
                    continue;
                MidiTrack* track = new MidiTrack();
                track->setDefaultName();
                track->setMasterFlag(true);

                track->setOutChannel(channel);
                track->setOutPort(mPort);

                MidiPort* mport = &midiPorts[track->outPort()];
                // this overwrites any instrument set for this port:
                mport->setInstrument(instr);

                EventList* mel = track->events();
                buildMidiEventList(mel, el, track, division, first, false, false);

                first = false;

                processTrack(track);

                song->insertTrack(track, -1);
                //Create the Audio input side of the track
                Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false);
                if(input)
                {
                    input->setMasterFlag(false);
                    input->setChainMaster(track->id());
                    track->addManagedTrack(input->id());
                }
            }
        }
        if (first)
        {
            //
            // track does only contain non-channel messages
            // (SYSEX or META)
            //
            MidiTrack* track = new MidiTrack();
            track->setDefaultName();
            track->setMasterFlag(true);
            track->setOutChannel(0);
            track->setOutPort(mPort);
            EventList* mel = track->events();
            //buildMidiEventList(mel, el, track, division, true);
            // Do SysexMeta. Don't do loops.
            buildMidiEventList(mel, el, track, division, true, false, false);
            processTrack(track);
            song->insertTrack(track, -1);
            //Create the Audio input side of the track
            Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false);
            if(input)
            {
                input->setMasterFlag(false);
                input->setChainMaster(track->id());
                track->addManagedTrack(input->id());
            }
        }
        mPort++;
        //FIXME: Provice a non-iterative way to do this using the new losMidiPorts hash
        //Or maintain a list of configured or inuse ports
        while((&midiPorts[mPort])->device() && mPort < kMaxMidiPorts)
            mPort++;//Just incase we have a configured port after an empty one
    }

    if (!merge)
    {
        TrackList* tl = song->tracks();
        if (!tl->empty())
        {
            Track* track = tl->front();
            track->setSelected(true);
        }
        song->initLen();

        int z, n;
        sigmap.timesig(0, z, n);

        int tempo = tempomap.tempo(0);
        transport->setTimesig(z, n);
        transport->setTempo(tempo);

        bool masterF = !tempomap.empty();
        song->setMasterFlag(masterF);
        transport->setMasterFlag(masterF);

        song->updatePos();

        composer->reset();
    }
    else
    {
        song->initLen();
    }

    return false;
}/*}}}*/