zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit f3946b60102baf97e8684d6f9f95e0ecad5f8fc8
parent 96e803c9a6230ae3d00925821b0eda296a2d396b
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Thu, 31 May 2012 23:31:44 -0400

Adds aftertouch support

Integrates MIDI aftertouch support for normal, legato, and mono notes.

- Patch by Olaf Schulz

Diffstat:
MAUTHORS.txt | 1+
Msrc/Misc/Master.cpp | 16++++++++++++++++
Msrc/Misc/Master.h | 1+
Msrc/Misc/Part.cpp | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Misc/Part.h | 3+++
Msrc/Nio/AlsaEngine.cpp | 8++++++++
Msrc/Nio/InMgr.cpp | 3+++
Msrc/Nio/InMgr.h | 4+++-
Msrc/Nio/JackEngine.cpp | 7+++++++
Msrc/Nio/MidiIn.cpp | 7+++++++
Msrc/Synth/SynthNote.cpp | 7+++++++
Msrc/Synth/SynthNote.h | 10++++++++++
12 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/AUTHORS.txt b/AUTHORS.txt @@ -21,5 +21,6 @@ Contributors: Hans Petter Selasky (OSS Midi, FreeBSD support, Bank UI bug fix) Damien Goutte-Gattat (Bank select midi support) Lieven Moors (Spike/Circle waveform) + Olaf Schulz (MIDI Aftertouch support) Jonathan Liles (NSM support) diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -157,6 +157,22 @@ void Master::noteOff(char chan, char note) } /* + * Pressure Messages (velocity=0 for NoteOff) + */ +void Master::polyphonicAftertouch(char chan, char note, char velocity) +{ + if(velocity) { + for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) + if(chan == part[npart]->Prcvchn) + if(part[npart]->Penabled) + part[npart]->PolyphonicAftertouch(note, velocity, keyshift); + + } + else + this->noteOff(chan, note); +} + +/* * Controllers */ void Master::setController(char chan, int type, int par) diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -91,6 +91,7 @@ class Master //Midi IN void noteOn(char chan, char note, char velocity); void noteOff(char chan, char note); + void polyphonicAftertouch(char chan, char note, char velocity); void setController(char chan, int type, int par); void setProgram(char chan, unsigned int pgm); //void NRPN... diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -645,6 +645,58 @@ void Part::NoteOff(unsigned char note) //relase the key } } +void Part::PolyphonicAftertouch(unsigned char note, + unsigned char velocity, + int masterkeyshift) +{ + if(!Pnoteon || (note < Pminkey) || (note > Pmaxkey)) + return; + if(Pdrummode) + return; + + // MonoMem stuff: + if(!Ppolymode) // if Poly is off + + monomem[note].velocity = velocity; // Store this note's velocity. + + + for(int i = 0; i < POLIPHONY; ++i) + if((partnote[i].note == note) && (partnote[i].status == KEY_PLAYING)) { + /* update velocity */ + // compute the velocity offset + float vel = + VelF(velocity / 127.0f, Pvelsns) + (Pveloffs - 64.0f) / 64.0f; + vel = (vel < 0.0f) ? 0.0f : vel; + vel = (vel > 1.0f) ? 1.0f : vel; + + if(!Pkitmode) { // "normal mode" + if(kit[0].Padenabled) + partnote[i].kititem[0].adnote->setVelocity(vel); + if(kit[0].Psubenabled) + partnote[i].kititem[0].subnote->setVelocity(vel); + if(kit[0].Ppadenabled) + partnote[i].kititem[0].padnote->setVelocity(vel); + } + else // "kit mode" + for(int item = 0; item < NUM_KIT_ITEMS; ++item) { + if(kit[item].Pmuted) + continue; + if((note < kit[item].Pminkey) + || (note > kit[item].Pmaxkey)) + continue; + + int ci = partnote[i].itemsplaying; // ci=current item + if(kit[item].Padenabled) + partnote[i].kititem[item].adnote->setVelocity(vel); + if(kit[item].Psubenabled) + partnote[i].kititem[item].subnote->setVelocity(vel); + if(kit[item].Ppadenabled) + partnote[i].kititem[item].padnote->setVelocity(vel); + } + } + +} + /* * Controllers */ diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -56,6 +56,9 @@ class Part unsigned char velocity, int masterkeyshift); void NoteOff(unsigned char note); + void PolyphonicAftertouch(unsigned char note, + unsigned char velocity, + int masterkeyshift); void AllNotesOff(); //panic void SetController(unsigned int type, int par); void RelaseSustainedKeys(); //this is called when the sustain pedal is relased diff --git a/src/Nio/AlsaEngine.cpp b/src/Nio/AlsaEngine.cpp @@ -136,6 +136,14 @@ void *AlsaEngine::MidiThread(void) InMgr::getInstance().putEvent(ev); break; + case SND_SEQ_EVENT_KEYPRESS: + ev.type = M_PRESSURE; + ev.channel = event->data.note.channel; + ev.num = event->data.note.note; + ev.value = event->data.note.velocity; + InMgr::getInstance().putEvent(ev); + break; + case SND_SEQ_EVENT_PITCHBEND: ev.type = M_CONTROLLER; ev.channel = event->data.control.channel; diff --git a/src/Nio/InMgr.cpp b/src/Nio/InMgr.cpp @@ -86,6 +86,9 @@ void InMgr::flush() case M_PGMCHANGE: master.setProgram(ev.channel, ev.num); break; + case M_PRESSURE: + master.polyphonicAftertouch(ev.channel, ev.num, ev.value); + break; } } } diff --git a/src/Nio/InMgr.h b/src/Nio/InMgr.h @@ -8,8 +8,10 @@ enum midi_type { M_NOTE = 1, M_CONTROLLER = 2, - M_PGMCHANGE = 3 + M_PGMCHANGE = 3, + M_PRESSURE = 4 }; //type=1 for note, type=2 for controller, type=3 for program change +//type=4 for polyphonic aftertouch struct MidiEvent { MidiEvent(); diff --git a/src/Nio/JackEngine.cpp b/src/Nio/JackEngine.cpp @@ -368,6 +368,13 @@ void JackEngine::handleMidi(unsigned long frames) InMgr::getInstance().putEvent(ev); break; + case 0xA0: /* pressure, aftertouch */ + ev.type = M_PRESSURE; + ev.num = midi_data[1]; + ev.value = midi_data[2]; + InMgr::getInstance().putEvent(ev); + break; + case 0xB0: /* controller */ ev.type = M_CONTROLLER; ev.num = midi_data[1]; diff --git a/src/Nio/MidiIn.cpp b/src/Nio/MidiIn.cpp @@ -45,6 +45,13 @@ void MidiIn::midiProcess(unsigned char head, ev.value = value; InMgr::getInstance().putEvent(ev); break; + case 0xA0: /* pressure, aftertouch */ + ev.type = M_PRESSURE; + ev.channel = chan; + ev.num = num; + ev.value = value; + InMgr::getInstance().putEvent(ev); + break; case 0xb0: //Controller ev.type = M_CONTROLLER; ev.channel = chan; diff --git a/src/Synth/SynthNote.cpp b/src/Synth/SynthNote.cpp @@ -125,3 +125,10 @@ void SynthNote::Legato::apply(SynthNote &note, float *outl, float *outr) break; } } + +void SynthNote::setVelocity(float velocity_) { + legato.setSilent(true); //Let legato.update(...) returns 0. + legatonote(legato.getFreq(), velocity_, + legato.getPortamento(), legato.getMidinote(), true); + legato.setDecounter(0); //avoid chopping sound due fade-in +} diff --git a/src/Synth/SynthNote.h b/src/Synth/SynthNote.h @@ -45,6 +45,8 @@ class SynthNote virtual void legatonote(float freq, float velocity, int portamento_, int midinote_, bool externcall) = 0; + /* For polyphonic aftertouch needed */ + void setVelocity(float velocity_); protected: // Legato transitions class Legato @@ -70,6 +72,14 @@ class SynthNote float freq, vel; int portamento, midinote; } param; + + public: /* Some get routines for legatonote calls (aftertouch feature)*/ + float getFreq() {return param.freq; } + float getVelocity() {return param.vel; } + int getPortamento() {return param.portamento; } + int getMidinote() {return param.midinote; } + void setSilent(bool silent_) {silent = silent_; } + void setDecounter(int decounter_) {decounter = decounter_; } } legato; };