Exemple #1
0
MidiControllerList::MidiControllerList(const MidiControllerList& mcl) : std::map<int, MidiController*>()
{
  for(ciMidiController i = mcl.begin(); i != mcl.end(); ++i)
  {
    MidiController* mc = i->second;
    add(new MidiController(*mc));
  }  
}
Exemple #2
0
MidiController* MidiPort::midiController(int num) const
{
	if (_instrument && _device && _device->isSynthPlugin() == false)
	{
		MidiControllerList* mcl = _instrument->controller();
		for (iMidiController i = mcl->begin(); i != mcl->end(); ++i)
		{
			int cn = i->second->num();
			if (cn == num)
				return i->second;
			// wildcard?
			if (((cn & 0xff) == 0xff) && ((cn & ~0xff) == (num & ~0xff)))
				return i->second;
		}
	}

	for (iMidiController i = defaultMidiController.begin(); i != defaultMidiController.end(); ++i)
	{
		int cn = i->second->num();
		if (cn == num)
			return i->second;
		// wildcard?
		if (((cn & 0xff) == 0xff) && ((cn & ~0xff) == (num & ~0xff)))
			return i->second;
	}


	QString name = midiCtrlName(num);
	int min = 0;
	int max = 127;

	MidiController::ControllerType t = midiControllerType(num);
	switch (t)
	{
		case MidiController::RPN:
		case MidiController::NRPN:
		case MidiController::Controller7:
			max = 127;
			break;
		case MidiController::Controller14:
		case MidiController::RPN14:
		case MidiController::NRPN14:
			max = 16383;
			break;
		case MidiController::Program:
			max = 0xffffff;
			break;
		case MidiController::Pitch:
			max = 8191;
			min = -8192;
			break;
		case MidiController::Velo: // cannot happen
			break;
	}
	MidiController* c = new MidiController(name, num, min, max, 0);
	defaultMidiController.add(c);
	return c;
}
Exemple #3
0
void initMidiController()
{
	defaultMidiController.add(&veloCtrl);
	defaultMidiController.add(&pitchCtrl);
	defaultMidiController.add(&programCtrl);
	// Removed p3.3.37
	//defaultMidiController.add(&mastervolCtrl);
	defaultMidiController.add(&volumeCtrl);
	defaultMidiController.add(&panCtrl);
}
Exemple #4
0
MidiController* MidiPort::drumController(int ctl)
{
	if (!_instrument)
		return 0;

	MidiControllerList* cl = _instrument->controller();

	// If it's an RPN, NRPN, RPN14, or NRPN14 controller...
	if (((ctl - CTRL_RPN_OFFSET >= 0) && (ctl - CTRL_RPN_OFFSET <= 0xffff)) ||
			((ctl - CTRL_NRPN_OFFSET >= 0) && (ctl - CTRL_NRPN_OFFSET <= 0xffff)) ||
			((ctl - CTRL_RPN14_OFFSET >= 0) && (ctl - CTRL_RPN14_OFFSET <= 0xffff)) ||
			((ctl - CTRL_NRPN14_OFFSET >= 0) && (ctl - CTRL_NRPN14_OFFSET <= 0xffff)))
	{
		// Does the instrument have a drum controller to match this controller's number?
		iMidiController imc = cl->find(ctl | 0xff);
		if (imc != cl->end())
			// Yes, it's a drum controller. Return a pointer to it.
			return imc->second;
	}

	return 0;
}
Exemple #5
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);
}
Exemple #6
0
int MidiPort::limitValToInstrCtlRange(int ctl, int val)
{
	if (!_instrument || val == CTRL_VAL_UNKNOWN)
		return val;

	MidiControllerList* cl = _instrument->controller();

	// Is it a drum controller?
	MidiController *mc = drumController(ctl);
	if (!mc)
	{
		// It's not a drum controller. Find it as a regular controller instead.
		iMidiController imc = cl->find(ctl);
		if (imc != cl->end())
			mc = imc->second;
	}

	// If it's a valid controller, limit the value to the instrument controller range.
	if (mc)
		return limitValToInstrCtlRange(mc, val);

	return val;
}
Exemple #7
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);
}
Exemple #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);
    }    
  }
}