Beispiel #1
0
void MidiPort::tryCtrlInitVal(int chan, int ctl, int val)
{
	//printf("Entering: MidiPort::tryCtrlInitVal\n");
	if (_instrument)
	{
		MidiControllerList* cl = _instrument->controller();
		ciMidiController imc = cl->find(ctl);
		if (imc != cl->end())
		{
			MidiController* mc = imc->second;
			int initval = mc->initVal();

			// Initialize from either the instrument controller's initial value, or the supplied value.
			if (initval != CTRL_VAL_UNKNOWN)
			{
				if (_device)
				{
					MidiPlayEvent ev(0, portno(), chan, ME_CONTROLLER, ctl, initval + mc->bias());
					_device->putEvent(ev);
				}
				setHwCtrlStates(chan, ctl, CTRL_VAL_UNKNOWN, initval + mc->bias());

				return;
			}
		}
	}

	if (_device)
	{
		//MidiPlayEvent ev(song->cpos(), portno(), chan, ME_CONTROLLER, ctl, val);
		MidiPlayEvent ev(0, portno(), chan, ME_CONTROLLER, ctl, val);
		_device->putEvent(ev);
	}
	// Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
	//setHwCtrlState(chan, ctl, val);
	// Set it again so that control labels show 'off'...
	//setHwCtrlState(chan, ctl, CTRL_VAL_UNKNOWN);
	setHwCtrlStates(chan, ctl, CTRL_VAL_UNKNOWN, val);
}
Beispiel #2
0
void LOS::importController(int channel, MidiPort* mport, int n)
{
    MidiInstrument* instr = mport->instrument();
    MidiCtrlValListList* vll = mport->controller();
    iMidiCtrlValList i = vll->find(channel, n);
    if (i != vll->end())
        return; // controller does already exist
    MidiController* ctrl = 0;
    MidiControllerList* mcl = instr->controller();
    // printf("import Ctrl\n");
    for (iMidiController i = mcl->begin(); i != mcl->end(); ++i)
    {
        MidiController* mc = i->second;
        int cn = mc->num();
        // printf("   %x %x\n", n, cn);
        if (cn == n)
        {
            ctrl = mc;
            break;
        }
        // wildcard?
        if (((cn & 0xff) == 0xff) && ((cn & ~0xff) == (n & ~0xff)))
        {
            ctrl = i->second;
            break;
        }
    }
    if (ctrl == 0)
    {
        printf("controller 0x%x not defined for instrument %s, channel %d\n",
                n, instr->iname().toLatin1().constData(), channel);
        // TODO: register default Controller
        //      MidiController* MidiPort::midiController(int num) const
    }
    MidiCtrlValList* newValList = new MidiCtrlValList(n);
    vll->add(channel, newValList);
}
Beispiel #3
0
void updateBypassMode(){
#ifdef OWLMODULAR
  bypass = false;
  updateLed();
#else
  if(isStompSwitchPressed()){
    bypass = true;
    setLed(NONE);
    midi.sendCc(LED, 0);
  }else{
    bypass = false;
    updateLed();
  }
#endif
}
Beispiel #4
0
void MidiInstrument::read(Xml& xml)
      {
      for (;;) {
            Xml::Token token = xml.parse();
            const QString& tag = xml.s1();
            switch (token) {
                  case Xml::Error:
                  case Xml::End:
                        return;
                  case Xml::TagStart:
                        if (tag == "Patch") {
                              Patch* patch = new Patch;
                              patch->read(xml);
                              if (pg.empty()) {
                                    PatchGroup* p = new PatchGroup;
                                    p->patches.push_back(patch);
                                    pg.push_back(p);
                                    }
                              else
                                    pg[0]->patches.push_back(patch);
                              }
                        else if (tag == "PatchGroup") {
                              PatchGroup* p = new PatchGroup;
                              p->read(xml);
                              pg.push_back(p);
                              }
                        else if (tag == "Controller") {
                              MidiController* mc = new MidiController();
                              mc->read(xml);
                              //
                              // HACK: make predefined "Program" controller overloadable
                              //
                              if (mc->name() == "Program") {
                                    for (iMidiController i = _controller->begin(); i != _controller->end(); ++i) {
                                          if (i->second->name() == mc->name()) {
                                                delete i->second;
                                                _controller->del(i);
                                                break;
                                                }
                                          }
                                    }

                              _controller->add(mc);
                              }
                        else if (tag == "Drummaps") {
                              readDrummaps(xml);
                              }
                        else if (tag == "Init")
                              readEventList(xml, _midiInit, "Init");
                        else if (tag == "Reset")
                              readEventList(xml, _midiReset, "Reset");
                        else if (tag == "State")
                              readEventList(xml, _midiState, "State");
                        else if (tag == "InitScript") {
                              if (_initScript)
                                    delete _initScript;
                              QByteArray ba = xml.parse1().toLatin1();
                              const char* istr = ba.constData();
                              int len = ba.length() +1;
                              if (len > 1) {
                                    _initScript = new char[len];
                                    memcpy(_initScript, istr, len);
                                    }
                              }
                        else if (tag == "SysEx") {
                              SysEx* se = new SysEx;
                              if(!se->read(xml))
                              {
                                delete se;
                                printf("MidiInstrument::read():SysEx: reading sysex failed\n");
                              }
                              else
                                _sysex.append(se);
                              }
                        else
                              xml.unknown("MidiInstrument");
                        break;
                  case Xml::Attribut:
                        if (tag == "name")
                              setIName(xml.s2());
                        else if(tag == "nullparam") { } // Obsolete.
                        else if(tag == "NoteOffMode") 
                              _noteOffMode = (NoteOffMode)xml.s2().toInt(); // Default is NoteOffAll.
                        break;
                  case Xml::TagEnd:
                        if (tag == "MidiInstrument")
                              return;
                  default:
                        break;
                  }
            }
      }
