From 8fa4866ff8e5ec9402ed055e0eb30f697f86d552 Mon Sep 17 00:00:00 2001 From: "Raine M. Ekman" Date: Mon, 6 Jan 2014 21:26:26 +0100 Subject: [PATCH] Added OpulenZ, an FM synth for LMMS Signed-off-by: Tobias Doerffel --- data/themes/default/style.css | 7 + plugins/CMakeLists.txt | 1 + plugins/opl2/CMakeLists.txt | 3 + plugins/opl2/README | 62 ++ plugins/opl2/adlibemu.c | 600 +++++++++++++ plugins/opl2/adlibemu.h | 26 + plugins/opl2/artwork.png | Bin 0 -> 116949 bytes plugins/opl2/fmopl.c | 1390 +++++++++++++++++++++++++++++++ plugins/opl2/fmopl.h | 174 ++++ plugins/opl2/kemuopl.h | 61 ++ plugins/opl2/logo.png | Bin 0 -> 285 bytes plugins/opl2/mididata.h | 174 ++++ plugins/opl2/opl.h | 69 ++ plugins/opl2/opl2_led_off.png | Bin 0 -> 586 bytes plugins/opl2/opl2_led_on.png | Bin 0 -> 665 bytes plugins/opl2/opl2instrument.cpp | 613 ++++++++++++++ plugins/opl2/opl2instrument.h | 173 ++++ plugins/opl2/temuopl.cpp | 75 ++ plugins/opl2/temuopl.h | 47 ++ plugins/opl2/wave1_off.png | Bin 0 -> 749 bytes plugins/opl2/wave1_on.png | Bin 0 -> 786 bytes plugins/opl2/wave2_off.png | Bin 0 -> 435 bytes plugins/opl2/wave2_on.png | Bin 0 -> 520 bytes plugins/opl2/wave3_off.png | Bin 0 -> 497 bytes plugins/opl2/wave3_on.png | Bin 0 -> 580 bytes plugins/opl2/wave4_off.png | Bin 0 -> 693 bytes plugins/opl2/wave4_on.png | Bin 0 -> 742 bytes 27 files changed, 3475 insertions(+) create mode 100644 plugins/opl2/CMakeLists.txt create mode 100644 plugins/opl2/README create mode 100644 plugins/opl2/adlibemu.c create mode 100644 plugins/opl2/adlibemu.h create mode 100644 plugins/opl2/artwork.png create mode 100644 plugins/opl2/fmopl.c create mode 100644 plugins/opl2/fmopl.h create mode 100644 plugins/opl2/kemuopl.h create mode 100644 plugins/opl2/logo.png create mode 100644 plugins/opl2/mididata.h create mode 100644 plugins/opl2/opl.h create mode 100644 plugins/opl2/opl2_led_off.png create mode 100644 plugins/opl2/opl2_led_on.png create mode 100644 plugins/opl2/opl2instrument.cpp create mode 100644 plugins/opl2/opl2instrument.h create mode 100644 plugins/opl2/temuopl.cpp create mode 100644 plugins/opl2/temuopl.h create mode 100644 plugins/opl2/wave1_off.png create mode 100644 plugins/opl2/wave1_on.png create mode 100644 plugins/opl2/wave2_off.png create mode 100644 plugins/opl2/wave2_on.png create mode 100644 plugins/opl2/wave3_off.png create mode 100644 plugins/opl2/wave3_on.png create mode 100644 plugins/opl2/wave4_off.png create mode 100644 plugins/opl2/wave4_on.png diff --git a/data/themes/default/style.css b/data/themes/default/style.css index 49de862e8..908e609b4 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -224,6 +224,13 @@ sf2InstrumentView knob { qproperty-lineWidth: 2; } +opl2instrumentView knob { + color: rgb(128,128,128); + qproperty-outerColor: rgb(255,255,255); + qproperty-innerRadius: 2; + qproperty-outerRadius: 9; + qproperty-lineWidth: 2; +} /* Notes: lcd-spinbox colors: (12, 250, 150), (37, 57, 42) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index db590e379..0cbdc4359 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -10,6 +10,7 @@ ADD_SUBDIRECTORY(lb302) #ADD_SUBDIRECTORY(lb303) ADD_SUBDIRECTORY(midi_import) ADD_SUBDIRECTORY(organic) +ADD_SUBDIRECTORY(opl2) ADD_SUBDIRECTORY(papu) ADD_SUBDIRECTORY(patman) ADD_SUBDIRECTORY(peak_controller_effect) diff --git a/plugins/opl2/CMakeLists.txt b/plugins/opl2/CMakeLists.txt new file mode 100644 index 000000000..0b9bd32cd --- /dev/null +++ b/plugins/opl2/CMakeLists.txt @@ -0,0 +1,3 @@ +INCLUDE(BuildPlugin) + +BUILD_PLUGIN(OPL2 opl2instrument.cpp opl2instrument.h opl.h kemuopl.h adlibemu.c adlibemu.h fmopl.c fmopl.h temuopl.cpp temuopl.h MOCFILES opl2instrument.h EMBEDDED_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.png) \ No newline at end of file diff --git a/plugins/opl2/README b/plugins/opl2/README new file mode 100644 index 000000000..a9796c1cf --- /dev/null +++ b/plugins/opl2/README @@ -0,0 +1,62 @@ +Snatched from AdPlug 2.2.1: +adlibemu.c +adlibemu.h +fmopl.c +fmopl.h +kemuopl.h +opl.h +temuopl.cpp +temuopl.h +mididata.h + +1.2.2 Sound generation section +------------------------------ + +The Sound generation section is responsible for generating the OPL's +sound, according to the input of the Playback section. This sound is +either routed back to the application for it to do something with it or +routed directly to a specific audio hardware. + + The following headers provide the interface to the sound generation +section: `emuopl.h', `temuopl.h', `kemuopl.h', `realopl.h', +`silentopl.h', `analopl.h' and `diskopl.h'. All classes inside these +headers are derived from the abstract base class `Copl', declared +inside the file `opl.h', which provides the common interface for the +Backend layer of the Playback section. This interface is not meant for +the Frontend layer (i.e. your application). Your application, however, +has to call special methods of these classes in order to route the data +back, if there is any. + + `emuopl.h' provides the class `CEmuopl', which implements a virtual +OPL emulator, which automatically selects the best available OPL chip +emulation and type for each replayer. + + `temuopl.h' provides the class `CTEmuopl', which is a wrapper class +around Tatsuyuki Satoh's fmopl OPL2 emulator, which generates wave +audio data to be routed back to the application. + + `kemuopl.h' provides the class `CKemuopl', which is a wrapper class +around Ken Silverman's adlibemu OPL2 emulator, which generates wave +audio data to be routed back to the application. + + `realopl.h' provides the class `CRealopl', which outputs to a real +hardware OPL2 or OPL3 chip. No data is routed back to the application. +This class is currently only working on x86 hardware. + + `silentopl.h' provides the class `CSilentopl', which is a dummy +OPL2/3, which generates nothing. All data sent to it is forgotten +immediately. No data is routed back to the application. + + `analopl.h' provides the class `CAnalopl', which is the same as `CRealopl', +but also provides a 9-channel loudness pseudo-analyzer interface for +the application. The loudness data is the only data routed back to the +application. + + `diskopl.h' provides the class `CDiskopl', which is an OPL3 emulator +that does not output any sound to the soundcard, but instead writes all +received OPL commands to a file in the RdosPlay RAW format. + + +Patches can be found at: +http://cd.textfiles.com/soundsensations/SYNTH/ +(list at http://cd.textfiles.com/soundsensations/NEWMENU/SYNTH.BBS ) \ No newline at end of file diff --git a/plugins/opl2/adlibemu.c b/plugins/opl2/adlibemu.c new file mode 100644 index 000000000..c35d6da7d --- /dev/null +++ b/plugins/opl2/adlibemu.c @@ -0,0 +1,600 @@ +/* + * ADLIBEMU.C + * Copyright (C) 1998-2001 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* +This file is a digital Adlib emulator for OPL2 and possibly OPL3 + +Features that could be added in a future version: +- Amplitude and Frequency Vibrato Bits (not hard, but a big speed hit) +- Global Keyboard Split Number Bit (need to research this one some more) +- 2nd Adlib chip for OPL3 (simply need to make my cell array bigger) +- Advanced connection modes of OPL3 (Just need to add more "docell" cases) +- L/R Stereo bits of OPL3 (Need adlibgetsample to return stereo) + +Features that aren't worth supporting: +- Anything related to adlib timers&interrupts (Sorry - I always used IRQ0) +- Composite sine wave mode (CSM) (Supported only on ancient cards) + +I'm not sure about a few things in my code: +- Attack curve. What function is this anyway? I chose to use an order-3 + polynomial to approximate but this doesn't seem right. +- Attack/Decay/Release constants - my constants may not be exact +- What should ADJUSTSPEED be? +- Haven't verified that Global Keyboard Split Number Bit works yet +- Some of the drums don't always sound right. It's pretty hard to guess + the exact waveform of drums when you look at random data which is + slightly randomized due to digital ADC recording. +- Adlib seems to have a lot more treble than my emulator does. I'm not + sure if this is simply unfixable due to the sound blaster's different + filtering on FM and digital playback or if it's a serious bug in my + code. +*/ + +#include +#include + +#if !defined(max) && !defined(__cplusplus) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#if !defined(min) && !defined(__cplusplus) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define PI 3.141592653589793 +#define MAXCELLS 18 +#define WAVPREC 2048 + +static float AMPSCALE=(8192.0); +#define FRQSCALE (49716/512.0) + +//Constants for Ken's Awe32, on a PII-266 (Ken says: Use these for KSM's!) +#define MODFACTOR 4.0 //How much of modulator cell goes into carrier +#define MFBFACTOR 1.0 //How much feedback goes back into modulator +#define ADJUSTSPEED 0.75 //0<=x<=1 Simulate finite rate of change of state + +//Constants for Ken's Awe64G, on a P-133 +//#define MODFACTOR 4.25 //How much of modulator cell goes into carrier +//#define MFBFACTOR 0.5 //How much feedback goes back into modulator +//#define ADJUSTSPEED 0.85 //0<=x<=1 Simulate finite rate of change of state + +typedef struct +{ + float val, t, tinc, vol, sustain, amp, mfb; + float a0, a1, a2, a3, decaymul, releasemul; + short *waveform; + long wavemask; + void (*cellfunc)(void *, float); + unsigned char flags, dum0, dum1, dum2; +} celltype; + +static long numspeakers, bytespersample; +static float recipsamp; +static celltype cell[MAXCELLS]; +static signed short wavtable[WAVPREC*3]; +static float kslmul[4] = {0.0,0.5,0.25,1.0}; +static float frqmul[16] = {.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}, nfrqmul[16]; +static unsigned char adlibreg[256], ksl[8][16]; +static unsigned char modulatorbase[9] = {0,1,2,8,9,10,16,17,18}; +static unsigned char odrumstat = 0; +static unsigned char base2cell[22] = {0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8}; + +float lvol[9] = {1,1,1,1,1,1,1,1,1}; //Volume multiplier on left speaker +float rvol[9] = {1,1,1,1,1,1,1,1,1}; //Volume multiplier on right speaker +long lplc[9] = {0,0,0,0,0,0,0,0,0}; //Samples to delay on left speaker +long rplc[9] = {0,0,0,0,0,0,0,0,0}; //Samples to delay on right speaker + +long nlvol[9], nrvol[9]; +long nlplc[9], nrplc[9]; +long rend = 0; +#define FIFOSIZ 256 +static float *rptr[9], *nrptr[9]; +static float rbuf[9][FIFOSIZ*2]; +static float snd[FIFOSIZ*2]; + +#ifndef USING_ASM +#define _inline +#endif + +#ifdef USING_ASM +static _inline void ftol (float f, long *a) +{ + _asm + { + mov eax, a + fld f + fistp dword ptr [eax] + } +} +#else +static void ftol(float f, long *a) { + *a=f; +} +#endif + +#define ctc ((celltype *)c) //A rare attempt to make code easier to read! +void docell4 (void *c, float modulator) { } +void docell3 (void *c, float modulator) +{ + long i; + + ftol(ctc->t+modulator,&i); + ctc->t += ctc->tinc; + ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED; +} +void docell2 (void *c, float modulator) +{ + long i; + + ftol(ctc->t+modulator,&i); + + if (*(long *)&ctc->amp <= 0x37800000) + { + ctc->amp = 0; + ctc->cellfunc = docell4; + } + ctc->amp *= ctc->releasemul; + + ctc->t += ctc->tinc; + ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED; +} +void docell1 (void *c, float modulator) +{ + long i; + + ftol(ctc->t+modulator,&i); + + if ((*(long *)&ctc->amp) <= (*(long *)&ctc->sustain)) + { + if (ctc->flags&32) + { + ctc->amp = ctc->sustain; + ctc->cellfunc = docell3; + } + else + ctc->cellfunc = docell2; + } + else + ctc->amp *= ctc->decaymul; + + ctc->t += ctc->tinc; + ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED; +} +void docell0 (void *c, float modulator) +{ + long i; + + ftol(ctc->t+modulator,&i); + + ctc->amp = ((ctc->a3*ctc->amp + ctc->a2)*ctc->amp + ctc->a1)*ctc->amp + ctc->a0; + if ((*(long *)&ctc->amp) > 0x3f800000) + { + ctc->amp = 1; + ctc->cellfunc = docell1; + } + + ctc->t += ctc->tinc; + ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED; +} + + +static long waveform[8] = {WAVPREC,WAVPREC>>1,WAVPREC,(WAVPREC*3)>>2,0,0,(WAVPREC*5)>>2,WAVPREC<<1}; +static long wavemask[8] = {WAVPREC-1,WAVPREC-1,(WAVPREC>>1)-1,(WAVPREC>>1)-1,WAVPREC-1,((WAVPREC*3)>>2)-1,WAVPREC>>1,WAVPREC-1}; +static long wavestart[8] = {0,WAVPREC>>1,0,WAVPREC>>2,0,0,0,WAVPREC>>3}; +static float attackconst[4] = {1/2.82624,1/2.25280,1/1.88416,1/1.59744}; +static float decrelconst[4] = {1/39.28064,1/31.41608,1/26.17344,1/22.44608}; +void cellon (long i, long j, celltype *c, unsigned char iscarrier) +{ + long frn, oct, toff; + float f; + + frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0]; + oct = ((((long)adlibreg[i+0xb0])>>2)&7); + toff = (oct<<1) + ((frn>>9)&((frn>>8)|(((adlibreg[8]>>6)&1)^1))); + if (!(adlibreg[j+0x20]&16)) toff >>= 2; + + f = pow(2.0,(adlibreg[j+0x60]>>4)+(toff>>2)-1)*attackconst[toff&3]*recipsamp; + c->a0 = .0377*f; c->a1 = 10.73*f+1; c->a2 = -17.57*f; c->a3 = 7.42*f; + f = -7.4493*decrelconst[toff&3]*recipsamp; + c->decaymul = pow(2.0,f*pow(2.0,(adlibreg[j+0x60]&15)+(toff>>2))); + c->releasemul = pow(2.0,f*pow(2.0,(adlibreg[j+0x80]&15)+(toff>>2))); + c->wavemask = wavemask[adlibreg[j+0xe0]&7]; + c->waveform = &wavtable[waveform[adlibreg[j+0xe0]&7]]; + if (!(adlibreg[1]&0x20)) c->waveform = &wavtable[WAVPREC]; + c->t = wavestart[adlibreg[j+0xe0]&7]; + c->flags = adlibreg[j+0x20]; + c->cellfunc = docell0; + c->tinc = (float)(frn<vol = pow(2.0,((float)(adlibreg[j+0x40]&63) + + (float)kslmul[adlibreg[j+0x40]>>6]*ksl[oct][frn>>6]) * -.125 - 14); + c->sustain = pow(2.0,(float)(adlibreg[j+0x80]>>4) * -.5); + if (!iscarrier) c->amp = 0; + c->mfb = pow(2.0,((adlibreg[i+0xc0]>>1)&7)+5)*(WAVPREC/2048.0)*MFBFACTOR; + if (!(adlibreg[i+0xc0]&14)) c->mfb = 0; + c->val = 0; +} + +//This function (and bug fix) written by Chris Moeller +void cellfreq (signed long i, signed long j, celltype *c) +{ + long frn, oct; + + frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0]; + oct = ((((long)adlibreg[i+0xb0])>>2)&7); + + c->tinc = (float)(frn<vol = pow(2.0,((float)(adlibreg[j+0x40]&63) + + (float)kslmul[adlibreg[j+0x40]>>6]*ksl[oct][frn>>6]) * -.125 - 14); +} + +static long initfirstime = 0; +void adlibinit (long dasamplerate, long danumspeakers, long dabytespersample) +{ + long i, j, frn, oct; + + memset((void *)adlibreg,0,sizeof(adlibreg)); + memset((void *)cell,0,sizeof(celltype)*MAXCELLS); + memset((void *)rbuf,0,sizeof(rbuf)); + rend = 0; odrumstat = 0; + + for(i=0;i=0;i--) nfrqmul[i] = frqmul[i]*recipsamp*FRQSCALE*(WAVPREC/2048.0); + + if (!initfirstime) + { + initfirstime = 1; + + for(i=0;i<(WAVPREC>>1);i++) + { + wavtable[i] = + wavtable[(i<<1) +WAVPREC] = (signed short)(16384*sin((float)((i<<1) )*PI*2/WAVPREC)); + wavtable[(i<<1)+1+WAVPREC] = (signed short)(16384*sin((float)((i<<1)+1)*PI*2/WAVPREC)); + } + for(i=0;i<(WAVPREC>>3);i++) + { + wavtable[i+(WAVPREC<<1)] = wavtable[i+(WAVPREC>>3)]-16384; + wavtable[i+((WAVPREC*17)>>3)] = wavtable[i+(WAVPREC>>2)]+16384; + } + + //[table in book]*8/3 + ksl[7][0] = 0; ksl[7][1] = 24; ksl[7][2] = 32; ksl[7][3] = 37; + ksl[7][4] = 40; ksl[7][5] = 43; ksl[7][6] = 45; ksl[7][7] = 47; + ksl[7][8] = 48; for(i=9;i<16;i++) ksl[7][i] = i+41; + for(j=6;j>=0;j--) + for(i=0;i<16;i++) + { + oct = (long)ksl[j+1][i]-8; if (oct < 0) oct = 0; + ksl[j][i] = (unsigned char)oct; + } + } + else + { + for(i=0;i<9;i++) + { + frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0]; + oct = ((((long)adlibreg[i+0xb0])>>2)&7); + cell[i].tinc = (float)(frn< (odrumstat&16)) //BassDrum + { + cellon(6,16,&cell[6],0); + cellon(6,19,&cell[15],1); + cell[15].vol *= 2; + } + if ((v&8) > (odrumstat&8)) //Snare + { + cellon(16,20,&cell[16],0); + cell[16].tinc *= 2*(nfrqmul[adlibreg[17+0x20]&15] / nfrqmul[adlibreg[20+0x20]&15]); + if (((adlibreg[20+0xe0]&7) >= 3) && ((adlibreg[20+0xe0]&7) <= 5)) cell[16].vol = 0; + cell[16].vol *= 2; + } + if ((v&4) > (odrumstat&4)) //TomTom + { + cellon(8,18,&cell[8],0); + cell[8].vol *= 2; + } + if ((v&2) > (odrumstat&2)) //Cymbal + { + cellon(17,21,&cell[17],0); + + cell[17].wavemask = wavemask[5]; + cell[17].waveform = &wavtable[waveform[5]]; + cell[17].tinc *= 16; cell[17].vol *= 2; + + //cell[17].waveform = &wavtable[WAVPREC]; cell[17].wavemask = 0; + //if (((adlibreg[21+0xe0]&7) == 0) || ((adlibreg[21+0xe0]&7) == 6)) + // cell[17].waveform = &wavtable[(WAVPREC*7)>>2]; + //if (((adlibreg[21+0xe0]&7) == 2) || ((adlibreg[21+0xe0]&7) == 3)) + // cell[17].waveform = &wavtable[(WAVPREC*5)>>2]; + } + if ((v&1) > (odrumstat&1)) //Hihat + { + cellon(7,17,&cell[7],0); + if (((adlibreg[17+0xe0]&7) == 1) || ((adlibreg[17+0xe0]&7) == 4) || + ((adlibreg[17+0xe0]&7) == 5) || ((adlibreg[17+0xe0]&7) == 7)) cell[7].vol = 0; + if ((adlibreg[17+0xe0]&7) == 6) { cell[7].wavemask = 0; cell[7].waveform = &wavtable[(WAVPREC*7)>>2]; } + } + + odrumstat = v; + } + else if (((unsigned)(i-0x40) < (unsigned)22) && ((i&7) < 6)) + { + if ((i&7) < 3) // Modulator + cellfreq(base2cell[i-0x40],i-0x40,&cell[base2cell[i-0x40]]); + else // Carrier + cellfreq(base2cell[i-0x40],i-0x40,&cell[base2cell[i-0x40]+9]); + } + else if ((unsigned)(i-0xa0) < (unsigned)9) + { + cellfreq(i-0xa0,modulatorbase[i-0xa0],&cell[i-0xa0]); + cellfreq(i-0xa0,modulatorbase[i-0xa0]+3,&cell[i-0xa0+9]); + } + else if ((unsigned)(i-0xb0) < (unsigned)9) + { + if ((v&32) > (tmp&32)) + { + cellon(i-0xb0,modulatorbase[i-0xb0],&cell[i-0xb0],0); + cellon(i-0xb0,modulatorbase[i-0xb0]+3,&cell[i-0xb0+9],1); + } + else if ((v&32) < (tmp&32)) + cell[i-0xb0].cellfunc = cell[i-0xb0+9].cellfunc = docell2; + cellfreq(i-0xb0,modulatorbase[i-0xb0],&cell[i-0xb0]); + cellfreq(i-0xb0,modulatorbase[i-0xb0]+3,&cell[i-0xb0+9]); + } + + //outdata(i,v); +} + +#ifdef USING_ASM +static long fpuasm; +static float fakeadd = 8388608.0+128.0; +static _inline void clipit8 (float f, long a) +{ + _asm + { + mov edi, a + fld dword ptr f + fadd dword ptr fakeadd + fstp dword ptr fpuasm + mov eax, fpuasm + test eax, 0x007fff00 + jz short skipit + shr eax, 16 + xor eax, -1 + skipit: mov byte ptr [edi], al + } +} + +static _inline void clipit16 (float f, long a) +{ + _asm + { + mov eax, a + fld dword ptr f + fist word ptr [eax] + cmp word ptr [eax], 0x8000 + jne short skipit2 + fst dword ptr [fpuasm] + cmp fpuasm, 0x80000000 + sbb word ptr [eax], 0 + skipit2: fstp st + } +} +#else +static void clipit8(float f,unsigned char *a) { + f/=256.0; + f+=128.0; + if (f>254.5) *a=255; + else if (f<0.5) *a=0; + else *a=f; +} + +static void clipit16(float f,short *a) { + if (f>32766.5) *a=32767; + else if (f<-32767.5) *a=-32768; + else *a=f; +} +#endif + +void adlibsetvolume(int i) { + AMPSCALE=i; +} + +void adlibgetsample (unsigned char *sndptr, long numbytes) +{ + long i, j, k=0, ns, endsamples, rptrs, numsamples; + celltype *cptr; + float f; + short *sndptr2=(short *)sndptr; + + numsamples = (numbytes>>(numspeakers+bytespersample-2)); + + if (bytespersample == 1) f = AMPSCALE/256.0; else f = AMPSCALE; + if (numspeakers == 1) + { + nlvol[0] = lvol[0]*f; + for(i=0;i<9;i++) rptr[i] = &rbuf[0][0]; + rptrs = 1; + } + else + { + rptrs = 0; + for(i=0;i<9;i++) + { + if ((!i) || (lvol[i] != lvol[i-1]) || (rvol[i] != rvol[i-1]) || + (lplc[i] != lplc[i-1]) || (rplc[i] != rplc[i-1])) + { + nlvol[rptrs] = lvol[i]*f; + nrvol[rptrs] = rvol[i]*f; + nlplc[rptrs] = rend-min(max(lplc[i],0),FIFOSIZ); + nrplc[rptrs] = rend-min(max(rplc[i],0),FIFOSIZ); + rptrs++; + } + rptr[i] = &rbuf[rptrs-1][0]; + } + } + + + //CPU time used to be somewhat less when emulator was only mono! + // Because of no delay fifos! + + for(ns=0;ns>1)-1)); //Snare + (cell[7].cellfunc)((void *)&cell[7],k&(WAVPREC-1)); //Hihat + (cell[17].cellfunc)((void *)&cell[17],k&((WAVPREC>>3)-1)); //Cymbal + (cell[8].cellfunc)((void *)&cell[8],0.0); //TomTom + nrptr[7][i] += cell[7].val + cell[16].val; + nrptr[8][i] += cell[8].val + cell[17].val; + } + } + } + for(j=9-1;j>=0;j--) + { + if ((adlibreg[0xbd]&0x20) && (j >= 6) && (j < 9)) continue; + + cptr = &cell[j]; k = j; + if (adlibreg[0xc0+k]&1) + { + if ((cptr[9].cellfunc == docell4) && (cptr->cellfunc == docell4)) continue; + for(i=0;icellfunc)((void *)cptr,cptr->val*cptr->mfb); + (cptr->cellfunc)((void *)&cptr[9],0); + nrptr[j][i] += cptr[9].val + cptr->val; + } + } + else + { + if (cptr[9].cellfunc == docell4) continue; + for(i=0;icellfunc)((void *)cptr,cptr->val*cptr->mfb); + (cptr[9].cellfunc)((void *)&cptr[9],cptr->val*WAVPREC*MODFACTOR); + nrptr[j][i] += cptr[9].val; + } + } + } + + if (numspeakers == 1) + { + if (bytespersample == 1) + { + for(i=endsamples-1;i>=0;i--) + clipit8(nrptr[0][i]*nlvol[0],sndptr+1); + } + else + { + for(i=endsamples-1;i>=0;i--) + clipit16(nrptr[0][i]*nlvol[0],sndptr2+i); + } + } + else + { + memset((void *)snd,0,endsamples*sizeof(float)*2); + for(j=0;j=0;i--) + clipit8(snd[i],sndptr+i); + } + else + { + for(i=(endsamples<<1)-1;i>=0;i--) + clipit16(snd[i],sndptr2+i); + } + } + + sndptr = sndptr+(numspeakers*endsamples); + sndptr2 = sndptr2+(numspeakers*endsamples); + rend = ((rend+endsamples)&(FIFOSIZ*2-1)); + } +} diff --git a/plugins/opl2/adlibemu.h b/plugins/opl2/adlibemu.h new file mode 100644 index 000000000..8600d787d --- /dev/null +++ b/plugins/opl2/adlibemu.h @@ -0,0 +1,26 @@ +/* + * ADLIBEMU.H + * Copyright (C) 1998-2001 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void adlibinit(long dasamplerate,long danumspeakers,long dabytespersample); +void adlib0(long i,long v); +void adlibgetsample(void *sndptr,long numbytes); +void adlibsetvolume(int i); +void randoinsts(); +extern float lvol[9],rvol[9],lplc[9],rplc[9]; diff --git a/plugins/opl2/artwork.png b/plugins/opl2/artwork.png new file mode 100644 index 0000000000000000000000000000000000000000..2aaf32ebb191708c14ac489f1e6033ae4e898683 GIT binary patch literal 116949 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Ě^ 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 +#include +#include +#include +#include +//#include "driver.h" /* use M.A.M.E. */ +#include "fmopl.h" + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +/* -------------------- for debug --------------------- */ +/* #define OPL_OUTPUT_LOG */ +#ifdef OPL_OUTPUT_LOG +static FILE *opl_dbg_fp = NULL; +static FM_OPL *opl_dbg_opl[16]; +static int opl_dbg_maxchip,opl_dbg_chip; +#endif + +/* -------------------- preliminary define section --------------------- */ +/* attack/decay rate time rate */ +#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */ +#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */ + +#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */ + +#define FREQ_BITS 24 /* frequency turn */ + +/* counter bits = 20 , octerve 7 */ +#define FREQ_RATE (1<<(FREQ_BITS-20)) +#define TL_BITS (FREQ_BITS+2) + +/* final output shift , limit minimum and maximum */ +#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */ +#define OPL_MAXOUT (0x7fff<=LOG_LEVEL ) logerror x +#define LOG(n,x) + +/* --------------------- subroutines --------------------- */ + +INLINE int Limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + +/* status set and IRQ handling */ +INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) +{ + /* set status flag */ + OPL->status |= flag; + if(!(OPL->status & 0x80)) + { + if(OPL->status & OPL->statusmask) + { /* IRQ on */ + OPL->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) +{ + /* reset status flag */ + OPL->status &=~flag; + if((OPL->status & 0x80)) + { + if (!(OPL->status & OPL->statusmask) ) + { + OPL->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); + } + } +} + +/* IRQ mask set */ +INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) +{ + OPL->statusmask = flag; + /* IRQ handling check */ + OPL_STATUS_SET(OPL,0); + OPL_STATUS_RESET(OPL,0); +} + +/* ----- key on ----- */ +INLINE void OPL_KEYON(OPL_SLOT *SLOT) +{ + /* sin wave restart */ + SLOT->Cnt = 0; + /* set attack */ + SLOT->evm = ENV_MOD_AR; + SLOT->evs = SLOT->evsa; + SLOT->evc = EG_AST; + SLOT->eve = EG_AED; +} +/* ----- key off ----- */ +INLINE void OPL_KEYOFF(OPL_SLOT *SLOT) +{ + if( SLOT->evm > ENV_MOD_RR) + { + /* set envelope counter from envleope output */ + SLOT->evm = ENV_MOD_RR; + if( !(SLOT->evc&EG_DST) ) + //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<evc = EG_DST; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->evsr; + } +} + +/* ---------- calcrate Envelope Generator & Phase Generator ---------- */ +/* return : envelope output */ +INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) +{ + /* calcrate envelope generator */ + if( (SLOT->evc+=SLOT->evs) >= SLOT->eve ) + { + switch( SLOT->evm ){ + case ENV_MOD_AR: /* ATTACK -> DECAY1 */ + /* next DR */ + SLOT->evm = ENV_MOD_DR; + SLOT->evc = EG_DST; + SLOT->eve = SLOT->SL; + SLOT->evs = SLOT->evsd; + break; + case ENV_MOD_DR: /* DECAY -> SL or RR */ + SLOT->evc = SLOT->SL; + SLOT->eve = EG_DED; + if(SLOT->eg_typ) + { + SLOT->evs = 0; + } + else + { + SLOT->evm = ENV_MOD_RR; + SLOT->evs = SLOT->evsr; + } + break; + case ENV_MOD_RR: /* RR -> OFF */ + SLOT->evc = EG_OFF; + SLOT->eve = EG_OFF+1; + SLOT->evs = 0; + break; + } + } + /* calcrate envelope */ + return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0); +} + +/* set algorythm connection */ +static void set_algorythm( OPL_CH *CH) +{ + INT32 *carrier = &outd[0]; + CH->connect1 = CH->CON ? carrier : &feedback2; + CH->connect2 = carrier; +} + +/* ---------- frequency counter for operater update ---------- */ +INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) +{ + int ksr; + + /* frequency step counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + /* attack , decay rate recalcration */ + SLOT->evsa = SLOT->AR[ksr]; + SLOT->evsd = SLOT->DR[ksr]; + SLOT->evsr = SLOT->RR[ksr]; + } + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = MUL_TABLE[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_typ = (v&0x20)>>5; + SLOT->vib = (v&0x40); + SLOT->ams = (v&0x80); + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl & tl */ +INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TL = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */ + + if( !(OPL->mode&0x80) ) + { /* not CSM latch total level */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ar = v>>4; + int dr = v&0x0f; + + SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0; + SLOT->evsa = SLOT->AR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa; + + SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0; + SLOT->evsd = SLOT->DR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int sl = v>>4; + int rr = v & 0x0f; + + SLOT->SL = SL_TABLE[sl]; + if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL; + SLOT->RR = &OPL->DR_TABLE[rr<<2]; + SLOT->evsr = SLOT->RR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr; +} + +/* operator output calcrator */ +#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env] +/* ---------- calcrate one of channel ---------- */ +INLINE void OPL_CALC_CH( OPL_CH *CH ) +{ + UINT32 env_out; + OPL_SLOT *SLOT; + + feedback2 = 0; + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + if(CH->FB) + { + int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; + CH->op1_out[1] = CH->op1_out[0]; + *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1); + } + else + { + *CH->connect1 += OP_OUT(SLOT,env_out,0); + } + }else + { + CH->op1_out[1] = CH->op1_out[0]; + CH->op1_out[0] = 0; + } + /* SLOT 2 */ + SLOT = &CH->SLOT[SLOT2]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + outd[0] += OP_OUT(SLOT,env_out, feedback2); + } +} + +/* ---------- calcrate rythm block ---------- */ +#define WHITE_NOISE_db 6.0 +INLINE void OPL_CALC_RH( OPL_CH *CH ) +{ + UINT32 env_tam,env_sd,env_top,env_hh; + int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); + INT32 tone8; + + OPL_SLOT *SLOT; + int env_out; + + /* BD : same as FM serial mode and output level is large */ + feedback2 = 0; + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + if(CH[6].FB) + { + int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB; + CH[6].op1_out[1] = CH[6].op1_out[0]; + feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1); + } + else + { + feedback2 = OP_OUT(SLOT,env_out,0); + } + }else + { + feedback2 = 0; + CH[6].op1_out[1] = CH[6].op1_out[0]; + CH[6].op1_out[0] = 0; + } + /* SLOT 2 */ + SLOT = &CH[6].SLOT[SLOT2]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + outd[0] += OP_OUT(SLOT,env_out, feedback2)*2; + } + + // SD (17) = mul14[fnum7] + white noise + // TAM (15) = mul15[fnum8] + // TOP (18) = fnum6(mul18[fnum8]+whitenoise) + // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise + env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise; + env_tam=OPL_CALC_SLOT(SLOT8_1); + env_top=OPL_CALC_SLOT(SLOT8_2); + env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise; + + /* PG */ + if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE); + else SLOT7_1->Cnt += 2*SLOT7_1->Incr; + if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE); + else SLOT7_2->Cnt += (CH[7].fc*8); + if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE); + else SLOT8_1->Cnt += SLOT8_1->Incr; + if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE); + else SLOT8_2->Cnt += (CH[8].fc*48); + + tone8 = OP_OUT(SLOT8_2,whitenoise,0 ); + + /* SD */ + if( env_sd < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8; + /* TAM */ + if( env_tam < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2; + /* TOP-CY */ + if( env_top < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2; + /* HH */ + if( env_hh < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2; +} + +/* ----------- initialize time tabls ----------- */ +static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ) +{ + int i; + double rate; + + /* make attack rate & decay rate tables */ + for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0; + for (i = 4;i <= 60;i++){ + rate = OPL->freqbase; /* frequency rate */ + if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ + rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ + rate *= (double)(EG_ENT<AR_TABLE[i] = rate / ARRATE; + OPL->DR_TABLE[i] = rate / DRRATE; + } + for (i = 60;i < 76;i++) + { + OPL->AR_TABLE[i] = EG_AED-1; + OPL->DR_TABLE[i] = OPL->DR_TABLE[60]; + } +#if 0 + for (i = 0;i < 64 ;i++){ /* make for overflow area */ + LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i, + ((double)(EG_ENT<AR_TABLE[i]) * (1000.0 / OPL->rate), + ((double)(EG_ENT<DR_TABLE[i]) * (1000.0 / OPL->rate) )); + } +#endif +} + +/* ---------- generic table initialize ---------- */ +static int OPLOpenTable( void ) +{ + int s,t; + double rate; + int i,j; + double pom; + + /* allocate dynamic tables */ + if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL) + return 0; + if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL) + { + free(TL_TABLE); + return 0; + } + if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL) + { + free(TL_TABLE); + free(SIN_TABLE); + return 0; + } + if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL) + { + free(TL_TABLE); + free(SIN_TABLE); + free(AMS_TABLE); + return 0; + } + /* make total level table */ + for (t = 0;t < EG_ENT-1 ;t++){ + rate = ((1< voltage */ + TL_TABLE[ t] = (int)rate; + TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; +/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/ + } + /* fill volume off area */ + for ( t = EG_ENT-1; t < TL_MAX ;t++){ + TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0; + } + + /* make sinwave table (total level offet) */ + /* degree 0 = degree 180 = off */ + SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1]; + for (s = 1;s <= SIN_ENT/4;s++){ + pom = sin(2*PI*s/SIN_ENT); /* sin */ + pom = 20*log10(1/pom); /* decibel */ + j = pom / EG_STEP; /* TL_TABLE steps */ + + /* degree 0 - 90 , degree 180 - 90 : plus section */ + SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; + /* degree 180 - 270 , degree 360 - 270 : minus section */ + SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; +/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/ + } + for (s = 0;s < SIN_ENT;s++) + { + SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; + SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)]; + SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s]; + } + + /* envelope counter -> envelope output table */ + for (i=0; i= EG_ENT ) pom = EG_ENT-1; */ + ENV_CURVE[i] = (int)pom; + /* DECAY ,RELEASE curve */ + ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; + } + /* off */ + ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; + /* make LFO ams table */ + for (i=0; iSLOT[SLOT1]; + OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; + /* all key off */ + OPL_KEYOFF(slot1); + OPL_KEYOFF(slot2); + /* total level latch */ + slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); + slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); + /* key on */ + CH->op1_out[0] = CH->op1_out[1] = 0; + OPL_KEYON(slot1); + OPL_KEYON(slot2); +} + +/* ---------- opl initialize ---------- */ +static void OPL_initalize(FM_OPL *OPL) +{ + int fn; + + /* frequency base */ + OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; + /* Timer base time */ + OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 ); + /* make time tables */ + init_timetables( OPL , OPL_ARRATE , OPL_DRRATE ); + /* make fnumber -> increment counter table */ + for( fn=0 ; fn < 1024 ; fn++ ) + { + OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2; + } + /* LFO freq.table */ + OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<rate * 3.7 * ((double)OPL->clock/3600000) : 0; + OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<rate * 6.4 * ((double)OPL->clock/3600000) : 0; +} + +/* ---------- write a OPL registers ---------- */ +static void OPLWriteReg(FM_OPL *OPL, int r, int v) +{ + OPL_CH *CH; + int slot; + int block_fnum; + + switch(r&0xe0) + { + case 0x00: /* 00-1f:controll */ + switch(r&0x1f) + { + case 0x01: + /* wave selector enable */ + if(OPL->type&OPL_TYPE_WAVESEL) + { + OPL->wavesel = v&0x20; + if(!OPL->wavesel) + { + /* preset compatible mode */ + int c; + for(c=0;cmax_ch;c++) + { + OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; + OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; + } + } + } + return; + case 0x02: /* Timer 1 */ + OPL->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + OPL->T[1] = (256-v)*16; + return; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flag clear */ + OPL_STATUS_RESET(OPL,0x7f); + } + else + { /* set IRQ mask ,timer enable*/ + UINT8 st1 = v&1; + UINT8 st2 = (v>>1)&1; + /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ + OPL_STATUS_RESET(OPL,v&0x78); + OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); + /* timer 2 */ + if(OPL->st[1] != st2) + { + double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; + OPL->st[1] = st2; + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); + } + /* timer 1 */ + if(OPL->st[0] != st1) + { + double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; + OPL->st[0] = st1; + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); + } + } + return; +#if BUILD_Y8950 + case 0x06: /* Key Board OUT */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_w) + OPL->keyboardhandler_w(OPL->keyboard_param,v); + else + LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n")); + } + return; + case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + return; + case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ + OPL->mode = v; + v&=0x1f; /* for DELTA-T unit */ + case 0x09: /* START ADD */ + case 0x0a: + case 0x0b: /* STOP ADD */ + case 0x0c: + case 0x0d: /* PRESCALE */ + case 0x0e: + case 0x0f: /* ADPCM data */ + case 0x10: /* DELTA-N */ + case 0x11: /* DELTA-N */ + case 0x12: /* EG-CTRL */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + return; +#if 0 + case 0x15: /* DAC data */ + case 0x16: + case 0x17: /* SHIFT */ + return; + case 0x18: /* I/O CTRL (Direction) */ + if(OPL->type&OPL_TYPE_IO) + OPL->portDirection = v&0x0f; + return; + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + OPL->portLatch = v; + if(OPL->porthandler_w) + OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); + } + return; + case 0x1a: /* PCM data */ + return; +#endif +#endif + } + break; + case 0x20: /* am,vib,ksr,eg type,mul */ + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_mul(OPL,slot,v); + return; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_ksl_tl(OPL,slot,v); + return; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_ar_dr(OPL,slot,v); + return; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_sl_rr(OPL,slot,v); + return; + case 0xa0: + switch(r) + { + case 0xbd: + /* amsep,vibdep,r,bd,sd,tom,tc,hh */ + { + UINT8 rkey = OPL->rythm^v; + OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; + OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; + OPL->rythm = v&0x3f; + if(OPL->rythm&0x20) + { +#if 0 + usrintf_showmessage("OPL Rythm mode select"); +#endif + /* BD key on/off */ + if(rkey&0x10) + { + if(v&0x10) + { + OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; + OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]); + OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]); + } + else + { + OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]); + OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]); + } + } + /* SD key on/off */ + if(rkey&0x08) + { + if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); + else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); + }/* TAM key on/off */ + if(rkey&0x04) + { + if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); + else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]); + } + /* TOP-CY key on/off */ + if(rkey&0x02) + { + if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); + else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); + } + /* HH key on/off */ + if(rkey&0x01) + { + if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); + else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); + } + } + } + return; + } + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + int keyon = (v>>5)&1; + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + if(CH->keyon != keyon) + { + if( (CH->keyon=keyon) ) + { + CH->op1_out[0] = CH->op1_out[1] = 0; + OPL_KEYON(&CH->SLOT[SLOT1]); + OPL_KEYON(&CH->SLOT[SLOT2]); + } + else + { + OPL_KEYOFF(&CH->SLOT[SLOT1]); + OPL_KEYOFF(&CH->SLOT[SLOT2]); + } + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + int blockRv = 7-(block_fnum>>10); + int fnum = block_fnum&0x3ff; + CH->block_fnum = block_fnum; + + CH->ksl_base = KSL_TABLE[block_fnum>>6]; + CH->fc = OPL->FN_TABLE[fnum]>>blockRv; + CH->kcode = CH->block_fnum>>9; + if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1; + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + return; + case 0xc0: + /* FB,C */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + { + int feedback = (v>>1)&7; + CH->FB = feedback ? (8+1) - feedback : 0; + CH->CON = v&1; + set_algorythm(CH); + } + return; + case 0xe0: /* wave type */ + slot = slot_array[r&0x1f]; + if(slot == -1) return; + CH = &OPL->P_CH[slot/2]; + if(OPL->wavesel) + { + /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */ + CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT]; + } + return; + } +} + +/* lock/unlock for common table */ +static int OPL_LockTable(void) +{ + num_lock++; + if(num_lock>1) return 0; + /* first time */ + cur_chip = NULL; + /* allocate total level table (128kb space) */ + if( !OPLOpenTable() ) + { + num_lock--; + return -1; + } + return 0; +} + +static void OPL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + /* last time */ + cur_chip = NULL; + OPLCloseTable(); +} + +#if (BUILD_YM3812 || BUILD_YM3526) +/*******************************************************************************/ +/* YM3812 local section */ +/*******************************************************************************/ + +/* ---------- update one of chip ----------- */ +void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) +{ + int i; + int data; + OPLSAMPLE *buf = buffer; + UINT32 amsCnt = OPL->amsCnt; + UINT32 vibCnt = OPL->vibCnt; + UINT8 rythm = OPL->rythm&0x20; + OPL_CH *CH,*R_CH; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* channel pointers */ + S_CH = OPL->P_CH; + E_CH = &S_CH[9]; + /* rythm slot */ + SLOT7_1 = &S_CH[7].SLOT[SLOT1]; + SLOT7_2 = &S_CH[7].SLOT[SLOT2]; + SLOT8_1 = &S_CH[8].SLOT[SLOT1]; + SLOT8_2 = &S_CH[8].SLOT[SLOT2]; + /* LFO state */ + amsIncr = OPL->amsIncr; + vibIncr = OPL->vibIncr; + ams_table = OPL->ams_table; + vib_table = OPL->vib_table; + } + R_CH = rythm ? &S_CH[6] : E_CH; + for( i=0; i < length ; i++ ) + { + /* channel A channel B channel C */ + /* LFO */ + ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; + vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; + outd[0] = 0; + /* FM part */ + for(CH=S_CH ; CH < R_CH ; CH++) + OPL_CALC_CH(CH); + /* Rythn part */ + if(rythm) + OPL_CALC_RH(S_CH); + /* limit check */ + data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); + /* store to sound buffer */ + buf[i] = data >> OPL_OUTSB; + } + + OPL->amsCnt = amsCnt; + OPL->vibCnt = vibCnt; +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + for(opl_dbg_chip=0;opl_dbg_chipamsCnt; + UINT32 vibCnt = OPL->vibCnt; + UINT8 rythm = OPL->rythm&0x20; + OPL_CH *CH,*R_CH; + YM_DELTAT *DELTAT = OPL->deltat; + + /* setup DELTA-T unit */ + YM_DELTAT_DECODE_PRESET(DELTAT); + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* channel pointers */ + S_CH = OPL->P_CH; + E_CH = &S_CH[9]; + /* rythm slot */ + SLOT7_1 = &S_CH[7].SLOT[SLOT1]; + SLOT7_2 = &S_CH[7].SLOT[SLOT2]; + SLOT8_1 = &S_CH[8].SLOT[SLOT1]; + SLOT8_2 = &S_CH[8].SLOT[SLOT2]; + /* LFO state */ + amsIncr = OPL->amsIncr; + vibIncr = OPL->vibIncr; + ams_table = OPL->ams_table; + vib_table = OPL->vib_table; + } + R_CH = rythm ? &S_CH[6] : E_CH; + for( i=0; i < length ; i++ ) + { + /* channel A channel B channel C */ + /* LFO */ + ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; + vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; + outd[0] = 0; + /* deltaT ADPCM */ + if( DELTAT->portstate ) + YM_DELTAT_ADPCM_CALC(DELTAT); + /* FM part */ + for(CH=S_CH ; CH < R_CH ; CH++) + OPL_CALC_CH(CH); + /* Rythn part */ + if(rythm) + OPL_CALC_RH(S_CH); + /* limit check */ + data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); + /* store to sound buffer */ + buf[i] = data >> OPL_OUTSB; + } + OPL->amsCnt = amsCnt; + OPL->vibCnt = vibCnt; + /* deltaT START flag */ + if( !DELTAT->portstate ) + OPL->status &= 0xfe; +} +#endif + +/* ---------- reset one of chip ---------- */ +void OPLResetChip(FM_OPL *OPL) +{ + int c,s; + int i; + + /* reset chip */ + OPL->mode = 0; /* normal mode */ + OPL_STATUS_RESET(OPL,0x7f); + /* reset with register write */ + OPLWriteReg(OPL,0x01,0); /* wabesel disable */ + OPLWriteReg(OPL,0x02,0); /* Timer1 */ + OPLWriteReg(OPL,0x03,0); /* Timer2 */ + OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + /* reset OPerator paramater */ + for( c = 0 ; c < OPL->max_ch ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + /* OPL->P_CH[c].PAN = OPN_CENTER; */ + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = &SIN_TABLE[0]; + /* CH->SLOT[s].evm = ENV_MOD_RR; */ + CH->SLOT[s].evc = EG_OFF; + CH->SLOT[s].eve = EG_OFF+1; + CH->SLOT[s].evs = 0; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = outd; + DELTAT->portshift = 5; + DELTAT->output_range = DELTAT_MIXING_LEVEL<P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch; +#if BUILD_Y8950 + if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT); +#endif + /* set channel state pointer */ + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + OPL->max_ch = max_ch; + /* init grobal tables */ + OPL_initalize(OPL); + /* reset chip */ + OPLResetChip(OPL); +#ifdef OPL_OUTPUT_LOG + if(!opl_dbg_fp) + { + opl_dbg_fp = fopen("opllog.opl","wb"); + opl_dbg_maxchip = 0; + } + if(opl_dbg_fp) + { + opl_dbg_opl[opl_dbg_maxchip] = OPL; + fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip, + type, + clock&0xff, + (clock/0x100)&0xff, + (clock/0x10000)&0xff, + (clock/0x1000000)&0xff); + opl_dbg_maxchip++; + } +#endif + return OPL; +} + +/* ---------- Destroy one of vietual YM3812 ---------- */ +void OPLDestroy(FM_OPL *OPL) +{ +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + fclose(opl_dbg_fp); + opl_dbg_fp = NULL; + } +#endif + OPL_UnLockTable(); + free(OPL); +} + +/* ---------- Option handlers ---------- */ + +void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) +{ + OPL->TimerHandler = TimerHandler; + OPL->TimerParam = channelOffset; +} +void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} +#if BUILD_Y8950 +void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) +{ + OPL->porthandler_w = PortHandler_w; + OPL->porthandler_r = PortHandler_r; + OPL->port_param = param; +} + +void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) +{ + OPL->keyboardhandler_w = KeyboardHandler_w; + OPL->keyboardhandler_r = KeyboardHandler_r; + OPL->keyboard_param = param; +} +#endif +/* ---------- YM3812 I/O interface ---------- */ +int OPLWrite(FM_OPL *OPL,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + OPL->address = v & 0xff; + } + else + { /* data port */ + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + for(opl_dbg_chip=0;opl_dbg_chipaddress,v); + } +#endif + OPLWriteReg(OPL,OPL->address,v); + } + return OPL->status>>7; +} + +unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { /* status port */ + return OPL->status & (OPL->statusmask|0x80); + } + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); + else + LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); + } + return 0; +#if 0 + case 0x0f: /* ADPCM-DATA */ + return 0; +#endif + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); + else + LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); + } + return 0; + case 0x1a: /* PCM-DATA */ + return 0; + } + return 0; +} + +int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + else + { /* Timer A */ + OPL_STATUS_SET(OPL,0x40); + /* CSM mode key,TL controll */ + if( OPL->mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + for(ch=0;ch<9;ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); + return OPL->status>>7; +} diff --git a/plugins/opl2/fmopl.h b/plugins/opl2/fmopl.h new file mode 100644 index 000000000..a01ff902c --- /dev/null +++ b/plugins/opl2/fmopl.h @@ -0,0 +1,174 @@ +#ifndef __FMOPL_H_ +#define __FMOPL_H_ + +/* --- select emulation chips --- */ +#define BUILD_YM3812 (HAS_YM3812) +//#define BUILD_YM3526 (HAS_YM3526) +//#define BUILD_Y8950 (HAS_Y8950) + +/* --- system optimize --- */ +/* select bit size of output : 8 or 16 */ +#define OPL_OUTPUT_BIT 16 + +/* compiler dependence */ +#ifndef OSD_CPU_H +#define OSD_CPU_H +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +#if (OPL_OUTPUT_BIT==16) +typedef INT16 OPLSAMPLE; +#endif +#if (OPL_OUTPUT_BIT==8) +typedef unsigned char OPLSAMPLE; +#endif + + +#if BUILD_Y8950 +#include "ymdeltat.h" +#endif + +typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); +typedef void (*OPL_IRQHANDLER)(int param,int irq); +typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); +typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); +typedef unsigned char (*OPL_PORTHANDLER_R)(int param); + +/* !!!!! here is private section , do not access there member direct !!!!! */ + +#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ +#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ +#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ +#define OPL_TYPE_IO 0x08 /* I/O port */ + +/* Saving is necessary for member of the 'R' mark for suspend/resume */ +/* ---------- OPL one of slot ---------- */ +typedef struct fm_opl_slot { + INT32 TL; /* total level :TL << 8 */ + INT32 TLL; /* adjusted now TL */ + UINT8 KSR; /* key scale rate :(shift down bit) */ + INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */ + INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */ + INT32 SL; /* sustin level :SL_TALBE[SL] */ + INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */ + UINT8 ksl; /* keyscale level :(shift down bits) */ + UINT8 ksr; /* key scale rate :kcode>>KSR */ + UINT32 mul; /* multiple :ML_TABLE[ML] */ + UINT32 Cnt; /* frequency count : */ + UINT32 Incr; /* frequency step : */ + /* envelope generator state */ + UINT8 eg_typ; /* envelope type flag */ + UINT8 evm; /* envelope phase */ + INT32 evc; /* envelope counter */ + INT32 eve; /* envelope counter end point */ + INT32 evs; /* envelope counter step */ + INT32 evsa; /* envelope step for AR :AR[ksr] */ + INT32 evsd; /* envelope step for DR :DR[ksr] */ + INT32 evsr; /* envelope step for RR :RR[ksr] */ + /* LFO */ + UINT8 ams; /* ams flag */ + UINT8 vib; /* vibrate flag */ + /* wave selector */ + INT32 **wavetable; +}OPL_SLOT; + +/* ---------- OPL one of channel ---------- */ +typedef struct fm_opl_channel { + OPL_SLOT SLOT[2]; + UINT8 CON; /* connection type */ + UINT8 FB; /* feed back :(shift down bit) */ + INT32 *connect1; /* slot1 output pointer */ + INT32 *connect2; /* slot2 output pointer */ + INT32 op1_out[2]; /* slot1 output for selfeedback */ + /* phase generator state */ + UINT32 block_fnum; /* block+fnum : */ + UINT8 kcode; /* key code : KeyScaleCode */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 keyon; /* key on/off flag */ +} OPL_CH; + +/* OPL state */ +typedef struct fm_opl_f { + UINT8 type; /* chip type */ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + double TimerBase; /* Timer base time (==sampling time) */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT32 mode; /* Reg.08 : CSM , notesel,etc. */ + /* Timer */ + int T[2]; /* timer counter */ + UINT8 st[2]; /* timer enable */ + /* FM channel slots */ + OPL_CH *P_CH; /* pointer of CH */ + int max_ch; /* maximum channel */ + /* Rythm sention */ + UINT8 rythm; /* Rythm mode , key flag */ +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + YM_DELTAT *deltat; /* DELTA-T ADPCM */ +#endif + /* Keyboard / I/O interface unit (Y8950) */ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + int port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + int keyboard_param; + /* time tables */ + INT32 AR_TABLE[75]; /* atttack rate tables */ + INT32 DR_TABLE[75]; /* decay rate tables */ + UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */ + /* LFO */ + INT32 *ams_table; + INT32 *vib_table; + INT32 amsCnt; + INT32 amsIncr; + INT32 vibCnt; + INT32 vibIncr; + /* wave selector enable flag */ + UINT8 wavesel; + /* external event callback handler */ + OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ + int TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + int IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ + int UpdateParam; /* stream update parameter */ +} FM_OPL; + +/* ---------- Generic interface section ---------- */ +#define OPL_TYPE_YM3526 (0) +#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) +#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) + +FM_OPL *OPLCreate(int type, int clock, int rate); +void OPLDestroy(FM_OPL *OPL); +void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset); +void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param); +void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param); +/* Y8950 port handlers */ +void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param); +void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param); + +void OPLResetChip(FM_OPL *OPL); +int OPLWrite(FM_OPL *OPL,int a,int v); +unsigned char OPLRead(FM_OPL *OPL,int a); +int OPLTimerOver(FM_OPL *OPL,int c); + +/* YM3626/YM3812 local section */ +void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); + +void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); + +#endif diff --git a/plugins/opl2/kemuopl.h b/plugins/opl2/kemuopl.h new file mode 100644 index 000000000..d2ca6e288 --- /dev/null +++ b/plugins/opl2/kemuopl.h @@ -0,0 +1,61 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2005 Simon Peter, , et al. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * kemuopl.h - Emulated OPL using Ken Silverman's emulator, by Simon Peter + * + */ + +#ifndef H_ADPLUG_KEMUOPL +#define H_ADPLUG_KEMUOPL + +#include "opl.h" +extern "C" { +#include "adlibemu.h" +} + +class CKemuopl: public Copl +{ +public: + CKemuopl(int rate, bool bit16, bool usestereo) + : use16bit(bit16), stereo(usestereo) + { + adlibinit(rate, usestereo ? 2 : 1, bit16 ? 2 : 1); + currType = TYPE_OPL2; + }; + + void update(short *buf, int samples) + { + if(use16bit) samples *= 2; + if(stereo) samples *= 2; + adlibgetsample(buf, samples); + } + + // template methods + void write(int reg, int val) + { + if(currChip == 0) + adlib0(reg, val); + }; + + void init() {}; + +private: + bool use16bit,stereo; +}; + +#endif diff --git a/plugins/opl2/logo.png b/plugins/opl2/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..913056fe22bd0dd1bcff8862a35b3b0b9ef55e6f GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDB3?!H8JlO)I7>k44ofy`glX(f`hz9tCxaJq- zGSoBt|Ig4=&v533p^r= zfz(kDW^8Xc@&zc!UgGKN%6^wafR){>MYm!XP^iSy#WBR<^xi8Mc@HRXxCVyp(B8nL zy@N@+anL&2>ItN$nY4g1L?Z>y~JFn6t VkG|*?KM%B@!PC{xWt~$(696MLW}^TA literal 0 HcmV?d00001 diff --git a/plugins/opl2/mididata.h b/plugins/opl2/mididata.h new file mode 100644 index 000000000..2a83cd997 --- /dev/null +++ b/plugins/opl2/mididata.h @@ -0,0 +1,174 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999, 2000, 2001 Simon Peter, , et al. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * FM instrument definitions below borrowed from the Allegro library by + * Phil Hassey, - see "adplug/players/mid.cpp" + * for further acknowledgements. + */ + +unsigned char midi_fm_instruments[128][14] = +{ + + /* This set of GM instrument patches was provided by Jorrit Rouwe... + */ + + { 0x21, 0x21, 0x8f, 0x0c, 0xf2, 0xf2, 0x45, 0x76, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Acoustic Grand */ + { 0x31, 0x21, 0x4b, 0x09, 0xf2, 0xf2, 0x54, 0x56, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Bright Acoustic */ + { 0x31, 0x21, 0x49, 0x09, 0xf2, 0xf2, 0x55, 0x76, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Electric Grand */ + { 0xb1, 0x61, 0x0e, 0x09, 0xf2, 0xf3, 0x3b, 0x0b, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Honky-Tonk */ + { 0x01, 0x21, 0x57, 0x09, 0xf1, 0xf1, 0x38, 0x28, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Piano 1 */ + { 0x01, 0x21, 0x93, 0x09, 0xf1, 0xf1, 0x38, 0x28, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Piano 2 */ + { 0x21, 0x36, 0x80, 0x17, 0xa2, 0xf1, 0x01, 0xd5, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Harpsichord */ + { 0x01, 0x01, 0x92, 0x09, 0xc2, 0xc2, 0xa8, 0x58, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Clav */ + { 0x0c, 0x81, 0x5c, 0x09, 0xf6, 0xf3, 0x54, 0xb5, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Celesta */ + { 0x07, 0x11, 0x97, 0x89, 0xf6, 0xf5, 0x32, 0x11, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Glockenspiel */ + { 0x17, 0x01, 0x21, 0x09, 0x56, 0xf6, 0x04, 0x04, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Music Box */ + { 0x18, 0x81, 0x62, 0x09, 0xf3, 0xf2, 0xe6, 0xf6, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Vibraphone */ + { 0x18, 0x21, 0x23, 0x09, 0xf7, 0xe5, 0x55, 0xd8, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Marimba */ + { 0x15, 0x01, 0x91, 0x09, 0xf6, 0xf6, 0xa6, 0xe6, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Xylophone */ + { 0x45, 0x81, 0x59, 0x89, 0xd3, 0xa3, 0x82, 0xe3, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Tubular Bells */ + { 0x03, 0x81, 0x49, 0x89, 0x74, 0xb3, 0x55, 0x05, 0x01, 0x00, 0x04, 0, 0, 0 }, /* Dulcimer */ + { 0x71, 0x31, 0x92, 0x09, 0xf6, 0xf1, 0x14, 0x07, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Drawbar Organ */ + { 0x72, 0x30, 0x14, 0x09, 0xc7, 0xc7, 0x58, 0x08, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Percussive Organ */ + { 0x70, 0xb1, 0x44, 0x09, 0xaa, 0x8a, 0x18, 0x08, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Rock Organ */ + { 0x23, 0xb1, 0x93, 0x09, 0x97, 0x55, 0x23, 0x14, 0x01, 0x00, 0x04, 0, 0, 0 }, /* Church Organ */ + { 0x61, 0xb1, 0x13, 0x89, 0x97, 0x55, 0x04, 0x04, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Reed Organ */ + { 0x24, 0xb1, 0x48, 0x09, 0x98, 0x46, 0x2a, 0x1a, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Accoridan */ + { 0x61, 0x21, 0x13, 0x09, 0x91, 0x61, 0x06, 0x07, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Harmonica */ + { 0x21, 0xa1, 0x13, 0x92, 0x71, 0x61, 0x06, 0x07, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Tango Accordian */ + { 0x02, 0x41, 0x9c, 0x89, 0xf3, 0xf3, 0x94, 0xc8, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Acoustic Guitar(nylon) */ + { 0x03, 0x11, 0x54, 0x09, 0xf3, 0xf1, 0x9a, 0xe7, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Acoustic Guitar(steel) */ + { 0x23, 0x21, 0x5f, 0x09, 0xf1, 0xf2, 0x3a, 0xf8, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Guitar(jazz) */ + { 0x03, 0x21, 0x87, 0x89, 0xf6, 0xf3, 0x22, 0xf8, 0x01, 0x00, 0x06, 0, 0, 0 }, /* Electric Guitar(clean) */ + { 0x03, 0x21, 0x47, 0x09, 0xf9, 0xf6, 0x54, 0x3a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Guitar(muted) */ + { 0x23, 0x21, 0x4a, 0x0e, 0x91, 0x84, 0x41, 0x19, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Overdriven Guitar */ + { 0x23, 0x21, 0x4a, 0x09, 0x95, 0x94, 0x19, 0x19, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Distortion Guitar */ + { 0x09, 0x84, 0xa1, 0x89, 0x20, 0xd1, 0x4f, 0xf8, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Guitar Harmonics */ + { 0x21, 0xa2, 0x1e, 0x09, 0x94, 0xc3, 0x06, 0xa6, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Acoustic Bass */ + { 0x31, 0x31, 0x12, 0x09, 0xf1, 0xf1, 0x28, 0x18, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Electric Bass(finger) */ + { 0x31, 0x31, 0x8d, 0x09, 0xf1, 0xf1, 0xe8, 0x78, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Electric Bass(pick) */ + { 0x31, 0x32, 0x5b, 0x09, 0x51, 0x71, 0x28, 0x48, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Fretless Bass */ + { 0x01, 0x21, 0x8b, 0x49, 0xa1, 0xf2, 0x9a, 0xdf, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Slap Bass 1 */ + { 0x21, 0x21, 0x8b, 0x11, 0xa2, 0xa1, 0x16, 0xdf, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Slap Bass 2 */ + { 0x31, 0x31, 0x8b, 0x09, 0xf4, 0xf1, 0xe8, 0x78, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Synth Bass 1 */ + { 0x31, 0x31, 0x12, 0x09, 0xf1, 0xf1, 0x28, 0x18, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Synth Bass 2 */ + { 0x31, 0x21, 0x15, 0x09, 0xdd, 0x56, 0x13, 0x26, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Violin */ + { 0x31, 0x21, 0x16, 0x09, 0xdd, 0x66, 0x13, 0x06, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Viola */ + { 0x71, 0x31, 0x49, 0x09, 0xd1, 0x61, 0x1c, 0x0c, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Cello */ + { 0x21, 0x23, 0x4d, 0x89, 0x71, 0x72, 0x12, 0x06, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Contrabass */ + { 0xf1, 0xe1, 0x40, 0x09, 0xf1, 0x6f, 0x21, 0x16, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Tremolo Strings */ + { 0x02, 0x01, 0x1a, 0x89, 0xf5, 0x85, 0x75, 0x35, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Pizzicato Strings */ + { 0x02, 0x01, 0x1d, 0x89, 0xf5, 0xf3, 0x75, 0xf4, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Orchestral Strings */ + { 0x10, 0x11, 0x41, 0x09, 0xf5, 0xf2, 0x05, 0xc3, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Timpani */ + { 0x21, 0xa2, 0x9b, 0x0a, 0xb1, 0x72, 0x25, 0x08, 0x01, 0x00, 0x0e, 0, 0, 0 }, /* String Ensemble 1 */ + { 0xa1, 0x21, 0x98, 0x09, 0x7f, 0x3f, 0x03, 0x07, 0x01, 0x01, 0x00, 0, 0, 0 }, /* String Ensemble 2 */ + { 0xa1, 0x61, 0x93, 0x09, 0xc1, 0x4f, 0x12, 0x05, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* SynthStrings 1 */ + { 0x21, 0x61, 0x18, 0x09, 0xc1, 0x4f, 0x22, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* SynthStrings 2 */ + { 0x31, 0x72, 0x5b, 0x8c, 0xf4, 0x8a, 0x15, 0x05, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Choir Aahs */ + { 0xa1, 0x61, 0x90, 0x09, 0x74, 0x71, 0x39, 0x67, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Voice Oohs */ + { 0x71, 0x72, 0x57, 0x09, 0x54, 0x7a, 0x05, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Synth Voice */ + { 0x90, 0x41, 0x00, 0x09, 0x54, 0xa5, 0x63, 0x45, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Orchestra Hit */ + { 0x21, 0x21, 0x92, 0x0a, 0x85, 0x8f, 0x17, 0x09, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Trumpet */ + { 0x21, 0x21, 0x94, 0x0e, 0x75, 0x8f, 0x17, 0x09, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Trombone */ + { 0x21, 0x61, 0x94, 0x09, 0x76, 0x82, 0x15, 0x37, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Tuba */ + { 0x31, 0x21, 0x43, 0x09, 0x9e, 0x62, 0x17, 0x2c, 0x01, 0x01, 0x02, 0, 0, 0 }, /* Muted Trumpet */ + { 0x21, 0x21, 0x9b, 0x09, 0x61, 0x7f, 0x6a, 0x0a, 0x00, 0x00, 0x02, 0, 0, 0 }, /* French Horn */ + { 0x61, 0x22, 0x8a, 0x0f, 0x75, 0x74, 0x1f, 0x0f, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Brass Section */ + { 0xa1, 0x21, 0x86, 0x8c, 0x72, 0x71, 0x55, 0x18, 0x01, 0x00, 0x00, 0, 0, 0 }, /* SynthBrass 1 */ + { 0x21, 0x21, 0x4d, 0x09, 0x54, 0xa6, 0x3c, 0x1c, 0x00, 0x00, 0x08, 0, 0, 0 }, /* SynthBrass 2 */ + { 0x31, 0x61, 0x8f, 0x09, 0x93, 0x72, 0x02, 0x0b, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Soprano Sax */ + { 0x31, 0x61, 0x8e, 0x09, 0x93, 0x72, 0x03, 0x09, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Alto Sax */ + { 0x31, 0x61, 0x91, 0x09, 0x93, 0x82, 0x03, 0x09, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Tenor Sax */ + { 0x31, 0x61, 0x8e, 0x09, 0x93, 0x72, 0x0f, 0x0f, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Baritone Sax */ + { 0x21, 0x21, 0x4b, 0x09, 0xaa, 0x8f, 0x16, 0x0a, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Oboe */ + { 0x31, 0x21, 0x90, 0x09, 0x7e, 0x8b, 0x17, 0x0c, 0x01, 0x01, 0x06, 0, 0, 0 }, /* English Horn */ + { 0x31, 0x32, 0x81, 0x09, 0x75, 0x61, 0x19, 0x19, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Bassoon */ + { 0x32, 0x21, 0x90, 0x09, 0x9b, 0x72, 0x21, 0x17, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Clarinet */ + { 0xe1, 0xe1, 0x1f, 0x09, 0x85, 0x65, 0x5f, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Piccolo */ + { 0xe1, 0xe1, 0x46, 0x09, 0x88, 0x65, 0x5f, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Flute */ + { 0xa1, 0x21, 0x9c, 0x09, 0x75, 0x75, 0x1f, 0x0a, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Recorder */ + { 0x31, 0x21, 0x8b, 0x09, 0x84, 0x65, 0x58, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Pan Flute */ + { 0xe1, 0xa1, 0x4c, 0x09, 0x66, 0x65, 0x56, 0x26, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Blown Bottle */ + { 0x62, 0xa1, 0xcb, 0x09, 0x76, 0x55, 0x46, 0x36, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Skakuhachi */ + { 0x62, 0xa1, 0xa2, 0x09, 0x57, 0x56, 0x07, 0x07, 0x00, 0x00, 0x0b, 0, 0, 0 }, /* Whistle */ + { 0x62, 0xa1, 0x9c, 0x09, 0x77, 0x76, 0x07, 0x07, 0x00, 0x00, 0x0b, 0, 0, 0 }, /* Ocarina */ + { 0x22, 0x21, 0x59, 0x09, 0xff, 0xff, 0x03, 0x0f, 0x02, 0x00, 0x00, 0, 0, 0 }, /* Lead 1 (square) */ + { 0x21, 0x21, 0x0e, 0x09, 0xff, 0xff, 0x0f, 0x0f, 0x01, 0x01, 0x00, 0, 0, 0 }, /* Lead 2 (sawtooth) */ + { 0x22, 0x21, 0x46, 0x89, 0x86, 0x64, 0x55, 0x18, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Lead 3 (calliope) */ + { 0x21, 0xa1, 0x45, 0x09, 0x66, 0x96, 0x12, 0x0a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Lead 4 (chiff) */ + { 0x21, 0x22, 0x8b, 0x09, 0x92, 0x91, 0x2a, 0x2a, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Lead 5 (charang) */ + { 0xa2, 0x61, 0x9e, 0x49, 0xdf, 0x6f, 0x05, 0x07, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Lead 6 (voice) */ + { 0x20, 0x60, 0x1a, 0x09, 0xef, 0x8f, 0x01, 0x06, 0x00, 0x02, 0x00, 0, 0, 0 }, /* Lead 7 (fifths) */ + { 0x21, 0x21, 0x8f, 0x86, 0xf1, 0xf4, 0x29, 0x09, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Lead 8 (bass+lead) */ + { 0x77, 0xa1, 0xa5, 0x09, 0x53, 0xa0, 0x94, 0x05, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Pad 1 (new age) */ + { 0x61, 0xb1, 0x1f, 0x89, 0xa8, 0x25, 0x11, 0x03, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Pad 2 (warm) */ + { 0x61, 0x61, 0x17, 0x09, 0x91, 0x55, 0x34, 0x16, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Pad 3 (polysynth) */ + { 0x71, 0x72, 0x5d, 0x09, 0x54, 0x6a, 0x01, 0x03, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Pad 4 (choir) */ + { 0x21, 0xa2, 0x97, 0x09, 0x21, 0x42, 0x43, 0x35, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Pad 5 (bowed) */ + { 0xa1, 0x21, 0x1c, 0x09, 0xa1, 0x31, 0x77, 0x47, 0x01, 0x01, 0x00, 0, 0, 0 }, /* Pad 6 (metallic) */ + { 0x21, 0x61, 0x89, 0x0c, 0x11, 0x42, 0x33, 0x25, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Pad 7 (halo) */ + { 0xa1, 0x21, 0x15, 0x09, 0x11, 0xcf, 0x47, 0x07, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Pad 8 (sweep) */ + { 0x3a, 0x51, 0xce, 0x09, 0xf8, 0x86, 0xf6, 0x02, 0x00, 0x00, 0x02, 0, 0, 0 }, /* FX 1 (rain) */ + { 0x21, 0x21, 0x15, 0x09, 0x21, 0x41, 0x23, 0x13, 0x01, 0x00, 0x00, 0, 0, 0 }, /* FX 2 (soundtrack) */ + { 0x06, 0x01, 0x5b, 0x09, 0x74, 0xa5, 0x95, 0x72, 0x00, 0x00, 0x00, 0, 0, 0 }, /* FX 3 (crystal) */ + { 0x22, 0x61, 0x92, 0x8c, 0xb1, 0xf2, 0x81, 0x26, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* FX 4 (atmosphere) */ + { 0x41, 0x42, 0x4d, 0x09, 0xf1, 0xf2, 0x51, 0xf5, 0x01, 0x00, 0x00, 0, 0, 0 }, /* FX 5 (brightness) */ + { 0x61, 0xa3, 0x94, 0x89, 0x11, 0x11, 0x51, 0x13, 0x01, 0x00, 0x06, 0, 0, 0 }, /* FX 6 (goblins) */ + { 0x61, 0xa1, 0x8c, 0x89, 0x11, 0x1d, 0x31, 0x03, 0x00, 0x00, 0x06, 0, 0, 0 }, /* FX 7 (echoes) */ + { 0xa4, 0x61, 0x4c, 0x09, 0xf3, 0x81, 0x73, 0x23, 0x01, 0x00, 0x04, 0, 0, 0 }, /* FX 8 (sci-fi) */ + { 0x02, 0x07, 0x85, 0x0c, 0xd2, 0xf2, 0x53, 0xf6, 0x00, 0x01, 0x00, 0, 0, 0 }, /* Sitar */ + { 0x11, 0x13, 0x0c, 0x89, 0xa3, 0xa2, 0x11, 0xe5, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Banjo */ + { 0x11, 0x11, 0x06, 0x09, 0xf6, 0xf2, 0x41, 0xe6, 0x01, 0x02, 0x04, 0, 0, 0 }, /* Shamisen */ + { 0x93, 0x91, 0x91, 0x09, 0xd4, 0xeb, 0x32, 0x11, 0x00, 0x01, 0x08, 0, 0, 0 }, /* Koto */ + { 0x04, 0x01, 0x4f, 0x09, 0xfa, 0xc2, 0x56, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Kalimba */ + { 0x21, 0x22, 0x49, 0x09, 0x7c, 0x6f, 0x20, 0x0c, 0x00, 0x01, 0x06, 0, 0, 0 }, /* Bagpipe */ + { 0x31, 0x21, 0x85, 0x09, 0xdd, 0x56, 0x33, 0x16, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Fiddle */ + { 0x20, 0x21, 0x04, 0x8a, 0xda, 0x8f, 0x05, 0x0b, 0x02, 0x00, 0x06, 0, 0, 0 }, /* Shanai */ + { 0x05, 0x03, 0x6a, 0x89, 0xf1, 0xc3, 0xe5, 0xe5, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Tinkle Bell */ + { 0x07, 0x02, 0x15, 0x09, 0xec, 0xf8, 0x26, 0x16, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Agogo */ + { 0x05, 0x01, 0x9d, 0x09, 0x67, 0xdf, 0x35, 0x05, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Steel Drums */ + { 0x18, 0x12, 0x96, 0x09, 0xfa, 0xf8, 0x28, 0xe5, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Woodblock */ + { 0x10, 0x00, 0x86, 0x0c, 0xa8, 0xfa, 0x07, 0x03, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Taiko Drum */ + { 0x11, 0x10, 0x41, 0x0c, 0xf8, 0xf3, 0x47, 0x03, 0x02, 0x00, 0x04, 0, 0, 0 }, /* Melodic Tom */ + { 0x01, 0x10, 0x8e, 0x09, 0xf1, 0xf3, 0x06, 0x02, 0x02, 0x00, 0x0e, 0, 0, 0 }, /* Synth Drum */ + { 0x0e, 0xc0, 0x00, 0x09, 0x1f, 0x1f, 0x00, 0xff, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Reverse Cymbal */ + { 0x06, 0x03, 0x80, 0x91, 0xf8, 0x56, 0x24, 0x84, 0x00, 0x02, 0x0e, 0, 0, 0 }, /* Guitar Fret Noise */ + { 0x0e, 0xd0, 0x00, 0x0e, 0xf8, 0x34, 0x00, 0x04, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Breath Noise */ + { 0x0e, 0xc0, 0x00, 0x09, 0xf6, 0x1f, 0x00, 0x02, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Seashore */ + { 0xd5, 0xda, 0x95, 0x49, 0x37, 0x56, 0xa3, 0x37, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Bird Tweet */ + { 0x35, 0x14, 0x5c, 0x11, 0xb2, 0xf4, 0x61, 0x15, 0x02, 0x00, 0x0a, 0, 0, 0 }, /* Telephone ring */ + { 0x0e, 0xd0, 0x00, 0x09, 0xf6, 0x4f, 0x00, 0xf5, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Helicopter */ + { 0x26, 0xe4, 0x00, 0x09, 0xff, 0x12, 0x01, 0x16, 0x00, 0x01, 0x0e, 0, 0, 0 }, /* Applause */ + { 0x00, 0x00, 0x00, 0x09, 0xf3, 0xf6, 0xf0, 0xc9, 0x00, 0x02, 0x0e, 0, 0, 0 } /* Gunshot */ + +}; + +/* logarithmic relationship between midi and FM volumes */ +static int my_midi_fm_vol_table[128] = { + 0, 11, 16, 19, 22, 25, 27, 29, 32, 33, 35, 37, 39, 40, 42, 43, + 45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, + 78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89, 89, + 90, 91, 91, 92, 93, 93, 94, 95, 96, 96, 97, 97, 98, 99, 99, 100, + 101, 101, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108, + 109, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115, + 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, + 123, 123, 124, 124, 125, 125, 126, 126, 127 +}; + diff --git a/plugins/opl2/opl.h b/plugins/opl2/opl.h new file mode 100644 index 000000000..401bcb982 --- /dev/null +++ b/plugins/opl2/opl.h @@ -0,0 +1,69 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2007 Simon Peter, , et al. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * opl.h - OPL base class, by Simon Peter + */ + +#ifndef H_ADPLUG_OPL +#define H_ADPLUG_OPL + +class Copl +{ + public: + typedef enum { + TYPE_OPL2, TYPE_OPL3, TYPE_DUAL_OPL2 + } ChipType; + + Copl() + : currChip(0), currType(TYPE_OPL2) + { + } + + virtual ~Copl() + { + } + + virtual void write(int reg, int val) = 0; // combined register select + data write + virtual void setchip(int n) // select OPL chip + { + if(n < 2) + currChip = n; + } + + virtual int getchip() // returns current OPL chip + { + return currChip; + } + + virtual void init(void) = 0; // reinitialize OPL chip(s) + + // return this OPL chip's type + ChipType gettype() + { + return currType; + } + + // Emulation only: fill buffer + virtual void update(short *buf, int samples) {} + + protected: + int currChip; // currently selected OPL chip number + ChipType currType; // this OPL chip's type +}; + +#endif diff --git a/plugins/opl2/opl2_led_off.png b/plugins/opl2/opl2_led_off.png new file mode 100644 index 0000000000000000000000000000000000000000..7c6abb05357b3bcb62bdfc025d6196d4d80c80e9 GIT binary patch literal 586 zcmV-Q0=4~#P)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00FW|L_t(I%cYdPY8ycmg}<2{ zt*mB|io`AgLQx}x;?99pk>qjg7s(^I$!nyHilp8m#=!wapcpnN7})F|9K#n_|PQBOb;heh*YgsspTUe}fOsCUnp64Hc-+*0xjce zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00IF?L_t(I%cYb}Yg0iKhMzO{ z=Ht2u$wDh4l$wR1#7Kn-Hw*RWw132((2ak?rCI2z$Q5iC72={6u0%@GMbNf4^Ko3< zn^-VV!GXiT9Ojw#ymMv*U~6kD23kN35N;m}V19af>ZIEI5O@XL1)^Ivd*B>+59G^} zUjn@}P4~OqZYxO=6omjm71clp0oB0C$(MPSWe0!)Z)2bi+)LARzu)h-Mxznq@tC40 z5Gku!&fDAD42Q!Ou$N`oYoHcavZ6=bZtLA>#Np#l$iP5NkVr~L6!6MNdxSYO44w?y zS(ZhBECD3VCSS*6762vMhTIK-j-5LcNO2bUGT2~}7P#5$PaEeBPh~VrW zfLUFxFBRxYQW@$MQ3VC5lGfTaB~*1u0BjYP0WpGlEql+GgqsRh0I!}#qrp$>;2ID` zoq*A@_XJ~}!G=w7eaYxnzooO5MZ%feaQ!eX6c zI-O4QJbwfH0PM}z_yXAY$JaOkJ^ + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +// TODO: +// - Pitch bend +// - Velocity (and aftertouch) sensitivity +// - in FM mode: OP2 level, add mode: OP1 and OP2 levels +// - .sbi (or similar) file loading into models +// - Extras: +// - double release: first release is in effect until noteoff (heard if percussive sound), +// second is switched in just before key bit cleared (is this useful???) +// - Unison: 2,3,4, or 9 voices with configurable spread? +// - Portamento (needs mono mode?) +// - Pre-bend/post-bend in poly mode could use portamento speed? +// - SBI file import? + +// - Envelope times in ms for UI: t[0] = 0, t[n] = ( 1< + +#include "opl.h" +#include "temuopl.h" +#include "kemuopl.h" + +#include "embed.cpp" +#include "math.h" + +#include "knob.h" +#include "lcd_spinbox.h" +#include "pixmap_button.h" +#include "tooltip.h" + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT OPL2_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "OpulenZ", + QT_TRANSLATE_NOOP( "pluginBrowser", + "2-operator FM Synth" ), + "Raine M. Ekman ", + 0x0100, + Plugin::Instrument, + new PluginPixmapLoader( "logo" ), + NULL, + NULL +}; + +// necessary for getting instance out of shared lib +Plugin * PLUGIN_EXPORT lmms_plugin_main( Model *, void * _data ) +{ + return( new opl2instrument( static_cast( _data ) ) ); +} + +} + +// I'd much rather do without a mutex, but it looks like +// the emulator code isn't really ready for threads +QMutex opl2instrument::emulatorMutex; + +opl2instrument::opl2instrument( InstrumentTrack * _instrument_track ) : + Instrument( _instrument_track, &OPL2_plugin_descriptor ), + m_patchModel( 0, 0, 127, this, tr( "Patch" ) ), + op1_a_mdl(14.0, 0.0, 15.0, 1.0, this, tr( "Op 1 Attack" ) ), + op1_d_mdl(14.0, 0.0, 15.0, 1.0, this, tr( "Op 1 Decay" ) ), + op1_s_mdl(3.0, 0.0, 15.0, 1.0, this, tr( "Op 1 Sustain" ) ), + op1_r_mdl(10.0, 0.0, 15.0, 1.0, this, tr( "Op 1 Release" ) ), + op1_lvl_mdl(62.0, 0.0, 63.0, 1.0, this, tr( "Op 1 Level" ) ), + op1_scale_mdl(0.0, 0.0, 3.0, 1.0, this, tr( "Op 1 Level Scaling" ) ), + op1_mul_mdl(0.0, 0.0, 15.0, 1.0, this, tr( "Op 1 Frequency Multiple" ) ), + feedback_mdl(0.0, 0.0, 7.0, 1.0, this, tr( "Op 1 Feedback" ) ), + op1_ksr_mdl(false, this, tr( "Op 1 Key Scaling Rate" ) ), + op1_perc_mdl(false, this, tr( "Op 1 Percussive Envelope" ) ), + op1_trem_mdl(true, this, tr( "Op 1 Tremolo" ) ), + op1_vib_mdl(false, this, tr( "Op 1 Vibrato" ) ), + op1_w0_mdl( ), + op1_w1_mdl( ), + op1_w2_mdl( ), + op1_w3_mdl( ), + op1_waveform_mdl(0,0,3,this, tr( "Op 1 Waveform" ) ), + + + op2_a_mdl(1.0, 0.0, 15.0, 1.0, this, tr( "Op 2 Attack" ) ), + op2_d_mdl(3.0, 0.0, 15.0, 1.0, this, tr( "Op 2 Decay" ) ), + op2_s_mdl(14.0, 0.0, 15.0, 1.0, this, tr( "Op 2 Sustain" ) ), + op2_r_mdl(12.0, 0.0, 15.0, 1.0, this, tr( "Op 2 Release" ) ), + op2_lvl_mdl(63.0, 0.0, 63.0, 1.0, this, tr( "Op 2 Level" ) ), + op2_scale_mdl(0.0, 0.0, 3.0, 1.0, this, tr( "Op 2 Level Scaling" ) ), + op2_mul_mdl(1.0, 0.0, 15.0, 1.0, this, tr( "Op 2 Frequency Multiple" ) ), + op2_ksr_mdl(false, this, tr( "Op 2 Key Scaling Rate" ) ), + op2_perc_mdl(false, this, tr( "Op 2 Percussive Envelope" ) ), + op2_trem_mdl(false, this, tr( "Op 2 Tremolo" ) ), + op2_vib_mdl(true, this, tr( "Op 2 Vibrato" ) ), + op2_w0_mdl( ), + op2_w1_mdl( ), + op2_w2_mdl( ), + op2_w3_mdl( ), + op2_waveform_mdl(0,0,3,this, tr( "Op 2 Waveform" ) ), + + fm_mdl(true, this, tr( "FM" ) ), + vib_depth_mdl(false, this, tr( "Vibrato Depth" ) ), + trem_depth_mdl(false, this, tr( "Tremolo Depth" ) ) +{ + unsigned char defaultPreset[] = + {0xa0, 0x61, 0x01, 0x00, 0x11, 0xec, 0xc5, + 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + + // Connect the plugin to the mixer... + InstrumentPlayHandle * iph = new InstrumentPlayHandle( this ); + engine::getMixer()->addPlayHandle( iph ); + + // Create an emulator - samplerate, 16 bit, mono + // CTemuopl is the better one, CKemuopl kinda sucks (some sounds silent, pitch goes flat after a while) + emulatorMutex.lock(); + // theEmulator = new CKemuopl(engine::getMixer()->processingSampleRate(), true, false); + theEmulator = new CTemuopl(engine::getMixer()->processingSampleRate(), true, false); + theEmulator->init(); + // Enable waveform selection + theEmulator->write(0x01,0x20); + emulatorMutex.unlock(); + + //loadPatch(midi_fm_instruments[0]); + // loadPatch(defaultPreset); + updatePatch(); + + // Can the buffer size change suddenly? I bet that would break lots of stuff + frameCount = engine::getMixer()->framesPerPeriod(); + renderbuffer = new short[frameCount]; + + // Some kind of sane default + tuneEqual(69, 440); + + for(int i=1; i<9; ++i) { + voiceNote[i] = OPL2_VOICE_FREE; + } + connect( engine::getMixer(), SIGNAL( sampleRateChanged() ), + this, SLOT( reloadEmulator() ) ); + // Connect knobs + // This one's for testing... + connect( &m_patchModel, SIGNAL( dataChanged() ), this, SLOT( loadGMPatch() ) ); +#define MOD_CON( model ) connect( &model, SIGNAL( dataChanged() ), this, SLOT( updatePatch() ) ); + MOD_CON( op1_a_mdl ); + MOD_CON( op1_d_mdl ); + MOD_CON( op1_s_mdl ); + MOD_CON( op1_r_mdl ); + MOD_CON( op1_lvl_mdl ); + MOD_CON( op1_scale_mdl ); + MOD_CON( op1_mul_mdl ); + MOD_CON( feedback_mdl ); + MOD_CON( op1_ksr_mdl ); + MOD_CON( op1_perc_mdl ); + MOD_CON( op1_trem_mdl ); + MOD_CON( op1_vib_mdl ); + MOD_CON( op1_w0_mdl ); + MOD_CON( op1_w1_mdl ); + MOD_CON( op1_w2_mdl ); + MOD_CON( op1_w3_mdl ); + MOD_CON( op1_waveform_mdl ); + + MOD_CON( op2_a_mdl ); + MOD_CON( op2_d_mdl ); + MOD_CON( op2_s_mdl ); + MOD_CON( op2_r_mdl ); + MOD_CON( op2_lvl_mdl ); + MOD_CON( op2_scale_mdl ); + MOD_CON( op2_mul_mdl ); + MOD_CON( op2_ksr_mdl ); + MOD_CON( op2_perc_mdl ); + MOD_CON( op2_trem_mdl ); + MOD_CON( op2_vib_mdl ); + MOD_CON( op2_w0_mdl ); + MOD_CON( op2_w1_mdl ); + MOD_CON( op2_w2_mdl ); + MOD_CON( op2_w3_mdl ); + MOD_CON( op2_waveform_mdl ); + + MOD_CON( fm_mdl ); + MOD_CON( vib_depth_mdl ); + MOD_CON( trem_depth_mdl ); +} + +// Samplerate changes when choosing oversampling, so this is more or less mandatory +void opl2instrument::reloadEmulator() { + emulatorMutex.lock(); + theEmulator = new CTemuopl(engine::getMixer()->processingSampleRate(), true, false); + theEmulator->init(); + theEmulator->write(0x01,0x20); + emulatorMutex.unlock(); + for(int i=1; i<9; ++i) { + voiceNote[i] = OPL2_VOICE_FREE; + } + // updatePatch(); +} + +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; + static int lastvoice=0; + if( _me.m_type == MidiNoteOn && !isMuted() ) { + // to get us in line with MIDI + key = _me.key() +12; + for(int i=lastvoice+1; i!=lastvoice; ++i,i%=9) { + if( voiceNote[i] == OPL2_VOICE_FREE ) { + theEmulator->write(0xA0+i, fnums[key] & 0xff); + theEmulator->write(0xB0+i, 32 + ((fnums[key] & 0x1f00) >> 8) ); + // printf("%d: %d %d\n", key, (fnums[key] & 0x1c00) >> 10, fnums[key] & 0x3ff); + voiceNote[i] = key; + // printf("Voice %d on\n",i); + lastvoice=i; + break; + } + } + } else if( _me.m_type == MidiNoteOff ) { + key = _me.key() +12; + for(int i=0; i<9; ++i) { + if( voiceNote[i] == key ) { + theEmulator->write(0xA0+i, fnums[key] & 0xff); + theEmulator->write(0xB0+i, (fnums[key] & 0x1f00) >> 8 ); + voiceNote[i] = OPL2_VOICE_FREE; + } + } + } else { + printf("Midi event type %d\n",_me.m_type); + // 224 - pitch wheel + // 160 - aftertouch? + } + emulatorMutex.unlock(); + return true; +} + +QString opl2instrument::nodeName() const +{ + return( OPL2_plugin_descriptor.name ); +} + +PluginView * opl2instrument::instantiateView( QWidget * _parent ) +{ + return( new opl2instrumentView( this, _parent ) ); +} + + +void opl2instrument::play( sampleFrame * _working_buffer ) +{ + emulatorMutex.lock(); + theEmulator->update(renderbuffer, frameCount); + + for( fpp_t frame = 0; frame < frameCount; ++frame ) + { + sample_t s = float(renderbuffer[frame])/32768.0; + for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch ) + { + _working_buffer[frame][ch] = s; + } + } + emulatorMutex.unlock(); + + // Throw the data to the track... + instrumentTrack()->processAudioBuffer( _working_buffer, frameCount, NULL ); + +} + + +void opl2instrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + op1_a_mdl.saveSettings( _doc, _this, "op1_a" ); + op1_d_mdl.saveSettings( _doc, _this, "op1_d" ); + op1_s_mdl.saveSettings( _doc, _this, "op1_s" ); + op1_r_mdl.saveSettings( _doc, _this, "op1_r" ); + op1_lvl_mdl.saveSettings( _doc, _this, "op1_lvl" ); + op1_scale_mdl.saveSettings( _doc, _this, "op1_scale" ); + op1_mul_mdl.saveSettings( _doc, _this, "op1_mul" ); + feedback_mdl.saveSettings( _doc, _this, "feedback" ); + op1_ksr_mdl.saveSettings( _doc, _this, "op1_ksr" ); + op1_perc_mdl.saveSettings( _doc, _this, "op1_perc" ); + op1_trem_mdl.saveSettings( _doc, _this, "op1_trem" ); + op1_vib_mdl.saveSettings( _doc, _this, "op1_vib" ); + op1_waveform_mdl.saveSettings( _doc, _this, "op1_waveform" ); + + op2_a_mdl.saveSettings( _doc, _this, "op2_a" ); + op2_d_mdl.saveSettings( _doc, _this, "op2_d" ); + op2_s_mdl.saveSettings( _doc, _this, "op2_s" ); + op2_r_mdl.saveSettings( _doc, _this, "op2_r" ); + op2_lvl_mdl.saveSettings( _doc, _this, "op2_lvl" ); + op2_scale_mdl.saveSettings( _doc, _this, "op2_scale" ); + op2_mul_mdl.saveSettings( _doc, _this, "op2_mul" ); + op2_ksr_mdl.saveSettings( _doc, _this, "op2_ksr" ); + op2_perc_mdl.saveSettings( _doc, _this, "op2_perc" ); + op2_trem_mdl.saveSettings( _doc, _this, "op2_trem" ); + op2_vib_mdl.saveSettings( _doc, _this, "op2_vib" ); + op2_waveform_mdl.saveSettings( _doc, _this, "op2_waveform" ); + + fm_mdl.saveSettings( _doc, _this, "fm" ); + vib_depth_mdl.saveSettings( _doc, _this, "vib_depth" ); + trem_depth_mdl.saveSettings( _doc, _this, "trem_depth" ); +} + +void opl2instrument::loadSettings( const QDomElement & _this ) +{ + printf("loadSettings!\n"); + op1_a_mdl.loadSettings( _this, "op1_a" ); + op1_d_mdl.loadSettings( _this, "op1_d" ); + op1_s_mdl.loadSettings( _this, "op1_s" ); + op1_r_mdl.loadSettings( _this, "op1_r" ); + op1_lvl_mdl.loadSettings( _this, "op1_lvl" ); + op1_scale_mdl.loadSettings( _this, "op1_scale" ); + op1_mul_mdl.loadSettings( _this, "op1_mul" ); + feedback_mdl.loadSettings( _this, "feedback" ); + op1_ksr_mdl.loadSettings( _this, "op1_ksr" ); + op1_perc_mdl.loadSettings( _this, "op1_perc" ); + op1_trem_mdl.loadSettings( _this, "op1_trem" ); + op1_vib_mdl.loadSettings( _this, "op1_vib" ); + op1_waveform_mdl.loadSettings( _this, "op1_waveform" ); + + op2_a_mdl.loadSettings( _this, "op2_a" ); + op2_d_mdl.loadSettings( _this, "op2_d" ); + op2_s_mdl.loadSettings( _this, "op2_s" ); + op2_r_mdl.loadSettings( _this, "op2_r" ); + op2_lvl_mdl.loadSettings( _this, "op2_lvl" ); + op2_scale_mdl.loadSettings( _this, "op2_scale" ); + op2_mul_mdl.loadSettings( _this, "op2_mul" ); + op2_ksr_mdl.loadSettings( _this, "op2_ksr" ); + op2_perc_mdl.loadSettings( _this, "op2_perc" ); + op2_trem_mdl.loadSettings( _this, "op2_trem" ); + op2_vib_mdl.loadSettings( _this, "op2_vib" ); + op2_waveform_mdl.loadSettings( _this, "op2_waveform" ); + + fm_mdl.loadSettings( _this, "fm" ); + vib_depth_mdl.loadSettings( _this, "vib_depth" ); + trem_depth_mdl.loadSettings( _this, "trem_depth" ); + +} + +// Load a preset in binary form +void opl2instrument::loadPatch(unsigned char inst[14]) { + const unsigned int adlib_opadd[] = {0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12}; + // Set all voices + printf("%02x %02x %02x %02x %02x ",inst[0],inst[1],inst[2],inst[3],inst[4]); + printf("%02x %02x %02x %02x %02x %02x\n",inst[5],inst[6],inst[7],inst[8],inst[9],inst[10]); + + emulatorMutex.lock(); + for(int v=0; v<9; ++v) { + theEmulator->write(0x20+adlib_opadd[v],inst[0]); // op1 AM/VIB/EG/KSR/Multiplier + theEmulator->write(0x23+adlib_opadd[v],inst[1]); // op2 + theEmulator->write(0x40+adlib_opadd[v],inst[2]); // op1 KSL/Output Level + theEmulator->write(0x43+adlib_opadd[v],inst[3]); // op2 + theEmulator->write(0x60+adlib_opadd[v],inst[4]); // op1 A/D + theEmulator->write(0x63+adlib_opadd[v],inst[5]); // op2 + theEmulator->write(0x80+adlib_opadd[v],inst[6]); // op1 S/R + theEmulator->write(0x83+adlib_opadd[v],inst[7]); // op2 + theEmulator->write(0xe0+adlib_opadd[v],inst[8]); // op1 waveform + theEmulator->write(0xe3+adlib_opadd[v],inst[9]); // op2 + theEmulator->write(0xc0+v,inst[10]); // feedback/algorithm + } + emulatorMutex.unlock(); +} + +void opl2instrument::tuneEqual(int center, float Hz) { + for(int n=0; n<128; ++n) { + float tmp = Hz*pow(2, (n-center)/12.0); + fnums[n] = Hz2fnum( tmp ); + //printf("%d: %d %d %f\n", n, (fnums[n] & 0x1c00) >> 10, fnums[n] & 0x3ff,tmp); + } +} + +// Find suitable F number in lowest possible block +int opl2instrument::Hz2fnum(float Hz) { + for(int block=0; block<8; ++block) { + unsigned int fnum = Hz * pow(2, 20-block) / 49716; + if(fnum<1023) { + return fnum + (block << 10); + } + } + return 0; +} + +// Load one of the default patches +void opl2instrument::loadGMPatch() { + unsigned char *inst = midi_fm_instruments[m_patchModel.value()]; + // printf("loadGMPatch: %d ", m_patchModel.value()); + loadPatch(inst); +} + +// +/* void opl2instrument::loadSBIFile() { + + } */ + +// Update patch from the models to the chip emulation +void opl2instrument::updatePatch() { + printf("updatePatch()\n"); + unsigned char *inst = midi_fm_instruments[0]; + inst[0] = ( op1_trem_mdl.value() ? 128 : 0 ) + + ( op1_vib_mdl.value() ? 64 : 0 ) + + ( op1_perc_mdl.value() ? 0 : 32 ) + // NB. This envelope mode is "perc", not "sus" + ( op1_ksr_mdl.value() ? 16 : 0 ) + + ((int)op1_mul_mdl.value() & 0x0f); + inst[1] = ( op2_trem_mdl.value() ? 128 : 0 ) + + ( op2_vib_mdl.value() ? 64 : 0 ) + + ( op2_perc_mdl.value() ? 0 : 32 ) + // NB. This envelope mode is "perc", not "sus" + ( op2_ksr_mdl.value() ? 16 : 0 ) + + ((int)op2_mul_mdl.value() & 0x0f); + inst[2] = ( (int)op1_scale_mdl.value() & 0x03 << 6 ) + + (63 - ( (int)op1_lvl_mdl.value() & 0x3f ) ); + inst[3] = ( (int)op2_scale_mdl.value() & 0x03 << 6 ) + + (63 - ( (int)op2_lvl_mdl.value() & 0x3f ) ); + inst[4] = ((15 - ((int)op1_a_mdl.value() & 0x0f ) ) << 4 )+ + (15 - ( (int)op1_d_mdl.value() & 0x0f ) ); + inst[5] = ((15 - ( (int)op2_a_mdl.value() & 0x0f ) ) << 4 )+ + (15 - ( (int)op2_d_mdl.value() & 0x0f ) ); + inst[6] = ((15 - ( (int)op1_s_mdl.value() & 0x0f ) ) << 4 ) + + (15 - ( (int)op1_r_mdl.value() & 0x0f ) ); + inst[7] = ((15 - ( (int)op2_s_mdl.value() & 0x0f ) ) << 4 ) + + (15 - ( (int)op2_r_mdl.value() & 0x0f ) ); + inst[8] = (int)op1_waveform_mdl.value() & 0x03; + inst[9] = (int)op2_waveform_mdl.value() & 0x03; + inst[10] = (fm_mdl.value() ? 0 : 1 ) + + (((int)feedback_mdl.value() & 0x07 )<< 1); + // These are always 0 in the list I had? + inst[11] = 0; + inst[12] = 0; + inst[13] = 0; + + // Not part of the patch per se + theEmulator->write(0xBD, (trem_depth_mdl.value() ? 128 : 0 ) + + (vib_depth_mdl.value() ? 64 : 0 )); + + loadPatch(inst); +} + + + +opl2instrumentView::opl2instrumentView( Instrument * _instrument, + QWidget * _parent ) : + InstrumentView( _instrument, _parent ) +{ + /* Unnecessary? + m_patch = new lcdSpinBox( 3, this , "PRESET"); + m_patch->setLabel( "PRESET" ); + m_patch->move( 100, 1 ); + m_patch->setEnabled( true ); + */ + +#define KNOB_GEN(knobname, hinttext, hintunit,xpos,ypos) \ + knobname = new knob( knobStyled, this );\ + knobname->setHintText( tr(hinttext) + "", hintunit );\ + knobname->setFixedSize(22,22);\ + knobname->setCenterPointX(11.0);\ + knobname->setCenterPointY(11.0);\ + knobname->setTotalAngle(270.0);\ + knobname->move(xpos,ypos); + +#define BUTTON_GEN(buttname, tooltip, xpos, ypos) \ + buttname = new pixmapButton( this, NULL );\ + buttname->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "opl2_led_on" ) );\ + buttname->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( "opl2_led_off" ) );\ + buttname->setCheckable( true );\ + toolTip::add( buttname, tr( tooltip ) );\ + buttname->move( xpos, ypos ); + +#define WAVEBUTTON_GEN(buttname, tooltip, xpos, ypos, icon_on, icon_off, buttgroup) \ + buttname = new pixmapButton( this, NULL );\ + buttname->setActiveGraphic( PLUGIN_NAME::getIconPixmap( icon_on ) ); \ + buttname->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( icon_off ) ); \ + toolTip::add( buttname, tr( tooltip ) );\ + buttname->move( xpos, ypos );\ + buttgroup->addButton(buttname); + + + // OP1 knobs & buttons... + KNOB_GEN(op1_a_kn, "Attack", "", 6, 48); + KNOB_GEN(op1_d_kn, "Decay", "", 34, 48); + KNOB_GEN(op1_s_kn, "Sustain", "", 62, 48); + KNOB_GEN(op1_r_kn, "Release", "", 90, 48); + KNOB_GEN(op1_lvl_kn, "Level", "", 166, 48); + KNOB_GEN(op1_scale_kn, "Scale", "", 194, 48); + KNOB_GEN(op1_mul_kn, "Frequency multiplier", "", 222, 48); + BUTTON_GEN(op1_ksr_btn, "Keyboard scaling rate", 9, 87); + BUTTON_GEN(op1_perc_btn, "Percussive envelope", 36, 87); + BUTTON_GEN(op1_trem_btn, "Tremolo", 65, 87); + BUTTON_GEN(op1_vib_btn, "Vibrato", 93, 87); + KNOB_GEN(feedback_kn, "Feedback", "", 128, 48); + + op1_waveform = new automatableButtonGroup( this ); + WAVEBUTTON_GEN(op1_w0_btn,"Sine", 154, 86, "wave1_on", "wave1_off", op1_waveform); + WAVEBUTTON_GEN(op1_w1_btn,"Half sine", 178, 86, "wave2_on", "wave2_off", op1_waveform); + WAVEBUTTON_GEN(op1_w2_btn,"Absolute sine", 199, 86, "wave3_on", "wave3_off", op1_waveform); + WAVEBUTTON_GEN(op1_w3_btn,"Quarter sine", 220, 86, "wave4_on", "wave4_off", op1_waveform); + + + // And the same for OP2 + KNOB_GEN(op2_a_kn, "Attack", "", 6, 138); + KNOB_GEN(op2_d_kn, "Decay", "", 34, 138); + KNOB_GEN(op2_s_kn, "Sustain", "", 62, 138); + KNOB_GEN(op2_r_kn, "Release", "", 90, 138); + KNOB_GEN(op2_lvl_kn, "Level", "", 166, 138); + KNOB_GEN(op2_scale_kn, "Scale", "", 194, 138); + KNOB_GEN(op2_mul_kn, "Frequency multiplier", "", 222, 138); + BUTTON_GEN(op2_ksr_btn, "Keyboard scaling rate", 9, 177); + BUTTON_GEN(op2_perc_btn, "Percussive envelope", 36, 177); + BUTTON_GEN(op2_trem_btn, "Tremolo", 65, 177); + BUTTON_GEN(op2_vib_btn, "Vibrato", 93, 177); + + op2_waveform = new automatableButtonGroup( this ); + WAVEBUTTON_GEN(op2_w0_btn,"Sine", 154, 176, "wave1_on", "wave1_off", op2_waveform); + WAVEBUTTON_GEN(op2_w1_btn,"Half sine", 178, 176, "wave2_on", "wave2_off", op2_waveform); + WAVEBUTTON_GEN(op2_w2_btn,"Absolute sine", 199, 176, "wave3_on", "wave3_off", op2_waveform); + WAVEBUTTON_GEN(op2_w3_btn,"Quarter Sine", 220, 176, "wave4_on", "wave4_off", op2_waveform); + + BUTTON_GEN(fm_btn, "FM", 9, 220); + BUTTON_GEN(vib_depth_btn, "Vibrato depth", 65, 220); + BUTTON_GEN(trem_depth_btn, "Tremolo depth", 93, 220); + + + setAutoFillBackground( true ); + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( + "artwork" ) ); + setPalette( pal ); + + + +} + +void opl2instrumentView::modelChanged() +{ + opl2instrument * m = castModel(); + // m_patch->setModel( &m->m_patchModel ); + + op1_a_kn->setModel( &m->op1_a_mdl ); + op1_d_kn->setModel( &m->op1_d_mdl ); + op1_s_kn->setModel( &m->op1_s_mdl ); + op1_r_kn->setModel( &m->op1_r_mdl ); + op1_lvl_kn->setModel( &m->op1_lvl_mdl ); + op1_scale_kn->setModel( &m->op1_scale_mdl ); + op1_mul_kn->setModel( &m->op1_mul_mdl ); + feedback_kn->setModel( &m->feedback_mdl ); + op1_ksr_btn->setModel( &m->op1_ksr_mdl ); + op1_perc_btn->setModel( &m->op1_perc_mdl ); + op1_trem_btn->setModel( &m->op1_trem_mdl ); + op1_vib_btn->setModel( &m->op1_vib_mdl ); + /* op1_w0_btn->setModel( &m->op1_w0_mdl ); + op1_w1_btn->setModel( &m->op1_w1_mdl ); + op1_w2_btn->setModel( &m->op1_w2_mdl ); + op1_w3_btn->setModel( &m->op1_w3_mdl ); */ + op1_waveform->setModel( &m->op1_waveform_mdl ); + + + op2_a_kn->setModel( &m->op2_a_mdl ); + op2_d_kn->setModel( &m->op2_d_mdl ); + op2_s_kn->setModel( &m->op2_s_mdl ); + op2_r_kn->setModel( &m->op2_r_mdl ); + op2_lvl_kn->setModel( &m->op2_lvl_mdl ); + op2_scale_kn->setModel( &m->op2_scale_mdl ); + op2_mul_kn->setModel( &m->op2_mul_mdl ); + op2_ksr_btn->setModel( &m->op2_ksr_mdl ); + op2_perc_btn->setModel( &m->op2_perc_mdl ); + op2_trem_btn->setModel( &m->op2_trem_mdl ); + op2_vib_btn->setModel( &m->op2_vib_mdl ); + /* op2_w0_btn->setModel( &m->op2_w0_mdl ); + op2_w1_btn->setModel( &m->op2_w1_mdl ); + op2_w2_btn->setModel( &m->op2_w2_mdl ); + op2_w3_btn->setModel( &m->op2_w3_mdl ); */ + op2_waveform->setModel( &m->op2_waveform_mdl ); + + fm_btn->setModel( &m->fm_mdl ); + vib_depth_btn->setModel( &m->vib_depth_mdl ); + trem_depth_btn->setModel( &m->trem_depth_mdl ); + +} + +#include "moc_opl2instrument.cxx" diff --git a/plugins/opl2/opl2instrument.h b/plugins/opl2/opl2instrument.h new file mode 100644 index 000000000..6933d7479 --- /dev/null +++ b/plugins/opl2/opl2instrument.h @@ -0,0 +1,173 @@ +/* + * OPL2 FM synth + * + * Copyright (c) 2013 Raine M. Ekman + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef _OPL2_H +#define _OPL2_H + +#include "Instrument.h" +#include "InstrumentView.h" +#include "opl.h" + +#include "lcd_spinbox.h" +#include "knob.h" +#include "pixmap_button.h" + +#define OPL2_VOICE_FREE 255 + +class opl2instrument : public Instrument +{ + Q_OBJECT +public: + opl2instrument( InstrumentTrack * _instrument_track ); + virtual QString nodeName() const; + virtual PluginView * instantiateView( QWidget * _parent ); + + inline virtual bool isMidiBased() const { return true; } + + virtual bool handleMidiEvent( const midiEvent & _me, + const midiTime & _time ); + virtual void play( sampleFrame * _working_buffer ); + + void saveSettings( QDomDocument & _doc, QDomElement & _this ); + void loadSettings( const QDomElement & _this ); + void loadPatch(unsigned char inst[14]); + void tuneEqual(int center, float Hz); + + IntModel m_patchModel; + + FloatModel op1_a_mdl; + FloatModel op1_d_mdl; + FloatModel op1_s_mdl; + FloatModel op1_r_mdl; + FloatModel op1_lvl_mdl; + FloatModel op1_scale_mdl; + FloatModel op1_mul_mdl; + FloatModel feedback_mdl; + BoolModel op1_ksr_mdl; + BoolModel op1_perc_mdl; + BoolModel op1_trem_mdl; + BoolModel op1_vib_mdl; + BoolModel op1_w0_mdl; + BoolModel op1_w1_mdl; + BoolModel op1_w2_mdl; + BoolModel op1_w3_mdl; + IntModel op1_waveform_mdl; + + + FloatModel op2_a_mdl; + FloatModel op2_d_mdl; + FloatModel op2_s_mdl; + FloatModel op2_r_mdl; + FloatModel op2_lvl_mdl; + FloatModel op2_scale_mdl; + FloatModel op2_mul_mdl; + BoolModel op2_ksr_mdl; + BoolModel op2_perc_mdl; + BoolModel op2_trem_mdl; + BoolModel op2_vib_mdl; + BoolModel op2_w0_mdl; + BoolModel op2_w1_mdl; + BoolModel op2_w2_mdl; + BoolModel op2_w3_mdl; + IntModel op2_waveform_mdl; + + BoolModel fm_mdl; + BoolModel vib_depth_mdl; + BoolModel trem_depth_mdl; + + +private slots: + void updatePatch(); + void reloadEmulator(); + void loadGMPatch(); + +private: + Copl *theEmulator; + fpp_t frameCount; + short *renderbuffer; + int voiceNote[9]; + int heldNotes[128]; + // These include both octave and Fnumber + int fnums[128]; + + int Hz2fnum(float Hz); + static QMutex emulatorMutex; +}; + + +class opl2instrumentView : public InstrumentView +{ + Q_OBJECT +public: + opl2instrumentView( Instrument * _instrument, QWidget * _parent ); + lcdSpinBox *m_patch; + void modelChanged(); + + knob *op1_a_kn; + knob *op1_d_kn; + knob *op1_s_kn; + knob *op1_r_kn; + knob *op1_lvl_kn; + knob *op1_scale_kn; + knob *op1_mul_kn; + knob *feedback_kn; + pixmapButton *op1_ksr_btn; + pixmapButton *op1_perc_btn; + pixmapButton *op1_trem_btn; + pixmapButton *op1_vib_btn; + pixmapButton *op1_w0_btn; + pixmapButton *op1_w1_btn; + pixmapButton *op1_w2_btn; + pixmapButton *op1_w3_btn; + automatableButtonGroup *op1_waveform; + + + knob *op2_a_kn; + knob *op2_d_kn; + knob *op2_s_kn; + knob *op2_r_kn; + knob *op2_lvl_kn; + knob *op2_scale_kn; + knob *op2_mul_kn; + pixmapButton *op2_ksr_btn; + pixmapButton *op2_perc_btn; + pixmapButton *op2_trem_btn; + pixmapButton *op2_vib_btn; + pixmapButton *op2_w0_btn; + pixmapButton *op2_w1_btn; + pixmapButton *op2_w2_btn; + pixmapButton *op2_w3_btn; + automatableButtonGroup *op2_waveform; + + + pixmapButton *fm_btn; + pixmapButton *vib_depth_btn; + pixmapButton *trem_depth_btn; + + + + +}; + +#endif diff --git a/plugins/opl2/temuopl.cpp b/plugins/opl2/temuopl.cpp new file mode 100644 index 000000000..13691d782 --- /dev/null +++ b/plugins/opl2/temuopl.cpp @@ -0,0 +1,75 @@ +/* + * AdPlug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter , et al. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * temuopl.cpp - Tatsuyuki Satoh's OPL2 emulator, by Simon Peter + */ + +#include "temuopl.h" + +CTemuopl::CTemuopl(int rate, bool bit16, bool usestereo) + : use16bit(bit16), stereo(usestereo) +{ + opl = OPLCreate(OPL_TYPE_YM3812, 3579545, rate); +} + +CTemuopl::~CTemuopl() +{ + OPLDestroy(opl); +} + +void CTemuopl::update(short *buf, int samples) +{ + int i; + + if(use16bit) { + YM3812UpdateOne(opl,buf,samples); + + if(stereo) + for(i=samples-1;i>=0;i--) { + buf[i*2] = buf[i]; + buf[i*2+1] = buf[i]; + } + } else { + short *tempbuf = new short[stereo ? samples*2 : samples]; + int i; + + YM3812UpdateOne(opl,tempbuf,samples); + + if(stereo) + for(i=samples-1;i>=0;i--) { + tempbuf[i*2] = tempbuf[i]; + tempbuf[i*2+1] = tempbuf[i]; + } + + for(i=0;i<(stereo ? samples*2 : samples);i++) + ((char *)buf)[i] = (tempbuf[i] >> 8) ^ 0x80; + + delete [] tempbuf; + } +} + +void CTemuopl::write(int reg, int val) +{ + OPLWrite(opl,0,reg); + OPLWrite(opl,1,val); +} + +void CTemuopl::init() +{ + OPLResetChip(opl); +} diff --git a/plugins/opl2/temuopl.h b/plugins/opl2/temuopl.h new file mode 100644 index 000000000..564fe3d8d --- /dev/null +++ b/plugins/opl2/temuopl.h @@ -0,0 +1,47 @@ +/* + * Adplug - Replayer for many OPL2/OPL3 audio file formats. + * Copyright (C) 1999 - 2004 Simon Peter, , et al. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * temuopl.h - Tatsuyuki Satoh's OPL2 emulator, by Simon Peter + */ + +#ifndef H_ADPLUG_TEMUOPL +#define H_ADPLUG_TEMUOPL + +#include "opl.h" +extern "C" { +#include "fmopl.h" +} + +class CTemuopl: public Copl +{ + public: + CTemuopl(int rate, bool bit16, bool usestereo); // rate = sample rate + virtual ~CTemuopl(); + + void update(short *buf, int samples); // fill buffer + + // template methods + void write(int reg, int val); + void init(); + + private: + bool use16bit,stereo; + FM_OPL *opl; // holds emulator data +}; + +#endif diff --git a/plugins/opl2/wave1_off.png b/plugins/opl2/wave1_off.png new file mode 100644 index 0000000000000000000000000000000000000000..c8a8f87acab304d654ff483536421887b0d6d5fa GIT binary patch literal 749 zcmVe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00LD>L_t(I%e9riYg17a$3N%( zXkK2@HX1?b@&t>hqaFMg+O>mIMJI7l#NlmqF(MR%jv|PHPA(1w`zLfMwsldekq&hd zs*)x)dGEgKkTfx^l&I-}1NWZG`F{DHbI-jJMUet>KpxP5FhnyQ@CzLu1Jtky@*VIf zj^m0kMnnXq6e4Xg&N)PcBuTo7S(cHeX&+dcriWstQO=8@RjZncwlvP6>BZc%fiTlBKKAw&YXpBiwRtV6LUcQ?{#)a?CQY4hVGYN&p4Nrcho!?U+V67zx0>Z}%EJx14>6@0XZ(7tJ z3dQFdvnizKJoW32T+I@Gv|xYhfdIxBjA=6uVyA8g{8(_*AN5ewPs3QO(OUYOT-&V? z1VNWzkSVs?VD4u$u4bf@9`i{EUnuN$y8``lkT@nLCfM28K|}_ACiJEzm_HcoEmh|N z`DSy^PfblxE|Y00000NkvXXu0mjfTKYKt literal 0 HcmV?d00001 diff --git a/plugins/opl2/wave1_on.png b/plugins/opl2/wave1_on.png new file mode 100644 index 0000000000000000000000000000000000000000..cdb87e118878b51e112a106e4a7080297617d3d5 GIT binary patch literal 786 zcmV+t1MU2YP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00MeRL_t(I%e9riYg9oH$3HV~ z_uacY^5YK07=$MQ3rmUSPmrXrN-2n-pomq9Yl7Is!X`qBGT`)+p{0gUIS#? z#=}ynG-Her5kXZEX$6xc2_ixiMSB<1G$oGXea7NA{_UG-(=t#hm1eB9vaqng%E}70 zT5S*De^WHbo0Z5aS zd_GTX4N(qqFBQ2A+mk7-0I~_$SIXJP9^aov`(o%`cSQi}YX<-ka=9F_F(jLitt<6A zDOsOD4~1%1QHcXpMMd!%3g?tRjoP%su6q=wd^A3wjg|g+pX3s#Xa~RvSZnb;pJdWt z#U43pb3*<@hT?2MX2W8gC9`2E&IWix9^R0}s_jrDfH4M9gKM{ob3Vn2hn22>P^nf3f`F*1=;u})5FCS0fchNdo_W|Mh{m9P15BYsjMc6*jiZF& z;bGR7z7c!iHl&kx-Su-wow+e+jh($ literal 0 HcmV?d00001 diff --git a/plugins/opl2/wave2_off.png b/plugins/opl2/wave2_off.png new file mode 100644 index 0000000000000000000000000000000000000000..836c438e134d8bad6a213c5f46d9fc0e5e6038e7 GIT binary patch literal 435 zcmV;k0ZjghP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00A3GL_t(I%eB-$O2j}E$MNr* zOcImb5OmQhY=lU31#jUA1P>rvYN4JY9>7wxvk<(AXe(IQ3M&dOqUO)o=%S(+VVr6n z{P-~M@fbQF{4$Y`k@vg2)dqB@ z)A^LI78)Mc8mf7Nz81n$g}zdMdub2^lcG)x&)YS=4?aK+^$z&Q3h%5vEJ>0~dcEH( zF&=ae9Q377EgHtdnrg)`yXv(^`~AKFD3==^wrZw#HS#2rfSEGf?Uw+|4BNqyWtjmO zZ&Y~a3h(0kHgAt!engxbL5&18g6^S4@;tY{{I2WT-&4nN?4wF4`{-b>WF3_>O*jAJ dlRmMHz5+}>LbgL1&$j>o002ovPDHLkV1m!5tV{p^ literal 0 HcmV?d00001 diff --git a/plugins/opl2/wave2_on.png b/plugins/opl2/wave2_on.png new file mode 100644 index 0000000000000000000000000000000000000000..9a99d9d9b97df56d2acc9a2ce2a70396beb1ec42 GIT binary patch literal 520 zcmV+j0{8uiP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00D4GL_t(I%e9n0PFq0`hrgMf zeZ)4#2n&#clvlU`MM9i_mIELfjsQ)HL|nlVWg^jV1H=sw1suQ>)aemPV`1~h@9k1J z5hgg6i)FSM&1gT(Z!|NK=lK$e&48WMP-(Z@F*&r^Y$k_VqtT%MEitrSuOnH>U~@Da z0U6`}&;E)P`~_IGS|wV^lcwoHW`fmfHDXp^f1vssDyNFS5(XQQ`|Ut%j;ra#XGDw7 z1glgk1S|0pkuJ;~I;1bdVY`OL&&b_=p!_tQ5^sWaIvu)O1&`L8$4I#}+);DR;U)681rCRM`v-vD(Zn5kk$(>6y~nE%NHbDi zWmu^>!7eAvwM>Zrn^!PZrT$&huIbv^D#@=@p6C1TaimXDL!SZD?_uXzotSO_0000< KMNUMnLSTZJ_Sdlh literal 0 HcmV?d00001 diff --git a/plugins/opl2/wave3_off.png b/plugins/opl2/wave3_off.png new file mode 100644 index 0000000000000000000000000000000000000000..1bb117a06e11a9ce179a1c4d41616f5936d36657 GIT binary patch literal 497 zcmVe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00CJ^L_t(I%e9m}O9L?&fS=@Y zr(Ao~a_Cfgg-W%Ep!gSDy9f?$iendX@h{XxTsn$w4uZeHzaR?YAUHU~B_XB2tj2T`R`X-pT-r;IjI;)X^&3EWGGdX$As($H81jOcVac|l1{GuTUD>X+dY z+;fR@oh=I2Qbt?p1mhiBSkEGp)@rp}`hFOp9Vnkzs0Ts3pc(Ea#LJr5bq9c#s}OZ3 zCKwUI%z>Rr>-D+@h?Y_Y-Gu7CLVSq42tBQN>qleTuXgQ8<|xMNTiEv!(QGy~z;GwV zxsf=xvhYS<&q4tFZKp6FuB3#kDdkgzXti4Ao8Pu=^L=VrmU*d^(!8|YUi`B}YfTtM nBuSFJv>*t&|M5v*n3jG4?x=LNq!ksV00000NkvXXu0mjfeC5iO literal 0 HcmV?d00001 diff --git a/plugins/opl2/wave3_on.png b/plugins/opl2/wave3_on.png new file mode 100644 index 0000000000000000000000000000000000000000..c79eb0e517f008a7933bda60f5a22d3fc526931d GIT binary patch literal 580 zcmV-K0=xZ*P)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00FE?L_t(I%e9ojY7{{bhQF$= zp18Z&U2%yX9Gt^m3?ldhf)MZl#5eF14}vHP9t2N&5HF%$d;{?ff`Yz)2Xl=ecnFCg zLpCux)7>6MFsy4lIQFHX>+g@M{;OJwqBu><%Yf@`LuE3Vq}HLM(WrH(4TnSa@3su> z_xnf|s4fE}Kz@df79fAY{JQ7gfpxoGk_Bek&MRalSg+S3WdW~|1n5`jyjJ`Np}Lef zxE4vHIU^Qm;;6~hXNq+?9ijy)Nk|EU#}1iF(`+AM_$jfs9th_ep!*EV&m6LUM6;DB z9|Y0>ya|%$c`EPM9Ii!{pD1!5Om76@3g`~>UOG;^b?j`+09aYe_hwjkd;DTS4l#$NH(=g-yb6(aTFR?5 znVJ*q{V{#b+)Nxd3y#L9{!?vtOjlRW|1%_|#H^|aAwU8tisI(~_@rO84gCRSUyNVn SRF+f#0000P000vR1^@s6Wpbtk00006VoOIv0RI5$ z0KFoD=Cl9+010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3$u}6(j0~W4HhS02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00JFJL_t(I%e9riYZO5g$3HVW zo6F{YkvqIth-+~qV4K#)`~en%pp96F5ET(yA+=y@dkB{1A2{p}Vs#L(wGjd$%IRUu z-tNq^*xMiH1|e`ayTk0`y?Nj7cjrAug<;rZHNyg@KxBYBD+2ig90Q-s{{H@(i|&r& zm?TNC*5=bWm;0yFsSJn117HSxR^4t_mO)!2O|!kd&CbpaaU9ENGD3Ma?zaY*zqA1Fh0ho=A4HO{fCIk_MLMr~$S2aWgYb{zA zWK6wYU)Y@V9jCV)_L{Ky*guzX7L)Xa&Le-}Oq_FR5l9In2!f)puL#j|ORbjLL0~EX zvt37Y&rz#EtrR0ACC<48?Pfe4=f>o2j2uH_;4yt>>5QvNzP+Adjunl8$K+MQrSV!t ziM5u!y_*Gy);g{I>kitQ&I^M&Q~XBAeA)OhnBjlXY`*kSX9|tWW6B3DB1q9T7~fCX zMmG{R-}i`kwfaTbfi8@00000NkvXXu0mjfi$^iJ literal 0 HcmV?d00001 diff --git a/plugins/opl2/wave4_on.png b/plugins/opl2/wave4_on.png new file mode 100644 index 0000000000000000000000000000000000000000..7af2f083b7ddee7c729a6fe9c3b9f1a883da5099 GIT binary patch literal 742 zcmVP000vR1^@s6Wpbtk00006VoOIv0RI5$ z0KFoD=Cl9+010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3$u}6)KZj+Z+G@02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00K@)L_t(I%e9rgYZOrw#eetB zefyPN*AR@UG9WSO{1b!(B#5<*wFpTBE3pe$i;YAZA^(8b38t4|R3s7zSP3c!K_YSU zwVV047PHx%&8AS?ykUxY_q=z`y>rid5{BU@XEPGu0B9+2^NdIifem0&=jP^?{&jT} zMZ|GTk|dosP18<%cX!uTR#p~)BjAgSjEvYIWSeE%OioTRH8n*PMYg)SdKY-1^?IFy z`vWSF8Q)+1Al{6bn3xbi0MS~lh7=N_s{q!X?^$_b?zHc0xX+;1gw}GalNo?kDiur< zj@$sMb_x71p;R)Q>k84Kp&_i0;9d6PWE;va9sZNB^DOCTK9(SP%m-oTc^5+kycdcU z1Iv+=%Vknch{TWvoO=`?2LcL_#C>9eZ%}>O#+3UpUZGe4%au{r*Vk#x#SLwR>?gT!t3Y!)VSheh_>QuD0#n!$${&rHndvTxa}FmC-2&ZK8V_SohYK7I z*R#R-drEu-_8(Y=as3!4f^&v-ZG(F6@lNm?&{|0G-UCqjsg!PeTm!5C@*9$I*m)A; z$uRy%8N1=30u~wZWoTYc@!l}HEE)s>UX0c(1Ox=_z~1ud4RlNZ(0HAX2pmG;t;2gr z^DTUwNy`7XaPSp$4~oSgZ=Wm^b%MU>^H$ccf8)=bi_@%07*qoM6N<$g8TD7(f|Me literal 0 HcmV?d00001