From c428892c569f25f61f38104787611cc37f00a234 Mon Sep 17 00:00:00 2001 From: bruce Date: Wed, 4 Sep 2013 23:36:55 +0800 Subject: [PATCH] Basic note on/off triggering from MIDI working. --- Source/PluginProcessor.cpp | 66 +++++++++++++++++++++----------------- Source/dbopl.cpp | 3 ++ Source/hiopl.cpp | 66 ++++++++++++++++++++++++++++++++++++-- Source/hiopl.h | 5 ++- Source/setup.h | 3 ++ 5 files changed, 111 insertions(+), 32 deletions(-) diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 141c098..62c7a12 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -11,6 +11,14 @@ #include "PluginProcessor.h" #include "PluginEditor.h" +enum +{ + // Parameters Tags + pOsc1Wave = 0, + pOsc2Wave, + + pNumParams +}; //============================================================================== JuceOplvstiAudioProcessor::JuceOplvstiAudioProcessor() @@ -30,7 +38,7 @@ const String JuceOplvstiAudioProcessor::getName() const int JuceOplvstiAudioProcessor::getNumParameters() { - return 0; + return pNumParams; } float JuceOplvstiAudioProcessor::getParameter (int index) @@ -40,10 +48,22 @@ float JuceOplvstiAudioProcessor::getParameter (int index) void JuceOplvstiAudioProcessor::setParameter (int index, float newValue) { + switch (index) { + case pOsc1Wave: + break; + case pOsc2Wave: + break; + } } const String JuceOplvstiAudioProcessor::getParameterName (int index) { + switch (index) { + case pOsc1Wave: + return "Carrier waveform"; + case pOsc2Wave: + return "Modulator waveform"; + } return String::empty; } @@ -126,36 +146,9 @@ void JuceOplvstiAudioProcessor::changeProgramName (int index, const String& newN //============================================================================== void JuceOplvstiAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) { - Opl->SetSampleRate(sampleRate); + Opl->SetSampleRate((int)sampleRate); // Use this method as the place to do any pre-playback // initialisation that you need.. - - Opl->_WriteReg(0x20,0x32); - Opl->_WriteReg(0x23,0x21); - Opl->_WriteReg(0x40,0x1a); - Opl->_WriteReg(0x43,0x09); - Opl->_WriteReg(0x60,0x84); - Opl->_WriteReg(0x63,0x84); - Opl->_WriteReg(0x80,0x29); - Opl->_WriteReg(0x83,0x44); - Opl->_WriteReg(0xe3,0x00); - Opl->_WriteReg(0xe0,0x02); - Opl->_WriteReg(0xc0,0x06); - Opl->_WriteReg(0xa0,0x8b); - Opl->_WriteReg(0xb0,0x26); - Opl->_WriteReg(0x21,0x32); - Opl->_WriteReg(0x24,0x21); - Opl->_WriteReg(0x41,0x1a); - Opl->_WriteReg(0x44,0x09); - Opl->_WriteReg(0x61,0x84); - Opl->_WriteReg(0x64,0x84); - Opl->_WriteReg(0x81,0x29); - Opl->_WriteReg(0x84,0x44); - Opl->_WriteReg(0xe4,0x00); - Opl->_WriteReg(0xe1,0x02); - Opl->_WriteReg(0xc1,0x06); - Opl->_WriteReg(0xa1,0x8b); - Opl->_WriteReg(0xb1,0x2a); } void JuceOplvstiAudioProcessor::releaseResources() @@ -167,6 +160,21 @@ void JuceOplvstiAudioProcessor::releaseResources() void JuceOplvstiAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) { buffer.clear(0, 0, buffer.getNumSamples()); + MidiBuffer::Iterator midi_buffer_iterator(midiMessages); + + MidiMessage midi_message(0); + int sample_number; + while (midi_buffer_iterator.getNextEvent(midi_message,sample_number)) { + if (midi_message.isNoteOn()) { + //note on at sample_number samples after + //the begining of the current buffer + float noteHz = MidiMessage::getMidiNoteInHertz(midi_message.getNoteNumber()); + Opl->KeyOn(0, noteHz); + } + else if (midi_message.isNoteOff()) { + Opl->KeyOff(0); + } + } Opl->Generate(buffer.getNumSamples(), buffer.getSampleData(0)); } diff --git a/Source/dbopl.cpp b/Source/dbopl.cpp index 36ecf96..1f30670 100644 --- a/Source/dbopl.cpp +++ b/Source/dbopl.cpp @@ -41,6 +41,9 @@ #include "dosbox.h" #include "dbopl.h" +#ifdef _MSC_VER +#pragma warning ( disable: 4244 4127 ) +#endif #ifndef PI #define PI 3.14159265358979323846 diff --git a/Source/hiopl.cpp b/Source/hiopl.cpp index d102ee2..f8bc30d 100644 --- a/Source/hiopl.cpp +++ b/Source/hiopl.cpp @@ -27,6 +27,17 @@ void Hiopl::Generate(int length, float* buffer) { void Hiopl::SetSampleRate(int hz) { adlib->Init(hz); + _WriteReg(0x20,0x32); // modulator multiplier 2 + _WriteReg(0x23,0x21); // carrier multiplier 1 + _WriteReg(0x40,0x1a); // modulator level + _WriteReg(0x43,0x09); // carrier level + _WriteReg(0x60,0x84); // AD + _WriteReg(0x63,0x84); // AD + _WriteReg(0x80,0x29); // SR + _WriteReg(0x83,0x44); // SR + _WriteReg(0xe3,0x00); // wave select + _WriteReg(0xe0,0x02); // wave select + _WriteReg(0xc0,0x06); // carrier self-feedback level } void Hiopl::_WriteReg(Bit32u reg, Bit8u value) { @@ -34,9 +45,13 @@ void Hiopl::_WriteReg(Bit32u reg, Bit8u value) { regCache[reg] = value; } +void Hiopl::_ClearRegBits(Bit32u reg, Bit8u mask) { + _WriteReg(reg, regCache[reg] & ~mask); +} + void Hiopl::SetWaveform(int ch, int osc, Waveform wave) { assert(_CheckParams(ch, osc)); - _WriteReg(0xe0+2*ch+osc, wave); + _WriteReg(0xe0+2*ch+osc, (Bit8u)wave); } Waveform Hiopl::GetWaveform(int ch, int osc) { @@ -44,8 +59,55 @@ Waveform Hiopl::GetWaveform(int ch, int osc) { return static_cast(regCache[0xe0+2*ch+osc]); } -void Hiopl::KeyOn(int ch, int frq) { +void Hiopl::KeyOn(int ch, float frqHz) { + unsigned int fnum, block; + _milliHertzToFnum((unsigned int)(frqHz * 1000.0), &fnum, &block); + _WriteReg(0xa0, fnum % 0x100); + _WriteReg(0xb0, 0x20|((block&0x7)<<2)|(0x3&(fnum/0x100))); + //_WriteReg(0xa0, 0x8b); + //_WriteReg(0xb0, 0x26); +} +void Hiopl::KeyOff(int ch) { + _ClearRegBits(0xb0, 0x20); +} + +// from libgamemusic, opl-util.cpp +void Hiopl::_milliHertzToFnum(unsigned int milliHertz, + unsigned int *fnum, unsigned int *block, unsigned int conversionFactor) +{ + // Special case to avoid divide by zero + if (milliHertz == 0) { + *block = 0; // actually any block will work + *fnum = 0; + return; + } + // Special case for frequencies too high to produce + if (milliHertz > 6208431) { + *block = 7; + *fnum = 1023; + return; + } + + // This is a bit more efficient and doesn't need log2() from math.h + if (milliHertz > 3104215) *block = 7; + else if (milliHertz > 1552107) *block = 6; + else if (milliHertz > 776053) *block = 5; + else if (milliHertz > 388026) *block = 4; + else if (milliHertz > 194013) *block = 3; + else if (milliHertz > 97006) *block = 2; + else if (milliHertz > 48503) *block = 1; + else *block = 0; + + // Slightly more efficient version + *fnum = ((unsigned long long)milliHertz << (20 - *block)) / (conversionFactor * 1000.0) + 0.5; + if ((*block == 7) && (*fnum > 1023)) { + // frequency out of range, clipping to maximum value. + *fnum = 1023; + } + assert(*block <= 7); + assert(*fnum < 1024); + return; } Hiopl::~Hiopl() { diff --git a/Source/hiopl.h b/Source/hiopl.h index a2f5b23..92e0f30 100644 --- a/Source/hiopl.h +++ b/Source/hiopl.h @@ -22,12 +22,15 @@ class Hiopl { void SetSampleRate(int hz); void SetWaveform(int ch, int osc, Waveform wave); Waveform GetWaveform(int ch, int osc); - void Hiopl::KeyOn(int ch, int frq); + void KeyOn(int ch, float frqHz); + void KeyOff(int ch); void _WriteReg(Bit32u reg, Bit8u value); + void _ClearRegBits(Bit32u reg, Bit8u mask); ~Hiopl(); private: Adlib::Handler *adlib; Bit8u regCache[256]; Bit32s *Buf32; bool _CheckParams(int ch, int osc); + void _milliHertzToFnum(unsigned int milliHertz, unsigned int *fnum, unsigned int *block, unsigned int conversionFactor=49716); }; diff --git a/Source/setup.h b/Source/setup.h index 4d7dd17..72fcc0e 100644 --- a/Source/setup.h +++ b/Source/setup.h @@ -24,6 +24,9 @@ #ifdef _MSC_VER #pragma warning ( disable : 4786 ) #pragma warning ( disable : 4290 ) +#pragma warning ( disable : 4512 ) // assignment operator could not be generated +#pragma warning ( disable : 4100 ) // unreferenced parameter + #endif