From 9a9a867e7d3997b64332f3e75adbfd985dd187c1 Mon Sep 17 00:00:00 2001 From: "Raine M. Ekman" Date: Wed, 22 Jan 2014 20:57:02 +0200 Subject: [PATCH] Added pitch bend --- plugins/opl2/opl2instrument.cpp | 40 ++++++++++++++++++++++----------- plugins/opl2/opl2instrument.h | 6 ++++- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/plugins/opl2/opl2instrument.cpp b/plugins/opl2/opl2instrument.cpp index 323945738..dd8fda55a 100644 --- a/plugins/opl2/opl2instrument.cpp +++ b/plugins/opl2/opl2instrument.cpp @@ -23,9 +23,8 @@ */ // TODO: -// - Pitch bend // - Velocity (and aftertouch) sensitivity -// - in FM mode: OP2 level, add mode: OP1 and OP2 levels +// * in FM mode: OP2 level, add mode: OP1 and OP2 levels // - .sbi (or similar) file loading into models // - RT safety = get rid of mutex = make emulator code thread-safe @@ -163,12 +162,14 @@ opl2instrument::opl2instrument( InstrumentTrack * _instrument_track ) : frameCount = engine::mixer()->framesPerPeriod(); renderbuffer = new short[frameCount]; - // Some kind of sane default + // Some kind of sane defaults + pitchbend = 0; tuneEqual(69, 440); for(int i=1; i<9; ++i) { voiceNote[i] = OPL2_VOICE_FREE; } + connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( reloadEmulator() ) ); // Connect knobs @@ -239,18 +240,12 @@ bool opl2instrument::handleMidiEvent( const midiEvent & _me, const midiTime & _time ) { emulatorMutex.lock(); - // Real dummy version... Should at least add: - // - smarter voice allocation: - // - reuse same note, now we have round robin-ish - // - what to do when voices run out and so on... - // - mono mode - // - int key, vel; + int key, vel, tmp_pb; static int lastvoice=0; switch(_me.m_type) { case MidiNoteOn: if( !isMuted() ) { - // to get us in line with MIDI + // to get us in line with MIDI(?) key = _me.key() +12; vel = _me.velocity(); for(int i=lastvoice+1; i!=lastvoice; ++i,i%=9) { @@ -258,6 +253,7 @@ bool opl2instrument::handleMidiEvent( const midiEvent & _me, theEmulator->write(0xA0+i, fnums[key] & 0xff); theEmulator->write(0xB0+i, 32 + ((fnums[key] & 0x1f00) >> 8) ); voiceNote[i] = key; + velocities[key] = vel; lastvoice=i; break; } @@ -273,13 +269,30 @@ bool opl2instrument::handleMidiEvent( const midiEvent & _me, voiceNote[i] = OPL2_VOICE_FREE; } } + velocities[key] = 0; break; case MidiKeyPressure: key = _me.key() +12; vel = _me.velocity(); + if( velocities[key] != 0) { + velocities[key] = vel; + } break; case MidiPitchBend: - printf("TODO: Pitch bend\n"); + // Update fnumber table + tmp_pb = (2*BEND_CENTS)*((float)_me.m_data.m_param[0]/16383)-BEND_CENTS; + if( tmp_pb != pitchbend ) { + pitchbend = tmp_pb; + tuneEqual(69, 440.0); + } + // Update pitch of sounding notes + for( int i=0; i<9; ++i ) { + if( voiceNote[i] != OPL2_VOICE_FREE ) { + theEmulator->write(0xA0+i, fnums[voiceNote[i] ] & 0xff); + theEmulator->write(0xB0+i, 32 + ((fnums[voiceNote[i]] & 0x1f00) >> 8) ); + } + } + // printf("Pitch bend: %d\n", pitchbend); break; default: printf("Midi event type %d\n",_me.m_type); @@ -411,8 +424,9 @@ void opl2instrument::loadPatch(unsigned char inst[14]) { } void opl2instrument::tuneEqual(int center, float Hz) { + float tmp; for(int n=0; n<128; ++n) { - float tmp = Hz*pow(2, (n-center)/12.0); + tmp = Hz*pow( 2, ( n - center ) / 12.0 + pitchbend / 1200.0 ); fnums[n] = Hz2fnum( tmp ); } } diff --git a/plugins/opl2/opl2instrument.h b/plugins/opl2/opl2instrument.h index a02088167..7c81ba192 100644 --- a/plugins/opl2/opl2instrument.h +++ b/plugins/opl2/opl2instrument.h @@ -109,9 +109,13 @@ private: fpp_t frameCount; short *renderbuffer; int voiceNote[9]; - int heldNotes[128]; + // 0 - no note, >0 - note on velocity + int velocities[128]; // These include both octave and Fnumber int fnums[128]; + // in cents, range defaults to +/-100 cents (should this be changeable?) + int pitchbend; + #define BEND_CENTS 100 int Hz2fnum(float Hz); static QMutex emulatorMutex;