Reworked MIDI event handling in InstrumentTrack and renamed MIDI classes
The MIDI event handling in InstrumentTrack was complex and buggy. It has been simplified now such that processInEvent() tries to handle note on, note off and key pressure events. The actions taken should result in equivalent calls to processOutEvent() by NotePlayHandle instances. The processOutEvent() function sends according MIDI events to the attached instruments. All unhandled MIDI events are directly forwarded to the instrument in processInEvent(). It's possible that some corner-cases are not handled yet with the new code and we have regressions now. Furthermore renamed midiTime/midiEvent to MidiTime/MidiEvent to match coding style. Closes #72.
This commit is contained in:
@@ -1744,8 +1744,7 @@ p->putValue( jt->pos, value, false );
|
||||
{
|
||||
continue;
|
||||
}
|
||||
trackContentObject * tco =
|
||||
bb_tracks[it->pattern]->createTCO( midiTime() );
|
||||
trackContentObject * tco = bb_tracks[it->pattern]->createTCO( MidiTime() );
|
||||
tco->movePosition( it->position );
|
||||
if( it->length != DefaultTicksPerTact )
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "pattern.h"
|
||||
#include "Instrument.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MidiTime.h"
|
||||
#include "debug.h"
|
||||
#include "embed.h"
|
||||
#include "song.h"
|
||||
@@ -152,7 +153,7 @@ public:
|
||||
|
||||
AutomationTrack * at;
|
||||
AutomationPattern * ap;
|
||||
midiTime lastPos;
|
||||
MidiTime lastPos;
|
||||
|
||||
smfMidiCC & create( TrackContainer* tc )
|
||||
{
|
||||
@@ -172,11 +173,11 @@ public:
|
||||
}
|
||||
|
||||
|
||||
smfMidiCC & putValue( midiTime time, AutomatableModel * objModel, float value )
|
||||
smfMidiCC & putValue( MidiTime time, AutomatableModel * objModel, float value )
|
||||
{
|
||||
if( !ap || time > lastPos + DefaultTicksPerTact )
|
||||
{
|
||||
midiTime pPos = midiTime( time.getTact(), 0 );
|
||||
MidiTime pPos = MidiTime( time.getTact(), 0 );
|
||||
ap = dynamic_cast<AutomationPattern*>(
|
||||
at->createTCO(0) );
|
||||
ap->movePosition( pPos );
|
||||
@@ -186,7 +187,7 @@ public:
|
||||
lastPos = time;
|
||||
time = time - ap->startPosition();
|
||||
ap->putValue( time, value, false );
|
||||
ap->changeLength( midiTime( time.getTact() + 1, 0 ) );
|
||||
ap->changeLength( MidiTime( time.getTact() + 1, 0 ) );
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -212,7 +213,7 @@ public:
|
||||
Instrument * it_inst;
|
||||
bool isSF2;
|
||||
bool hasNotes;
|
||||
midiTime lastEnd;
|
||||
MidiTime lastEnd;
|
||||
|
||||
smfMidiChannel * create( TrackContainer* tc )
|
||||
{
|
||||
@@ -247,7 +248,7 @@ public:
|
||||
{
|
||||
if( !p || n.pos() > lastEnd + DefaultTicksPerTact )
|
||||
{
|
||||
midiTime pPos = midiTime(n.pos().getTact(), 0 );
|
||||
MidiTime pPos = MidiTime( n.pos().getTact(), 0 );
|
||||
p = dynamic_cast<pattern *>( it->createTCO( 0 ) );
|
||||
p->movePosition( pPos );
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <QtCore/QPair>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
#include "midi.h"
|
||||
#include "MidiEvent.h"
|
||||
#include "ImportFilter.h"
|
||||
|
||||
|
||||
@@ -117,8 +117,8 @@ private:
|
||||
}
|
||||
|
||||
|
||||
typedef QVector<QPair<int, midiEvent> > eventVector;
|
||||
eventVector m_events;
|
||||
typedef QVector<QPair<int, MidiEvent> > EventVector;
|
||||
EventVector m_events;
|
||||
int m_timingDivision;
|
||||
|
||||
} ;
|
||||
|
||||
@@ -286,17 +286,16 @@ int opl2instrument::pushVoice(int v) {
|
||||
return i;
|
||||
}
|
||||
|
||||
bool opl2instrument::handleMidiEvent( const midiEvent & _me,
|
||||
const midiTime & _time )
|
||||
bool opl2instrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time )
|
||||
{
|
||||
emulatorMutex.lock();
|
||||
int key, vel, voice, tmp_pb;
|
||||
|
||||
switch(_me.m_type) {
|
||||
switch(event.type()) {
|
||||
case MidiNoteOn:
|
||||
// to get us in line with MIDI(?)
|
||||
key = _me.key() +12;
|
||||
vel = _me.velocity();
|
||||
key = event.key() +12;
|
||||
vel = event.velocity();
|
||||
|
||||
voice = popVoice();
|
||||
if( voice != OPL2_NO_VOICE ) {
|
||||
@@ -311,7 +310,7 @@ bool opl2instrument::handleMidiEvent( const midiEvent & _me,
|
||||
}
|
||||
break;
|
||||
case MidiNoteOff:
|
||||
key = _me.key() +12;
|
||||
key = event.key() +12;
|
||||
for(voice=0; voice<9; ++voice) {
|
||||
if( voiceNote[voice] == key ) {
|
||||
theEmulator->write(0xA0+voice, fnums[key] & 0xff);
|
||||
@@ -323,8 +322,8 @@ bool opl2instrument::handleMidiEvent( const midiEvent & _me,
|
||||
velocities[key] = 0;
|
||||
break;
|
||||
case MidiKeyPressure:
|
||||
key = _me.key() +12;
|
||||
vel = _me.velocity();
|
||||
key = event.key() +12;
|
||||
vel = event.velocity();
|
||||
if( velocities[key] != 0) {
|
||||
velocities[key] = vel;
|
||||
}
|
||||
@@ -337,12 +336,12 @@ bool opl2instrument::handleMidiEvent( const midiEvent & _me,
|
||||
case MidiPitchBend:
|
||||
// Update fnumber table
|
||||
// Pitchbend should be in the range 0...16383 but the new range knob gets it wrong.
|
||||
// tmp_pb = (2*BEND_CENTS)*((float)_me.m_data.m_param[0]/16383)-BEND_CENTS;
|
||||
// tmp_pb = (2*BEND_CENTS)*((float)event.m_data.m_param[0]/16383)-BEND_CENTS;
|
||||
|
||||
// Something like 100 cents = 8192, but offset by 8192 so the +/-100 cents range goes from 0...16383?
|
||||
tmp_pb = ( _me.m_data.m_param[0]-8192 ) * BEND_CENTS / 8192;
|
||||
tmp_pb = ( event.pitchBend()-8192 ) * BEND_CENTS / 8192;
|
||||
|
||||
printf("Pitch bend: %d -> %d cents\n",_me.m_data.m_param[0],tmp_pb);
|
||||
printf("Pitch bend: %d -> %d cents\n",event.pitchBend(),tmp_pb);
|
||||
if( tmp_pb != pitchbend ) {
|
||||
pitchbend = tmp_pb;
|
||||
tuneEqual(69, 440.0);
|
||||
@@ -356,7 +355,7 @@ bool opl2instrument::handleMidiEvent( const midiEvent & _me,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("Midi event type %d\n",_me.m_type);
|
||||
printf("Midi event type %d\n",event.type());
|
||||
}
|
||||
emulatorMutex.unlock();
|
||||
return true;
|
||||
|
||||
@@ -50,8 +50,7 @@ public:
|
||||
|
||||
inline virtual bool isMidiBased() const { return true; }
|
||||
|
||||
virtual bool handleMidiEvent( const midiEvent & _me,
|
||||
const midiTime & _time );
|
||||
virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time );
|
||||
virtual void play( sampleFrame * _working_buffer );
|
||||
|
||||
void saveSettings( QDomDocument & _doc, QDomElement & _this );
|
||||
|
||||
@@ -310,13 +310,12 @@ void vestigeInstrument::play( sampleFrame * _buf )
|
||||
|
||||
|
||||
|
||||
bool vestigeInstrument::handleMidiEvent( const midiEvent & _me,
|
||||
const midiTime & _time )
|
||||
bool vestigeInstrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time )
|
||||
{
|
||||
m_pluginMutex.lock();
|
||||
if( m_plugin != NULL )
|
||||
{
|
||||
m_plugin->processMidiEvent( _me, _time );
|
||||
m_plugin->processMidiEvent( event, time );
|
||||
}
|
||||
m_pluginMutex.unlock();
|
||||
|
||||
@@ -779,8 +778,7 @@ void VestigeInstrumentView::noteOffAll( void )
|
||||
{
|
||||
for( int key = 0; key <= MidiMaxNote; ++key )
|
||||
{
|
||||
m_vi->m_plugin->processMidiEvent(
|
||||
midiEvent( MidiNoteOff, 0, key, 0 ), 0 );
|
||||
m_vi->m_plugin->processMidiEvent( MidiEvent( MidiNoteOff, 0, key, 0 ), 0 );
|
||||
}
|
||||
}
|
||||
m_vi->m_pluginMutex.unlock();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* vestige.h - instrument VeSTige for hosting VST-plugins
|
||||
*
|
||||
* Copyright (c) 2005-2012 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
#include "Instrument.h"
|
||||
#include "InstrumentView.h"
|
||||
#include "midi.h"
|
||||
#include "note.h"
|
||||
#include "knob.h"
|
||||
|
||||
@@ -69,8 +68,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool handleMidiEvent( const midiEvent & _me,
|
||||
const midiTime & _time );
|
||||
virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time );
|
||||
|
||||
virtual PluginView * instantiateView( QWidget * _parent );
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* LocalZynAddSubFx.cpp - local implementation of ZynAddSubFx plugin
|
||||
*
|
||||
* Copyright (c) 2009-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2009-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -190,47 +190,43 @@ void LocalZynAddSubFx::setLmmsWorkingDir( const std::string & _dir )
|
||||
|
||||
|
||||
|
||||
void LocalZynAddSubFx::processMidiEvent( const midiEvent & _e )
|
||||
void LocalZynAddSubFx::processMidiEvent( const MidiEvent& event )
|
||||
{
|
||||
// all functions are called while m_master->mutex is held
|
||||
static NULLMidiIn midiIn;
|
||||
|
||||
switch( _e.m_type )
|
||||
switch( event.type() )
|
||||
{
|
||||
case MidiNoteOn:
|
||||
if( _e.velocity() > 0 )
|
||||
if( event.velocity() > 0 )
|
||||
{
|
||||
if( _e.key() <= 0 || _e.key() >= 128 )
|
||||
if( event.key() <= 0 || event.key() >= 128 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if( m_runningNotes[_e.key()] > 0 )
|
||||
if( m_runningNotes[event.key()] > 0 )
|
||||
{
|
||||
m_master->NoteOff( _e.channel(), _e.key() );
|
||||
m_master->NoteOff( event.channel(), event.key() );
|
||||
}
|
||||
++m_runningNotes[_e.key()];
|
||||
m_master->NoteOn( _e.channel(), _e.key(), _e.velocity() );
|
||||
++m_runningNotes[event.key()];
|
||||
m_master->NoteOn( event.channel(), event.key(), event.velocity() );
|
||||
break;
|
||||
}
|
||||
case MidiNoteOff:
|
||||
if( _e.key() <= 0 || _e.key() >= 128 )
|
||||
if( event.key() <= 0 || event.key() >= 128 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if( --m_runningNotes[_e.key()] <= 0 )
|
||||
if( --m_runningNotes[event.key()] <= 0 )
|
||||
{
|
||||
m_master->NoteOff( _e.channel(), _e.key() );
|
||||
m_master->NoteOff( event.channel(), event.key() );
|
||||
}
|
||||
break;
|
||||
case MidiPitchBend:
|
||||
m_master->SetController( _e.channel(), C_pitchwheel,
|
||||
_e.m_data.m_param[0] +
|
||||
_e.m_data.m_param[1]*128-8192 );
|
||||
m_master->SetController( event.channel(), C_pitchwheel, event.pitchBend()-8192 );
|
||||
break;
|
||||
case MidiControlChange:
|
||||
m_master->SetController( _e.channel(),
|
||||
midiIn.getcontroller( _e.m_data.m_param[0] ),
|
||||
_e.m_data.m_param[1] );
|
||||
m_master->SetController( event.channel(), midiIn.getcontroller( event.controllerNumber() ), event.controllerValue() );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* LocalZynAddSubFx.h - local implementation of ZynAddSubFx plugin
|
||||
*
|
||||
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2009-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -25,6 +25,7 @@
|
||||
#ifndef _LOCAL_ZYNADDSUBFX_H
|
||||
#define _LOCAL_ZYNADDSUBFX_H
|
||||
|
||||
#include "MidiEvent.h"
|
||||
#include "note.h"
|
||||
|
||||
class Master;
|
||||
@@ -48,7 +49,7 @@ public:
|
||||
void setPresetDir( const std::string & _dir );
|
||||
void setLmmsWorkingDir( const std::string & _dir );
|
||||
|
||||
void processMidiEvent( const midiEvent & _e );
|
||||
void processMidiEvent( const MidiEvent& event );
|
||||
|
||||
void processAudio( sampleFrame * _out );
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* RemoteZynAddSubFx.cpp - ZynAddSubFx-embedding plugin
|
||||
*
|
||||
* Copyright (c) 2008-2012 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
@@ -126,10 +126,9 @@ public:
|
||||
}
|
||||
|
||||
// all functions are called while m_master->mutex is held
|
||||
virtual void processMidiEvent( const midiEvent & _e,
|
||||
const f_cnt_t /* _offset */ )
|
||||
virtual void processMidiEvent( const MidiEvent& event, const f_cnt_t /* _offset */ )
|
||||
{
|
||||
LocalZynAddSubFx::processMidiEvent( _e );
|
||||
LocalZynAddSubFx::processMidiEvent( event );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -340,14 +340,13 @@ void ZynAddSubFxInstrument::play( sampleFrame * _buf )
|
||||
|
||||
|
||||
|
||||
bool ZynAddSubFxInstrument::handleMidiEvent( const midiEvent & _me,
|
||||
const midiTime & _time )
|
||||
bool ZynAddSubFxInstrument::handleMidiEvent( const MidiEvent& event, const MidiTime& time )
|
||||
{
|
||||
// do not forward external MIDI Control Change events if the according
|
||||
// LED is not checked
|
||||
if( _me.type() == MidiControlChange &&
|
||||
_me.sourcePort() != this &&
|
||||
m_forwardMidiCcModel.value() == false )
|
||||
if( event.type() == MidiControlChange &&
|
||||
event.sourcePort() != this &&
|
||||
m_forwardMidiCcModel.value() == false )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -355,11 +354,11 @@ bool ZynAddSubFxInstrument::handleMidiEvent( const midiEvent & _me,
|
||||
m_pluginMutex.lock();
|
||||
if( m_remotePlugin )
|
||||
{
|
||||
m_remotePlugin->processMidiEvent( _me, 0 );
|
||||
m_remotePlugin->processMidiEvent( event, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_plugin->processMidiEvent( _me );
|
||||
m_plugin->processMidiEvent( event );
|
||||
}
|
||||
m_pluginMutex.unlock();
|
||||
|
||||
@@ -446,8 +445,7 @@ void ZynAddSubFxInstrument::initPlugin()
|
||||
|
||||
void ZynAddSubFxInstrument::sendControlChange( MidiControllers midiCtl, float value )
|
||||
{
|
||||
handleMidiEvent( midiEvent( MidiControlChange, instrumentTrack()->midiPort()->realOutputChannel(), midiCtl, (int) value, this ),
|
||||
midiTime() );
|
||||
handleMidiEvent( MidiEvent( MidiControlChange, instrumentTrack()->midiPort()->realOutputChannel(), midiCtl, (int) value, this ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -70,8 +70,7 @@ public:
|
||||
|
||||
virtual void play( sampleFrame * _working_buffer );
|
||||
|
||||
virtual bool handleMidiEvent( const midiEvent & _me,
|
||||
const midiTime & _time );
|
||||
virtual bool handleMidiEvent( const MidiEvent& event, const MidiTime& time = MidiTime() );
|
||||
|
||||
virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent );
|
||||
virtual void loadSettings( const QDomElement & _this );
|
||||
|
||||
Reference in New Issue
Block a user