2
0
Fork 0

Add some quick and dirty MIDI pitch wheel control.

This commit is contained in:
bruce 2013-12-23 15:51:29 +08:00
parent de9f8732a7
commit 1ce43da7ac
4 changed files with 32 additions and 5 deletions

View file

@ -120,6 +120,7 @@ JuceOplvstiAudioProcessor::JuceOplvstiAudioProcessor()
for (int i = 0; i < Hiopl::CHANNELS+1; i++) { for (int i = 0; i < Hiopl::CHANNELS+1; i++) {
active_notes[i] = NO_NOTE; active_notes[i] = NO_NOTE;
} }
currentScaledBend = 1.0f;
} }
void JuceOplvstiAudioProcessor::initPrograms() void JuceOplvstiAudioProcessor::initPrograms()
@ -366,6 +367,17 @@ void JuceOplvstiAudioProcessor::initPrograms()
} }
void JuceOplvstiAudioProcessor::applyPitchBend()
{ // apply the currently configured pitch bend to all active notes.
for (int i = 1; i <= Hiopl::CHANNELS; i++) {
if (NO_NOTE != active_notes[i]) {
float f = (float)MidiMessage::getMidiNoteInHertz(active_notes[i]);
f *= currentScaledBend;
Opl->SetFrequency(i, f);
}
}
}
JuceOplvstiAudioProcessor::~JuceOplvstiAudioProcessor() JuceOplvstiAudioProcessor::~JuceOplvstiAudioProcessor()
{ {
} }
@ -658,6 +670,7 @@ void JuceOplvstiAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuf
} }
Opl->KeyOn(ch, noteHz); Opl->KeyOn(ch, noteHz);
active_notes[ch] = n; active_notes[ch] = n;
applyPitchBend();
} }
else if (midi_message.isNoteOff()) { else if (midi_message.isNoteOff()) {
int n = midi_message.getNoteNumber(); int n = midi_message.getNoteNumber();
@ -668,6 +681,12 @@ void JuceOplvstiAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuf
Opl->KeyOff(ch); Opl->KeyOff(ch);
active_notes[ch] = NO_NOTE; active_notes[ch] = NO_NOTE;
} }
else if (midi_message.isPitchWheel()) {
int bend = midi_message.getPitchWheelValue() - 0x2000; // range -8192 to 8191
// 1.05946309436 == (2^(1/1200))^100 == 1 semitone == 100 cents
currentScaledBend = 1.0f + bend * .05775f / 8192;
applyPitchBend();
}
} }
Opl->Generate(buffer.getNumSamples(), buffer.getSampleData(0)); Opl->Generate(buffer.getNumSamples(), buffer.getSampleData(0));
} }

View file

@ -24,6 +24,7 @@ public:
//============================================================================== //==============================================================================
JuceOplvstiAudioProcessor(); JuceOplvstiAudioProcessor();
void initPrograms(); void initPrograms();
void applyPitchBend();
~JuceOplvstiAudioProcessor(); ~JuceOplvstiAudioProcessor();
//============================================================================== //==============================================================================
@ -88,6 +89,7 @@ private:
bool velocity; bool velocity;
static const int NO_NOTE=-1; static const int NO_NOTE=-1;
int active_notes[Hiopl::CHANNELS+1]; // keyed by channel int active_notes[Hiopl::CHANNELS+1]; // keyed by channel
float currentScaledBend;
//============================================================================== //==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceOplvstiAudioProcessor) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceOplvstiAudioProcessor)

View file

@ -160,11 +160,7 @@ void Hiopl::SetModulatorFeedback(int ch, int level) {
} }
void Hiopl::KeyOn(int ch, float frqHz) { void Hiopl::KeyOn(int ch, float frqHz) {
unsigned int fnum, block; Hiopl::SetFrequency(ch, frqHz, true);
int offset = this->_GetOffset(ch);
_milliHertzToFnum((unsigned int)(frqHz * 1000.0), &fnum, &block);
_WriteReg(0xa0+offset, fnum % 0x100);
_WriteReg(0xb0+offset, 0x20|((block&0x7)<<2)|(0x3&(fnum/0x100)));
} }
void Hiopl::KeyOff(int ch) { void Hiopl::KeyOff(int ch) {
@ -172,6 +168,15 @@ void Hiopl::KeyOff(int ch) {
_ClearRegBits(0xb0+offset, 0x20); _ClearRegBits(0xb0+offset, 0x20);
} }
void Hiopl::SetFrequency(int ch, float frqHz, bool keyOn) {
unsigned int fnum, block;
int offset = this->_GetOffset(ch);
_milliHertzToFnum((unsigned int)(frqHz * 1000.0), &fnum, &block);
_WriteReg(0xa0+offset, fnum % 0x100);
uint8 trig = (regCache[0xb0+offset] & 0x20) | (keyOn ? 0x20 : 0x00);
_WriteReg(0xb0+offset, trig|((block&0x7)<<2)|(0x3&(fnum/0x100)));
}
// from libgamemusic, opl-util.cpp // from libgamemusic, opl-util.cpp
void Hiopl::_milliHertzToFnum(unsigned int milliHertz, void Hiopl::_milliHertzToFnum(unsigned int milliHertz,
unsigned int *fnum, unsigned int *block, unsigned int conversionFactor) unsigned int *fnum, unsigned int *block, unsigned int conversionFactor)

View file

@ -46,6 +46,7 @@ class Hiopl {
void SetModulatorFeedback(int ch, int level); void SetModulatorFeedback(int ch, int level);
void KeyOn(int ch, float frqHz); void KeyOn(int ch, float frqHz);
void KeyOff(int ch); void KeyOff(int ch);
void SetFrequency(int ch, float frqHz, bool keyOn=false);
void _WriteReg(Bit32u reg, Bit8u value, Bit8u mask=0x0); void _WriteReg(Bit32u reg, Bit8u value, Bit8u mask=0x0);
void _ClearRegBits(Bit32u reg, Bit8u mask); void _ClearRegBits(Bit32u reg, Bit8u mask);
~Hiopl(); ~Hiopl();