#ifndef H_ADPLUG_SOPPLAYER
#define H_ADPLUG_SOPPLAYER
#include <stdint.h>
#include <stdio.h>
#include "player.h"
#define BD 6
#define SD 7
#define TOM 8
#define CYMB 9
#define HIHAT 10
#define MAX_VOLUME 0x7f
#define LOG2_VOLUME 7
#define MID_C 60
#define SOP_TOM_PITCH 36
#define TOM_TO_SD 7
#define SOP_SD_PITCH (SOP_TOM_PITCH + TOM_TO_SD)
#define NB_NOTES 96
#define OCTAVE 12
#define NB_STEP_PITCH 32
#define LOG_NB_STEP_PITCH 5
#define NB_TABLE_DEMI_TON OCTAVE
#define TABLE_SIZE (NB_STEP_PITCH * NB_TABLE_DEMI_TON)
#define maxVoices 20
#define YMB_SIZE 80
class Cad262Driver
{
public:
Cad262Driver(Copl *newopl)
: opl(newopl)
{};
~Cad262Driver()
{};
void SoundWarmInit();
void SetYM_262_SOP(int VX);
void SetMode_SOP(int mode);
void SetStereoPan_SOP(int chan, int value);
void SetVoiceVolume_SOP(unsigned chan, unsigned vol);
void SetVoiceTimbre_SOP(unsigned chan, unsigned char *array);
void SetVoicePitch_SOP(unsigned chan, int pitch);
void NoteOn_SOP(unsigned chan, unsigned pitch);
void NoteOff_SOP(unsigned chan);
int Set_4OP_Mode(unsigned chan, unsigned value);
private:
Copl *opl;
void UpdateFNums(int chan);
void SndOutput1(int addr, int value);
void SndOutput3(int addr, int value);
void SEND_INS(int base_addr, unsigned char *value, int mode);
void SetFreq_SOP(int voice, unsigned note, int pitch, int keyOn);
char percussion;
unsigned char VolumeTable[ 64 * 128 ];
char voiceNote[20];
char voiceKeyOn[20];
unsigned char vPitchBend[20];
unsigned char Ksl[20];
unsigned char Ksl2[20];
unsigned char Ksl2V[20];
unsigned char VoiceVolume[20], OP_MASK;
unsigned char ymbuf[ 2 * YMB_SIZE ];
unsigned char OP4[20];
unsigned char Stereo[22];
protected:
static const int fNumTbl[TABLE_SIZE];
static const unsigned char SlotX[maxVoices * 2];
static const unsigned char VolReg[11 * 2];
static const unsigned MOD12[OCTAVE * 11];
static const unsigned DIV12[OCTAVE * 8];
};
#define SOP_HEAD_SIZE 76
#define SOP_SIGN_SIZE 7
#define SOP_FILENAME 13
#define SOP_TITLE 31
#define SOP_DEF_TEMPO 120
#define SOP_COMMENT 13
#define SOP_INSTNAME 8
#define SOP_LONGNAME 19
#define SOP_INST2OP 11
#define SOP_INST4OP 22
#define SOP_MAX_INST 128
#define SOP_MAX_TRACK 24
#define SOP_MAX_VOL 127
#define SOP_CHAN_NONE 0
#define SOP_CHAN_4OP 1
#define SOP_CHAN_2OP 2
#define SOP_INST_4OP 0
#define SOP_INST_2OP 1
#define SOP_INST_BD 6
#define SOP_INST_SD 7
#define SOP_INST_TT 8
#define SOP_INST_CY 9
#define SOP_INST_HH 10
#define SOP_INST_WAV 11
#define SOP_INST_NONE 12
#define SOP_EVNT_SPEC 1
#define SOP_EVNT_NOTE 2
#define SOP_EVNT_TEMPO 3
#define SOP_EVNT_VOL 4
#define SOP_EVNT_PITCH 5
#define SOP_EVNT_INST 6
#define SOP_EVNT_PAN 7
#define SOP_EVNT_MVOL 8
class CsopPlayer: public CPlayer
{
public:
static CPlayer *factory(Copl *newopl);
CsopPlayer(Copl *newopl)
: CPlayer(newopl), drv(0), chanMode(0), inst(0), track(0)
{ }
~CsopPlayer()
{
if (chanMode) delete[] chanMode;
if (inst) delete[] inst;
if (track)
{
for (int i = 0; i < nTracks + 1; i++)
{
if (track[i].data) delete[] track[i].data;
}
delete[] track;
}
if (drv) drv->~Cad262Driver();
};
bool load(const std::string &filename, const CFileProvider &fp);
bool update();
void rewind(int subsong);
float getrefresh()
{
return timer;
};
unsigned int getspeed()
{
return cur_tempo;
};
std::string gettitle()
{
return title[0] ? std::string(title) : std::string(fname);
}
std::string gettype()
{
char type[36];
sprintf(type, "Note Sequencer v%u.%u by sopepos", (version >> 8) & 0xFF, version & 0xFF);
return std::string(type);
}
std::string getdesc()
{
return std::string(comment);
}
unsigned int getinstruments()
{
return inst ? nInsts : 0;
};
std::string getinstrument(unsigned int n)
{
return inst && n < nInsts ? std::string(inst[n].longname) : std::string();
};
private:
void SetTempo(uint8_t tempo);
void executeCommand(uint8_t t);
Cad262Driver * drv;
protected:
bool songend;
float timer;
uint16_t version;
uint8_t cur_tempo;
uint8_t volume[SOP_MAX_TRACK];
uint8_t lastvol[SOP_MAX_TRACK];
uint8_t master_vol;
char fname[SOP_FILENAME];
char title[SOP_TITLE];
uint8_t percussive, tickBeat, basicTempo;
char comment[SOP_COMMENT];
uint8_t nTracks, nInsts;
struct sop_inst {
uint8_t type;
char filename[SOP_INSTNAME + 1];
char longname[SOP_LONGNAME + 1];
uint8_t data[SOP_INST4OP];
};
#pragma pack(push, 1)
struct sop_sample {
uint16_t val1;
uint16_t val2;
uint16_t length;
uint16_t val4;
uint16_t base_freq;
uint16_t val6;
uint16_t val7;
uint8_t val8;
uint16_t val9;
uint16_t val10;
};
#pragma pack(pop)
struct sop_trk {
uint16_t nEvents;
uint32_t size;
uint8_t * data;
uint32_t pos;
uint32_t counter;
uint16_t ticks;
uint16_t dur;
};
uint8_t * chanMode;
sop_inst * inst;
sop_trk * track;
};
#endif