Beispiel #5
0
void toggleActiveSlot(){
  patches.toggleActiveSlot();
  updateLed();
  midi.sendPatchParameterNames(); // todo: this should probably be requested from client
}
Beispiel #6
0
void updateLed(){
  setLed((LedPin)patches.getActiveSlot());
  midi.sendCc(LED, getLed() == GREEN ? 42 : 84);
}
Beispiel #7
0
void setup(){
//   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 0 bits for preemption, 4 bits for subpriority
  /* Set up interrupt controller: 2 bits for priority (0-3),
   * 2 bits for sub-priority (0-3). Priorities control which
   * interrupts are allowed to preempt one another.
   */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  /* Increase SysTick priority to be higher than USB interrupt
   * priority. USB code stalls inside interrupt and we can't let
   * this throw off the SysTick timer.
   */
  NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, SYSTICK_PRIORITY, SYSTICK_SUBPRIORITY));
  NVIC_SetPriority(DMA1_Stream3_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 0, 0));
  NVIC_SetPriority(DMA1_Stream4_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 0, 0));
  NVIC_SetPriority(SPI2_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 1, 0));
  NVIC_SetPriority(ADC_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 2, 0));

  ledSetup();
  setLed(RED);

  /* check if we need to DFU boot */
  configureDigitalInput(SWITCH_B_PORT, SWITCH_B_PIN, GPIO_PuPd_UP);
  if(isPushButtonPressed())
    jump_to_bootloader();

  adcSetup();
  clockSetup();
  setupSwitchA(footSwitchCallback);
  setupSwitchB(pushButtonCallback);

  settings.init();
  midi.init(MIDI_CHANNEL);
  patches.init();

#ifdef EXPRESSION_PEDAL
#ifndef OWLMODULAR
  setupExpressionPedal();
#endif
#endif

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // DEBUG
  configureDigitalOutput(GPIOB, GPIO_Pin_1); // PB1, DEBUG LED
  debugClear();

#ifdef DEBUG_AUDIO
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // DEBUG
  configureDigitalOutput(GPIOA, GPIO_Pin_7); // PA7 DEBUG
  configureDigitalOutput(GPIOC, GPIO_Pin_5); // PC5 DEBUG
  clearPin(GPIOC, GPIO_Pin_5); // DEBUG
  clearPin(GPIOA, GPIO_Pin_7); // DEBUG
