diff --git a/CHANGELOG b/CHANGELOG index 80506d27..d7ef511c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +1.6.0-bacon20 + Fixed MIDI muting + Added MIDI chord command (MCHD) + 1.6.0-bacon19 Create column Titles. * Every view will have a column title (or header). diff --git a/docs/wiki/What-is-LittlePiggyTracker.md b/docs/wiki/What-is-LittlePiggyTracker.md index cbc37348..14e9161d 100644 --- a/docs/wiki/What-is-LittlePiggyTracker.md +++ b/docs/wiki/What-is-LittlePiggyTracker.md @@ -546,6 +546,11 @@ don't forget trying to combine it with complex hop structure ! - LPOF is absolute - you can't trigger a note with the LPOF, it has to be executed after a sample is playing - every time you trigger a sample LPOF is set back to the instrument parameters + +## MCHD aabb + +Plays the notes aa and bb semitones higher than the last played note (modulo 128). Note that the value `00` is ignored. The chords tones will last as long as the root note, i.e. until another note is played on the channel. + ## MDCC aabb **Sends a MIDI “continuous control” message. aa is the control number and bb is the value. It will be sent on the MIDI channel of the currently running instrument.** diff --git a/sources/Application/Instruments/CommandList.cpp b/sources/Application/Instruments/CommandList.cpp index 812385c2..a740c5dd 100644 --- a/sources/Application/Instruments/CommandList.cpp +++ b/sources/Application/Instruments/CommandList.cpp @@ -1,35 +1,12 @@ #include "CommandList.h" -static FourCC _all[]= { - I_CMD_NONE, - I_CMD_ARPG, - I_CMD_CRSH, - I_CMD_DLAY, - I_CMD_FBMX, - I_CMD_FBTN, - I_CMD_FCUT, - I_CMD_FLTR, - I_CMD_FRES, - I_CMD_GROV, - I_CMD_HOP, - I_CMD_IRTG, - I_CMD_KILL, - I_CMD_LEGA, - I_CMD_LPOF, - I_CMD_MDCC, - I_CMD_MDPG, - I_CMD_MVEL, - I_CMD_PAN_, - I_CMD_PFIN, - I_CMD_PLOF, - I_CMD_PTCH, - I_CMD_RTRG, - I_CMD_STOP, - I_CMD_TABL, - I_CMD_TMPO, - I_CMD_VOLM -} ; +static FourCC _all[] = { + I_CMD_NONE, I_CMD_ARPG, I_CMD_CRSH, I_CMD_DLAY, I_CMD_FBMX, I_CMD_FBTN, + I_CMD_FCUT, I_CMD_FLTR, I_CMD_FRES, I_CMD_GROV, I_CMD_HOP, I_CMD_IRTG, + I_CMD_KILL, I_CMD_LEGA, I_CMD_LPOF, I_CMD_MCHD, I_CMD_MDCC, I_CMD_MDPG, + I_CMD_MVEL, I_CMD_PAN_, I_CMD_PFIN, I_CMD_PLOF, I_CMD_PTCH, I_CMD_RTRG, + I_CMD_STOP, I_CMD_TABL, I_CMD_TMPO, I_CMD_VOLM}; int CommandList::GetCount() { return sizeof(_all) / sizeof(FourCC); } diff --git a/sources/Application/Instruments/CommandList.h b/sources/Application/Instruments/CommandList.h index 8201a72a..cd83a2a5 100644 --- a/sources/Application/Instruments/CommandList.h +++ b/sources/Application/Instruments/CommandList.h @@ -14,6 +14,7 @@ #define I_CMD_LEGA MAKE_FOURCC('L','E','G','A') #define I_CMD_RTRG MAKE_FOURCC('R','T','R','G') #define I_CMD_TMPO MAKE_FOURCC('T','M','P','O') +#define I_CMD_MCHD MAKE_FOURCC('M', 'C', 'H', 'D') #define I_CMD_MDCC MAKE_FOURCC('M','D','C','C') #define I_CMD_MDPG MAKE_FOURCC('M','D','P','G') #define I_CMD_MVEL MAKE_FOURCC('M','V','E','L') diff --git a/sources/Application/Instruments/I_Instrument.h b/sources/Application/Instruments/I_Instrument.h index 4a3365d4..4b1089f0 100644 --- a/sources/Application/Instruments/I_Instrument.h +++ b/sources/Application/Instruments/I_Instrument.h @@ -23,8 +23,10 @@ class I_Instrument:public VariableContainer, public Observable { virtual bool Init()=0 ; - // Start & stop the instument - virtual bool Start(int channel,unsigned char note,bool retrigger=true)=0 ; + // Start & stop the instument + // flags & 1 indicates retriggers (default) + // flags & 2 indicates muting (i.e. no trigger) + virtual bool Start(int channel,unsigned char note,int flags=1)=0 ; virtual void Stop(int channel)=0 ; // Engine playback start callback @@ -33,8 +35,10 @@ class I_Instrument:public VariableContainer, public Observable { // size refers to the number of samples // should always fill interleaved stereo / 16bit - - virtual bool Render(int channel,fixed *buffer,int size,bool updateTick)=0 ; + + // flags & 1 indicates 'updateTick'. + // flags & 2 indicated muting (i.e. stop notes) + virtual bool Render(int channel,fixed *buffer,int size,int flags)=0 ; virtual bool IsInitialized()=0 ; diff --git a/sources/Application/Instruments/MidiInstrument.cpp b/sources/Application/Instruments/MidiInstrument.cpp index dfdc2372..9dc9fcc7 100644 --- a/sources/Application/Instruments/MidiInstrument.cpp +++ b/sources/Application/Instruments/MidiInstrument.cpp @@ -14,8 +14,11 @@ MidiInstrument::MidiInstrument() { svc_=MidiService::GetInstance() ; }; - Variable *v=new Variable("channel",MIP_CHANNEL,0) ; - Insert(v) ; + for (int i = 0; i < SONG_CHANNEL_COUNT; i++) + lastNote_[i] = new T_SimpleList(true); + + Variable *v = new Variable("channel", MIP_CHANNEL, 0); + Insert(v) ; v=new Variable("note length",MIP_NOTELENGTH,0) ; Insert(v) ; v=new Variable("volume",MIP_VOLUME,255) ; @@ -39,51 +42,64 @@ void MidiInstrument::OnStart() { tableState_.Reset() ; } ; -bool MidiInstrument::Start(int c,unsigned char note,bool retrigger) { +bool MidiInstrument::Start(int c, unsigned char note, int flags) { + // Take note of requested note regardless of whethere it is sounded. + rootNote_[c] = note; + + bool muted = flags & 2; + + if (muted) { + muted_[c] = true; + return true; + } - first_[c]=true ; - lastNote_[c]=note ; + // Not muted, thus the note should be queued. + unsigned char *last_note = new unsigned char; + *last_note = note; + + lastNote_[c]->Insert(last_note); - Variable *v=FindVariable(MIP_CHANNEL) ; - int channel=v->GetInt() ; + first_[c] = true; + muted_[c] = false; + + Variable *v = FindVariable(MIP_CHANNEL); + int channel=v->GetInt() ; - v=FindVariable(MIP_NOTELENGTH) ; - remainingTicks_=v->GetInt() ; + v = FindVariable(MIP_NOTELENGTH); + remainingTicks_=v->GetInt() ; if (remainingTicks_==0) { remainingTicks_=-1 ; } - MidiMessage msg ; + // send initial volume for this midi channel - // send initial volume for this midi channel + v = FindVariable(MIP_VOLUME); + unsigned char volume = floor(static_cast(v->GetInt() + 0.99) / 2); + SetVolume(channel, volume); - v=FindVariable(MIP_VOLUME) ; - msg.status_=MIDI_CC+channel ; - msg.data1_=7 ; - msg.data2_ = floor(static_cast(v->GetInt()+0.99)/2) ; - svc_->QueueMessage(msg) ; - - - // store initial velocity - velocity_ = msg.data2_; + // store initial velocity + velocity_ = volume; playing_=true ; retrig_=false ; - return true ; -} ; + return true; +}; void MidiInstrument::Stop(int c) { + if (muted_[c]) + return; - Variable *v=FindVariable(MIP_CHANNEL) ; - int channel=v->GetInt() ; + Variable *v = FindVariable(MIP_CHANNEL); + int channel = v->GetInt(); - MidiMessage msg; - msg.status_=MIDI_NOTE_OFF+channel ; - msg.data1_=lastNote_[c] ; - msg.data2_=0x00 ; - svc_->QueueMessage(msg) ; - playing_=false ; + IteratorPtr it(lastNote_[c]->GetIterator()); + for (it->Begin(); !it->IsDone(); it->Next()) { + unsigned char note = it->CurrentItem(); + QueueNote(false, channel, note, 0); + } + lastNote_[c]->Empty(); + playing_ = false; } ; void MidiInstrument::SetChannel(int channel) { @@ -91,53 +107,62 @@ void MidiInstrument::SetChannel(int channel) { v->SetInt(channel) ; } ; -bool MidiInstrument::Render(int channel,fixed *buffer,int size,bool updateTick) { +bool MidiInstrument::Render(int channel, fixed *buffer, int size, int flags) { + bool mute = flags & 2; - // We do it here so we have the opportunity to send some command before + if (mute && !muted_[channel]) { + Stop(channel); + muted_[channel]=true; + return false; + } else if (!mute && muted_[channel]) + muted_[channel] = false; - Variable *v=FindVariable(MIP_CHANNEL) ; - int mchannel=v->GetInt() ; - if (first_[channel]) { - - // send note - - MidiMessage msg ; - - msg.status_=MIDI_NOTE_ON+mchannel ; - msg.data1_=lastNote_[channel] ; - msg.data2_ = velocity_; - svc_->QueueMessage(msg) ; - - first_[channel]=false ; - } - if (remainingTicks_>0) { - remainingTicks_-- ; - if (remainingTicks_==0) { - if (!retrig_) { - Stop(channel) ; - } else { - MidiMessage msg ; - remainingTicks_=retrigLoop_ ; - msg.status_=MIDI_NOTE_OFF+mchannel ; - msg.data1_=lastNote_[channel] ; - msg.data2_=0x00 ; - svc_->QueueMessage(msg) ; - msg.status_=MIDI_NOTE_ON+mchannel ; - msg.data1_=lastNote_[channel] ; - msg.data2_=0x7F ; - svc_->QueueMessage(msg) ; - } ; - } ; + // We do it here so we have the opportunity to send some command before + + Variable *v = FindVariable(MIP_CHANNEL); + int mchannel=v->GetInt() ; + + if (first_[channel]) { + + // send note(s) + IteratorPtr it(lastNote_[channel]->GetIterator()); + for (it->Begin(); !it->IsDone(); it->Next()) { + unsigned char note = it->CurrentItem(); + QueueNote(true, mchannel, note, velocity_); + } + + first_[channel] = false; + } + + if (remainingTicks_>0) { + remainingTicks_--; + if (remainingTicks_ == 0) { + if (!retrig_) { + Stop(channel); + } else { + remainingTicks_ = retrigLoop_; + IteratorPtr it( + lastNote_[channel]->GetIterator()); + for (it->Begin(); !it->IsDone(); it->Next()) { + unsigned char note = it->CurrentItem(); + QueueNote(false, mchannel, note, 0); + QueueNote(true, mchannel, note, velocity_); + } + }; + }; } ; - return false ; + return false; }; bool MidiInstrument::IsInitialized() { return true ; // Always initialised } ; -void MidiInstrument::ProcessCommand(int channel,FourCC cc,ushort value) { - +void MidiInstrument::ProcessCommand(int channel, FourCC cc, ushort value) { + // Do not process commands if muted. + if (muted_[channel]) + return; + Variable *v=FindVariable(MIP_CHANNEL) ; int mchannel=v->GetInt() ; @@ -161,39 +186,49 @@ void MidiInstrument::ProcessCommand(int channel,FourCC cc,ushort value) { case I_CMD_VOLM: { - MidiMessage msg ; - msg.status_=MIDI_CC+mchannel ; - msg.data1_= 7; - msg.data2_ = floor(static_cast(value / 2)); - svc_->QueueMessage(msg) ; - } ; - break ; - - case I_CMD_MDCC: - { - MidiMessage msg ; - msg.status_=MIDI_CC+mchannel ; - msg.data1_=(value&0x7F00)>>8 ; - msg.data2_=(value&0x7F) ; - svc_->QueueMessage(msg) ; - }; - break ; - - case I_CMD_MDPG: - { - MidiMessage msg ; - msg.status_=MIDI_PRG+mchannel ; - msg.data1_=(value&0x7F) ; - msg.data2_=MidiMessage::UNUSED_BYTE ; - svc_->QueueMessage(msg) ; - }; - break ; - } -} ; + unsigned char volume = floor(static_cast(value / 2)); + SetVolume(mchannel, volume); + }; break; + + case I_CMD_MCHD: { + if (muted_[channel]) + break; + + int notes[] = {value & 0xFF, value >> 8}; + for (unsigned int i = 0; i < 2; i++) { + unsigned char *chord_tone = new unsigned char; + *chord_tone = (rootNote_[channel] + notes[i]) % 128; + + // Make sure note hasn't already been triggered. + bool tone_sounded = *chord_tone == rootNote_[channel]; + IteratorPtr it( + lastNote_[channel]->GetIterator()); + for (it->Begin(); !it->IsDone(); it->Next()) + tone_sounded |= *chord_tone == it->CurrentItem(); + + if (!tone_sounded) { + QueueNote(true, mchannel, *chord_tone, velocity_); + lastNote_[channel]->Insert(chord_tone); + } + } + } break; + + case I_CMD_MDCC: { + unsigned char id = (value & 0x7F00) >> 8; + value &= 0x7F; + SetCC(mchannel, id, value); + }; break; + + case I_CMD_MDPG: { + unsigned char id = value & 0x7F; + SetPRG(mchannel, id); + }; break; + } +}; const char *MidiInstrument::GetName() { - Variable *v=FindVariable(MIP_CHANNEL) ; - sprintf(name_,"MIDI CH %2.2d",v->GetInt()+1) ; + Variable *v = FindVariable(MIP_CHANNEL); + sprintf(name_, "MIDI CH %2.2d", v->GetInt() + 1); return name_ ; } @@ -216,3 +251,35 @@ void MidiInstrument::SetTableState(TableSaveState &state) { memcpy(tableState_.hopCount_,state.hopCount_,sizeof(uchar)*TABLE_STEPS*3) ; memcpy(tableState_.position_,state.position_,sizeof(int)*3) ; } ; + +void MidiInstrument::QueueNote(bool note_on, int channel, unsigned char note, unsigned char velocity) +{ + MidiMessage msg; + msg.status_ = channel + (note_on ? MIDI_NOTE_ON : MIDI_NOTE_OFF); + msg.data1_ = note; + msg.data2_ = note_on * velocity; + + svc_->QueueMessage(msg); +} + +void MidiInstrument::SetVolume(int channel, unsigned char volume) { + SetCC(channel, 7, volume); +} + +void MidiInstrument::SetCC(int channel, unsigned char id, unsigned char value) { + MidiMessage msg; + + msg.status_=MIDI_CC+channel ; + msg.data1_=id ; + msg.data2_ = value ; + svc_->QueueMessage(msg) ; +} + +void MidiInstrument::SetPRG(int channel, unsigned char id) { + MidiMessage msg; + + msg.status_=MIDI_PRG+channel ; + msg.data1_=id ; + msg.data2_ = MidiMessage::UNUSED_BYTE ; + svc_->QueueMessage(msg) ; +} diff --git a/sources/Application/Instruments/MidiInstrument.h b/sources/Application/Instruments/MidiInstrument.h index 4490d621..0ca36df7 100644 --- a/sources/Application/Instruments/MidiInstrument.h +++ b/sources/Application/Instruments/MidiInstrument.h @@ -26,13 +26,13 @@ class MidiInstrument:public I_Instrument { virtual bool Init() ; // Start & stop the instument - virtual bool Start(int channel,unsigned char note,bool retrigger=true) ; + virtual bool Start(int channel, unsigned char note, int flags = 1); virtual void Stop(int channel) ; // size refers to the number of samples // should always fill interleaved stereo / 16bit - virtual bool Render(int channel,fixed *buffer,int size,bool updateTick) ; - virtual void ProcessCommand(int channel,FourCC cc,ushort value) ; + virtual bool Render(int channel, fixed *buffer, int size, int flags); + virtual void ProcessCommand(int channel,FourCC cc,ushort value) ; virtual bool IsInitialized() ; @@ -48,25 +48,35 @@ class MidiInstrument:public I_Instrument { virtual int GetTable() ; virtual bool GetTableAutomation(); - virtual void GetTableState(TableSaveState &state) ; - virtual void SetTableState(TableSaveState &state) ; - - // external parameter list - - void SetChannel(int i); - - private: - char name_[20] ; // Instrument name - int lastNote_[SONG_CHANNEL_COUNT] ; - int remainingTicks_ ; - bool playing_ ; - bool retrig_ ; - int retrigLoop_ ; - char velocity_; - TableSaveState tableState_ ; - bool first_[SONG_CHANNEL_COUNT] ; - - static MidiService* svc_ ; + virtual void GetTableState(TableSaveState &state); + virtual void SetTableState(TableSaveState &state); + virtual void QueueNote(bool note_on, int channel, unsigned char note, + unsigned char velocity); + virtual void SetVolume(int channel, unsigned char volume); + virtual void SetCC(int channel, unsigned char id, unsigned char value); + virtual void SetPRG(int channel, unsigned char id); + + // external parameter list + + void SetChannel(int i); + + private: + char name_[20]; // Instrument name + T_SimpleList + *lastNote_[SONG_CHANNEL_COUNT]; // List of played note(s). + int rootNote_[SONG_CHANNEL_COUNT]; + // Keep track of last requested note even if not played. This way, + // 'root notes' of chords are stored even when the track is muted. + int remainingTicks_; + bool playing_; + bool retrig_; + int retrigLoop_; + char velocity_; + TableSaveState tableState_; + bool first_[SONG_CHANNEL_COUNT]; + bool muted_[SONG_CHANNEL_COUNT]; + + static MidiService *svc_; } ; #endif diff --git a/sources/Application/Instruments/SampleInstrument.cpp b/sources/Application/Instruments/SampleInstrument.cpp index 33aca908..2fbdfd40 100644 --- a/sources/Application/Instruments/SampleInstrument.cpp +++ b/sources/Application/Instruments/SampleInstrument.cpp @@ -166,9 +166,10 @@ void SampleInstrument::OnStart() { tableState_.Reset() ; } ; -bool SampleInstrument::Start(int channel,unsigned char midinote,bool cleanstart) -{ - // Look if we're dirty & need to update this instrument's data +bool SampleInstrument::Start(int channel, unsigned char midinote, int flags) { + bool cleanstart = flags & 1; + + // Look if we're dirty & need to update this instrument's data if (dirty_) { @@ -273,6 +274,7 @@ bool SampleInstrument::Start(int channel,unsigned char midinote,bool cleanstart) }; rp->baseSpeed_ = fl2fp((freq * length) / driverRate); rp->rendFirst_ = rp->rendLoopStart_; + if (cleanstart) { rp->position_ = float(rp->rendFirst_); } @@ -452,46 +454,48 @@ void SampleInstrument::updateFeedback(renderParams *rp) { // Size in samples -bool SampleInstrument::Render(int channel,fixed *buffer,int size,bool updateTick) { +bool SampleInstrument::Render(int channel, fixed *buffer, int size, int flags) { - bool somethingToMix=false ; + bool somethingToMix = false; + bool updateTick = flags & 1; - // Get Current render parameters - - renderParams *rp=renderParams_+channel ; - lastMidiNote_[channel]=rp->midiNote_ ; - bool *rpFinished=&(rp->finished_) ; + // Get Current render parameters - if (source_) { + renderParams *rp = renderParams_ + channel; + lastMidiNote_[channel] = rp->midiNote_; + bool *rpFinished = &(rp->finished_); - if (*rpFinished) return false ; - - // clear the fixed point buffer + if (source_) { - SYS_MEMSET(buffer,0,size*2*sizeof(fixed)) ; + if (*rpFinished) + return false; + // clear the fixed point buffer - bool hasUpdaters=!(rp->activeUpdaters_.empty()) ; + SYS_MEMSET(buffer, 0, size * 2 * sizeof(fixed)); - int filterMix=filterMix_->GetInt() ; - FilterMode filterMode=(FilterMode)filterMode_->GetInt() ; - bool filterBoost=(filterMode==FM_SCREAM) ; - bool bassyFilter=(filterMode==FM_BASSY) ; + bool hasUpdaters = !(rp->activeUpdaters_.empty()); - // Be sure filters are properly initialized + int filterMix = filterMix_->GetInt(); + FilterMode filterMode = (FilterMode)filterMode_->GetInt(); + bool filterBoost = (filterMode == FM_SCREAM); + bool bassyFilter = (filterMode == FM_BASSY); - set_filter(channel,FLT_LOWPASS,rp->cutoff_,rp->reso_,filterMix,bassyFilter); + // Be sure filters are properly initialized - filter_t* flt =get_filter(channel) ; - bool filtering=(rp->cutoff_reso_>i2fp(0)) ; + set_filter(channel, FLT_LOWPASS, rp->cutoff_, rp->reso_, filterMix, + bassyFilter); - // Process tick-level updates - - if (updateTick) { + filter_t *flt = get_filter(channel); + bool filtering = (rp->cutoff_ < i2fp(1)) || (rp->reso_ > i2fp(0)); - if (hasUpdaters) { + // Process tick-level updates - doTickUpdate(channel) ; + if (updateTick) { + + if (hasUpdaters) { + + doTickUpdate(channel); struct RUParams rup ; rup.cutOffset_=rup.resOffset_=rup.volumeOffset_=rup.panOffset_=0 ; @@ -507,36 +511,35 @@ bool SampleInstrument::Render(int channel,fixed *buffer,int size,bool updateTick rp->volume_=rp->baseVolume_+rup.volumeOffset_ ; rp->speed_=fp_mul(rp->baseSpeed_,rup.speedOffset_) ; rp->pan_=rp->basePan_+rup.panOffset_ ; - } - - // Process retrig - - if (rp->retrig_) { - if (rp->retrigCount_==0) { - int ticks=rp->retrigOffset_-rp->retrigLoop_ ; - long offset=long(ticks*SyncMaster::GetInstance()->GetTickSampleCount()) ; - rp->position_+=offset*fp2fl(rp->speed_) ; - if (rp->position_<0) { - rp->position_=0 ; - } ; - rp->retrigCount_=rp->retrigLoop_ ; - } - rp->retrigCount_-- ; - } ; - + } - } - - // Get additional parameters from variables + // Process retrig + + if (rp->retrig_) { + if (rp->retrigCount_ == 0) { + int ticks = rp->retrigOffset_ - rp->retrigLoop_; + long offset = + long(ticks * + SyncMaster::GetInstance()->GetTickSampleCount()); + rp->position_ += offset * fp2fl(rp->speed_); + if (rp->position_ < 0) { + rp->position_ = 0; + }; + rp->retrigCount_ = rp->retrigLoop_; + } + rp->retrigCount_-- ; + } ; + } + // Get additional parameters from variables - // Crush + // Crush - int shift=16-rp->crush_; - fixed mask=0xFFFFFFFF ; - if (shift !=0) { - mask<<=FIXED_SHIFT+shift ; - } + int shift = 16 - rp->crush_; + fixed mask = 0xFFFFFFFF; + if (shift != 0) { + mask <<= FIXED_SHIFT + shift; + } // Crush vol @@ -988,9 +991,8 @@ bool SampleInstrument::Render(int channel,fixed *buffer,int size,bool updateTick somethingToMix=true ; } - return somethingToMix ; -} ; - + return somethingToMix; +}; void SampleInstrument::AssignSample(int i) { diff --git a/sources/Application/Instruments/SampleInstrument.h b/sources/Application/Instruments/SampleInstrument.h index eadefd43..f481327e 100644 --- a/sources/Application/Instruments/SampleInstrument.h +++ b/sources/Application/Instruments/SampleInstrument.h @@ -59,9 +59,9 @@ class SampleInstrument: public I_Instrument,I_Observer { virtual ~SampleInstrument() ; // I_Instrument implementation virtual bool Init() ; - virtual bool Start(int channel,unsigned char note,bool trigger=true) ; + virtual bool Start(int channel, unsigned char note, int flags = 1); virtual void Stop(int channel) ; - virtual bool Render(int channel,fixed *buffer,int size,bool updateTick) ; + virtual bool Render(int channel, fixed *buffer, int size, int flags); virtual bool IsInitialized() ; virtual bool IsEmpty() ; diff --git a/sources/Application/Model/Project.h b/sources/Application/Model/Project.h index 7f195cdd..38c43493 100644 --- a/sources/Application/Model/Project.h +++ b/sources/Application/Model/Project.h @@ -21,7 +21,7 @@ #define PROJECT_NUMBER "1" #define PROJECT_RELEASE "6" -#define BUILD_COUNT "0-bacon19" +#define BUILD_COUNT "0-bacon20" #define MAX_TAP 3 diff --git a/sources/Application/Player/PlayerChannel.cpp b/sources/Application/Player/PlayerChannel.cpp index 7efb660e..c8fca827 100644 --- a/sources/Application/Player/PlayerChannel.cpp +++ b/sources/Application/Player/PlayerChannel.cpp @@ -29,7 +29,9 @@ void PlayerChannel::StartInstrument(I_Instrument *instr,unsigned char note,bool if (instr_) { StopInstrument() ; } - if (instr->Start(index_,note,trigger)) { // note could be refused coz it's out of the keymap + /* The note will not trigger if it is out the keymap or, in the case of a + MIDI instrument, if the channel is muted. */ + if (instr->Start(index_,note, trigger | (muted_ << 1))) { instr_=instr ; } else { instr_=0 ; @@ -46,7 +48,8 @@ void PlayerChannel::StopInstrument() { bool PlayerChannel::Render(fixed *buffer,int samplecount) { if (instr_) { bool tableSlice=SyncMaster::GetInstance()->TableSlice() ; - bool status=instr_->Render(index_,buffer,samplecount,tableSlice) ; + bool status = instr_->Render(index_, buffer, samplecount, + tableSlice | (muted_ << 1)); if (status && !muted_) { // Apply HPF if enabled if (hpfMode_ != 0) { diff --git a/sources/Application/Utils/HelpLegend.h b/sources/Application/Utils/HelpLegend.h index 6551f692..7c832ba1 100644 --- a/sources/Application/Utils/HelpLegend.h +++ b/sources/Application/Utils/HelpLegend.h @@ -51,6 +51,11 @@ static inline std::string* getHelpLegend(FourCC command) { result[1].assign("sets the tempo to hex"); result[2].assign("value bb"); break; + case I_CMD_MCHD: + result[0].assign("MiDiCHorD:aabb"); + result[1].assign("send notes aa and bb"); + result[2].assign("semitones higher"); + break; case I_CMD_MDCC: result[0].assign("MiDiCC:aabb"); result[1].assign("CC message aa"); diff --git a/sources/Foundation/T_SimpleList.cpp b/sources/Foundation/T_SimpleList.cpp index ea29ac0d..ad360350 100644 --- a/sources/Foundation/T_SimpleList.cpp +++ b/sources/Foundation/T_SimpleList.cpp @@ -67,7 +67,7 @@ I_Iterator *T_SimpleList::GetIterator() { template I_Iterator *T_SimpleList::GetIterator(bool reverse) { - return new T_SimpleListIterator(*this,reverse) ; + return new T_SimpleListIterator(*this, reverse); } // Empties the list's content