Added OpulenZ, an FM synth for LMMS
Signed-off-by: Tobias Doerffel <tobias.doerffel@gmail.com>
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
3
plugins/opl2/CMakeLists.txt
Normal file
@@ -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)
|
||||
62
plugins/opl2/README
Normal file
@@ -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 )
|
||||
600
plugins/opl2/adlibemu.c
Normal file
@@ -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 <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#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<<oct)*nfrqmul[adlibreg[j+0x20]&15];
|
||||
c->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<<oct)*nfrqmul[adlibreg[j+0x20]&15];
|
||||
c->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<MAXCELLS;i++)
|
||||
{
|
||||
cell[i].cellfunc = docell4;
|
||||
cell[i].amp = 0;
|
||||
cell[i].vol = 0;
|
||||
cell[i].t = 0;
|
||||
cell[i].tinc = 0;
|
||||
cell[i].wavemask = 0;
|
||||
cell[i].waveform = &wavtable[WAVPREC];
|
||||
}
|
||||
|
||||
numspeakers = danumspeakers;
|
||||
bytespersample = dabytespersample;
|
||||
|
||||
recipsamp = 1.0 / (float)dasamplerate;
|
||||
for(i=15;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<<oct)*nfrqmul[adlibreg[modulatorbase[i]+0x20]&15];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void adlib0 (long i, long v)
|
||||
{
|
||||
unsigned char tmp = adlibreg[i];
|
||||
adlibreg[i] = v;
|
||||
|
||||
if (i == 0xbd)
|
||||
{
|
||||
if ((v&16) > (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<numsamples;ns+=endsamples)
|
||||
{
|
||||
endsamples = min(FIFOSIZ*2-rend,FIFOSIZ);
|
||||
endsamples = min(endsamples,numsamples-ns);
|
||||
|
||||
for(i=0;i<9;i++)
|
||||
nrptr[i] = &rptr[i][rend];
|
||||
for(i=0;i<rptrs;i++)
|
||||
memset((void *)&rbuf[i][rend],0,endsamples*sizeof(float));
|
||||
|
||||
if (adlibreg[0xbd]&0x20)
|
||||
{
|
||||
//BassDrum (j=6)
|
||||
if (cell[15].cellfunc != docell4)
|
||||
{
|
||||
if (adlibreg[0xc6]&1)
|
||||
{
|
||||
for(i=0;i<endsamples;i++)
|
||||
{
|
||||
(cell[15].cellfunc)((void *)&cell[15],0.0);
|
||||
nrptr[6][i] += cell[15].val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i=0;i<endsamples;i++)
|
||||
{
|
||||
(cell[6].cellfunc)((void *)&cell[6],cell[6].val*cell[6].mfb);
|
||||
(cell[15].cellfunc)((void *)&cell[15],cell[6].val*WAVPREC*MODFACTOR);
|
||||
nrptr[6][i] += cell[15].val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Snare/Hihat (j=7), Cymbal/TomTom (j=8)
|
||||
if ((cell[7].cellfunc != docell4) || (cell[8].cellfunc != docell4) || (cell[16].cellfunc != docell4) || (cell[17].cellfunc != docell4))
|
||||
{
|
||||
for(i=0;i<endsamples;i++)
|
||||
{
|
||||
k = k*1664525+1013904223;
|
||||
(cell[16].cellfunc)((void *)&cell[16],k&((WAVPREC>>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;i<endsamples;i++)
|
||||
{
|
||||
(cptr->cellfunc)((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;i<endsamples;i++)
|
||||
{
|
||||
(cptr->cellfunc)((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<rptrs;j++)
|
||||
{
|
||||
for(i=0;i<endsamples;i++)
|
||||
{
|
||||
snd[(i<<1) ] += rbuf[j][(nlplc[j]+i)&(FIFOSIZ*2-1)]*nlvol[j];
|
||||
snd[(i<<1)+1] += rbuf[j][(nrplc[j]+i)&(FIFOSIZ*2-1)]*nrvol[j];
|
||||
}
|
||||
nlplc[j] += endsamples;
|
||||
nrplc[j] += endsamples;
|
||||
}
|
||||
|
||||
if (bytespersample == 1)
|
||||
{
|
||||
for(i=(endsamples<<1)-1;i>=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));
|
||||
}
|
||||
}
|
||||
26
plugins/opl2/adlibemu.h
Normal file
@@ -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];
|
||||
BIN
plugins/opl2/artwork.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
1390
plugins/opl2/fmopl.c
Normal file
174
plugins/opl2/fmopl.h
Normal file
@@ -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
|
||||
61
plugins/opl2/kemuopl.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Adplug - Replayer for many OPL2/OPL3 audio file formats.
|
||||
* Copyright (C) 1999 - 2005 Simon Peter, <dn.tlp@gmx.net>, 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
|
||||
* <dn.tlp@gmx.net>
|
||||
*/
|
||||
|
||||
#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
|
||||
BIN
plugins/opl2/logo.png
Normal file
|
After Width: | Height: | Size: 285 B |
174
plugins/opl2/mididata.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Adplug - Replayer for many OPL2/OPL3 audio file formats.
|
||||
* Copyright (C) 1999, 2000, 2001 Simon Peter, <dn.tlp@gmx.net>, 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, <philhassey@hotmail.com> - 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
|
||||
};
|
||||
|
||||
69
plugins/opl2/opl.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Adplug - Replayer for many OPL2/OPL3 audio file formats.
|
||||
* Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, 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 <dn.tlp@gmx.net>
|
||||
*/
|
||||
|
||||
#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
|
||||
BIN
plugins/opl2/opl2_led_off.png
Normal file
|
After Width: | Height: | Size: 586 B |
BIN
plugins/opl2/opl2_led_on.png
Normal file
|
After Width: | Height: | Size: 665 B |
613
plugins/opl2/opl2instrument.cpp
Normal file
@@ -0,0 +1,613 @@
|
||||
/*
|
||||
* OPL2 FM synth
|
||||
*
|
||||
* Copyright (c) 2013 Raine M. Ekman <raine/at/iki/fi>
|
||||
*
|
||||
* 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<<n ) * X, X = 0.11597 for A, 0.6311 for D/R
|
||||
// - attack 0.0, 0.23194, 0.46388, 0.92776, 1.85552, 3.71104, 7.42208, 14.84416,
|
||||
// 29.68832, 59.37664, 118.75328, 237.50656, 475.01312, 950.02624, 1900.05248, 3800.10496
|
||||
// -decay/release 0.0, 1.2622, 2.5244, 5.0488, 10.0976, 20.1952, 40.3904, 80.7808, 161.5616,
|
||||
// 323.1232, 646.2464, 1292.4928, 2584.9856, 5169.9712, 10339.9424, 20679.8848
|
||||
|
||||
#include "opl2instrument.h"
|
||||
#include "mididata.h"
|
||||
#include "debug.h"
|
||||
#include "Instrument.h"
|
||||
#include "engine.h"
|
||||
#include "InstrumentPlayHandle.h"
|
||||
#include "InstrumentTrack.h"
|
||||
|
||||
#include <QtXml/QDomDocument>
|
||||
|
||||
#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 <raine/at/iki/fi>",
|
||||
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<InstrumentTrack *>( _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<opl2instrument>();
|
||||
// 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"
|
||||
173
plugins/opl2/opl2instrument.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* OPL2 FM synth
|
||||
*
|
||||
* Copyright (c) 2013 Raine M. Ekman <raine/at/iki/fi>
|
||||
*
|
||||
* 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
|
||||
75
plugins/opl2/temuopl.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* AdPlug - Replayer for many OPL2/OPL3 audio file formats.
|
||||
* Copyright (C) 1999 - 2004 Simon Peter <dn.tlp@gmx.net>, 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 <dn.tlp@gmx.net>
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
47
plugins/opl2/temuopl.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Adplug - Replayer for many OPL2/OPL3 audio file formats.
|
||||
* Copyright (C) 1999 - 2004 Simon Peter, <dn.tlp@gmx.net>, 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 <dn.tlp@gmx.net>
|
||||
*/
|
||||
|
||||
#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
|
||||
BIN
plugins/opl2/wave1_off.png
Normal file
|
After Width: | Height: | Size: 749 B |
BIN
plugins/opl2/wave1_on.png
Normal file
|
After Width: | Height: | Size: 786 B |
BIN
plugins/opl2/wave2_off.png
Normal file
|
After Width: | Height: | Size: 435 B |
BIN
plugins/opl2/wave2_on.png
Normal file
|
After Width: | Height: | Size: 520 B |
BIN
plugins/opl2/wave3_off.png
Normal file
|
After Width: | Height: | Size: 497 B |
BIN
plugins/opl2/wave3_on.png
Normal file
|
After Width: | Height: | Size: 580 B |
BIN
plugins/opl2/wave4_off.png
Normal file
|
After Width: | Height: | Size: 693 B |
BIN
plugins/opl2/wave4_on.png
Normal file
|
After Width: | Height: | Size: 742 B |