#endif /* DEBUG_AUDIO */
	
  usb_init();

#if SERIAL_PORT == 1
  setupSerialPort1(115200);
#elif SERIAL_PORT == 2
  setupSerialPort2(115200); // expression pedal
#warning expression pedal jack configured as serial port
#ifdef EXPRESSION_PEDAL
#error invalid configuration
#endif
#endif

#ifdef OWLMODULAR
  configureDigitalInput(GPIOB, GPIO_Pin_6, GPIO_PuPd_NOPULL);  // PB6 OWL Modular digital input
  configureDigitalOutput(GPIOB, GPIO_Pin_7);  // PB7 OWL Modular digital output
  setPin(GPIOB, GPIO_Pin_7); // PB7 OWL Modular digital output
#endif

  codec.setup();
  codec.init(settings);

  printString("startup\n");
  updateBypassMode();

  codec.start();
}
Beispiel #8
0
void MidiDevice::handleSeek()
{
  // If the device is not in use by a port, don't bother it.
  if(_port == -1)
    return;
  
  MidiPort* mp = &MusEGlobal::midiPorts[_port];
  MidiInstrument* instr = mp->instrument();
  MidiCtrlValListList* cll = mp->controller();
  unsigned pos = MusEGlobal::audio->tickPos();
  
  //---------------------------------------------------
  //    Send STOP 
  //---------------------------------------------------
    
  // Don't send if external sync is on. The master, and our sync routing system will take care of that.  
  if(!MusEGlobal::extSyncFlag.value())
  {
    if(mp->syncInfo().MRTOut())
    {
      // Shall we check for device write open flag to see if it's ok to send?...
      //if(!(rwFlags() & 0x1) || !(openFlags() & 1))
      //if(!(openFlags() & 1))
      //  continue;
      mp->sendStop();
    }    
  }

  //---------------------------------------------------
  //    If playing, clear all notes and flush out any
  //     stuck notes which were put directly to the device
  //---------------------------------------------------
  
  if(MusEGlobal::audio->isPlaying()) 
  {
    _playEvents.clear();
    for(iMPEvent i = _stuckNotes.begin(); i != _stuckNotes.end(); ++i) 
    {
      MidiPlayEvent ev(*i);
      ev.setTime(0);
      putEvent(ev);  // For immediate playback try putEvent, putMidiEvent, or sendEvent (for the optimizations).
    }
    _stuckNotes.clear();
  }
  
  //---------------------------------------------------
  //    Send new controller values
  //---------------------------------------------------
    
  // Find channels on this port used in the song...
  bool usedChans[MIDI_CHANNELS];
  int usedChanCount = 0;
  for(int i = 0; i < MIDI_CHANNELS; ++i)
    usedChans[i] = false;
  if(MusEGlobal::song->click() && MusEGlobal::clickPort == _port)
  {
    usedChans[MusEGlobal::clickChan] = true;
    ++usedChanCount;
  }
  bool drum_found = false;
  for(ciMidiTrack imt = MusEGlobal::song->midis()->begin(); imt != MusEGlobal::song->midis()->end(); ++imt)
  {
    //------------------------------------------------------------
    //    While we are at it, flush out any track-related playback stuck notes
    //     (NOT 'live' notes) which were not put directly to the device
    //------------------------------------------------------------
    MPEventList& mel = (*imt)->stuckNotes;
    for(iMPEvent i = mel.begin(), i_next = i; i != mel.end(); i = i_next)
    {
      ++i_next;

      if((*i).port() != _port)
        continue;
      MidiPlayEvent ev(*i);
      ev.setTime(0);
      putEvent(ev); // For immediate playback try putEvent, putMidiEvent, or sendEvent (for the optimizations).
      mel.erase(i);
    }
    
    if((*imt)->type() == MusECore::Track::DRUM)
    {
      if(!drum_found)
      {
        drum_found = true; 
        for(int i = 0; i < DRUM_MAPSIZE; ++i)
        {
          // Default to track port if -1 and track channel if -1.
          int mport = MusEGlobal::drumMap[i].port;
          if(mport == -1)
            mport = (*imt)->outPort();
          int mchan = MusEGlobal::drumMap[i].channel;
          if(mchan == -1)
            mchan = (*imt)->outChannel();
          if(mport != _port || usedChans[mchan])
            continue;
          usedChans[mchan] = true;
          ++usedChanCount;
          if(usedChanCount >= MIDI_CHANNELS)
            break;  // All are used, done searching.
        }
      }
    }
    else
    {
      if((*imt)->outPort() != _port || usedChans[(*imt)->outChannel()])
        continue;
      usedChans[(*imt)->outChannel()] = true;
      ++usedChanCount;
    }

    if(usedChanCount >= MIDI_CHANNELS)
      break;    // All are used. Done searching.
  }   
  
  for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl) 
  {
    MidiCtrlValList* vl = ivl->second;
    int chan = ivl->first >> 24;
    if(!usedChans[chan])  // Channel not used in song?
      continue;
    int ctlnum = vl->num();

    // Find the first non-muted value at the given tick...
    bool values_found = false;
    bool found_value = false;
    
    iMidiCtrlVal imcv = vl->lower_bound(pos);
    if(imcv != vl->end() && imcv->first == (int)pos)
    {
      for( ; imcv != vl->end() && imcv->first == (int)pos; ++imcv)
      {
        const Part* p = imcv->second.part;
        if(!p)
          continue;
        // Ignore values that are outside of the part.
        if(pos < p->tick() || pos >= (p->tick() + p->lenTick()))
          continue;
        values_found = true;
        // Ignore if part or track is muted or off.
        if(p->mute())
          continue;
        const Track* track = p->track();
        if(track && (track->isMute() || track->off()))
          continue;
        found_value = true;
        break;
      }
    }
    else
    {
      while(imcv != vl->begin())
      {
        --imcv;
        const Part* p = imcv->second.part;
        if(!p)
          continue;
        // Ignore values that are outside of the part.
        unsigned t = imcv->first;
        if(t < p->tick() || t >= (p->tick() + p->lenTick()))
          continue;
        values_found = true;
        // Ignore if part or track is muted or off.
        if(p->mute())
          continue;
        const Track* track = p->track();
        if(track && (track->isMute() || track->off()))
          continue;
        found_value = true;
        break;
      }
    }

    if(found_value)
    {
      // Don't bother sending any sustain values if not playing. Just set the hw state.
      if(ctlnum == CTRL_SUSTAIN && !MusEGlobal::audio->isPlaying())
        mp->setHwCtrlState(chan, CTRL_SUSTAIN, imcv->second.val);
      else
        // Use sendEvent to get the optimizations and limiting. But force if there's a value at this exact position.
        // NOTE: Why again was this forced? There was a reason. Think it was RJ in response to bug rep, then I modded.
        // A reason not to force: If a straight line is drawn on graph, multiple identical events are stored
        //  (which must be allowed). So seeking through them here sends them all redundantly, not good. // REMOVE Tim.
        mp->sendEvent(MidiPlayEvent(0, _port, chan, ME_CONTROLLER, ctlnum, imcv->second.val), false); //, imcv->first == pos);
        //mp->sendEvent(MidiPlayEvent(0, _port, chan, ME_CONTROLLER, ctlnum, imcv->second.val), pos == 0 || imcv->first == pos);
    }

    // Either no value was found, or they were outside parts, or pos is in the unknown area before the first value.
    // Send instrument default initial values.  NOT for syntis. Use midiState and/or initParams for that. 
    //if((imcv == vl->end() || !done) && !MusEGlobal::song->record() && instr && !isSynti()) 
    // Hmm, without refinement we can only do this at position 0, due to possible 'skipped' values outside parts, above.
    if(!values_found && MusEGlobal::config.midiSendCtlDefaults && !MusEGlobal::song->record() && pos == 0 && instr && !isSynti())
    {
      MidiControllerList* mcl = instr->controller();
      ciMidiController imc = mcl->find(vl->num());
      if(imc != mcl->end())
      {
        MidiController* mc = imc->second;
        if(mc->initVal() != CTRL_VAL_UNKNOWN)
          // Use sendEvent to get the optimizations and limiting. No force sending. Note the addition of bias.
          mp->sendEvent(MidiPlayEvent(0, _port, chan, ME_CONTROLLER, ctlnum, mc->initVal() + mc->bias()), false);
      }
    }
  }
  
  //---------------------------------------------------
  //    reset sustain
  //---------------------------------------------------
  
  for(int ch = 0; ch < MIDI_CHANNELS; ++ch) 
  {
    if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127) 
    {
      const MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
      putEvent(ev);
    }
  }
  
  //---------------------------------------------------
  //    Send STOP and "set song position pointer"
  //---------------------------------------------------
    
  // Don't send if external sync is on. The master, and our sync routing system will take care of that.  
  if(!MusEGlobal::extSyncFlag.value())
  {
    if(mp->syncInfo().MRTOut())
    {
      //mp->sendStop();   // Moved above
      int beat = (pos * 4) / MusEGlobal::config.division;
      mp->sendSongpos(beat);
    }    
  }
}
Beispiel #9
0
void MidiInstrument::read(Xml& xml)
{
    bool ok;
    int base = 10;
    _nullvalue = -1;
    m_keymaps.clear();
    for (;;)
    {
        Xml::Token token = xml.parse();
        const QString& tag = xml.s1();
        switch (token)
        {
            case Xml::Error:
            case Xml::End:
                return;
            case Xml::TagStart:
                if (tag == "Patch")
                {
                    Patch* patch = new Patch;
                    patch->read(xml);
                    if (pg.empty())
                    {
                        PatchGroup* p = new PatchGroup;
                        p->patches.push_back(patch);
                        pg.push_back(p);
                    }
                    else
                        pg[0]->patches.push_back(patch);
                }
                else if (tag == "PatchGroup")
                {
                    PatchGroup* p = new PatchGroup;
                    p->read(xml);
                    pg.push_back(p);
                }
                else if (tag == "Controller")
                {
                    MidiController* mc = new MidiController();
                    mc->read(xml);
                    // Added by Tim. Copied from los 2.
                    //
                    // HACK: make predefined "Program" controller overloadable
                    //
                    if (mc->name() == "Program")
                    {
                        for (iMidiController i = _controller->begin(); i != _controller->end(); ++i)
                        {
                            if (i->second->name() == mc->name())
                            {
                                delete i->second;
                                _controller->erase(i);
                                break;
                            }
                        }
                    }

                    _controller->add(mc);
                }
                else if (tag == "Init")
                    readEventList(xml, _midiInit, "Init");
                else if (tag == "Reset")
                    readEventList(xml, _midiReset, "Reset");
                else if (tag == "State")
                    readEventList(xml, _midiState, "State");
                else if (tag == "InitScript")
                {
                    if (_initScript)
                        delete _initScript;
                    QByteArray ba = xml.parse1().toLatin1();
                    const char* istr = ba.constData();
                    int len = strlen(istr) + 1;
                    if (len > 1)
                    {
                        _initScript = new char[len];
                        memcpy(_initScript, istr, len);
                    }
                }
                else if(tag == "KeyMap")
                {
                    KeyMap *km = new KeyMap;
                    km->read(xml);
                    m_keymaps.insert(km->key, km);
                }
                else
                    xml.unknown("MidiInstrument");
                break;
            case Xml::Attribut:
                if (tag == "name")
                    setIName(xml.s2());
                else if (tag == "nullparam")
                {
                    _nullvalue = xml.s2().toInt(&ok, base);
                }
                else if(tag == "panValue")
                    m_panValue = xml.s2().toDouble();
                break;
            case Xml::TagEnd:
                if (tag == "MidiInstrument")
                    return;
            default:
                break;
        }
    }
}