#ifndef RAD20PLAYER_H #define RAD20PLAYER_H #include //================================================================================================== // RAD player class. //================================================================================================== class RADPlayer { // Various constants enum { kTracks = 100, kChannels = 9, kTrackLines = 64, kRiffTracks = 10, kInstruments = 127, cmPortamentoUp = 0x1, cmPortamentoDwn = 0x2, cmToneSlide = 0x3, cmToneVolSlide = 0x5, cmVolSlide = 0xA, cmSetVol = 0xC, cmJumpToLine = 0xD, cmSetSpeed = 0xF, cmIgnore = ('I' - 55), cmMultiplier = ('M' - 55), cmRiff = ('R' - 55), cmTranspose = ('T' - 55), cmFeedback = ('U' - 55), cmVolume = ('V' - 55), }; enum e_Source { SNone, SRiff, SIRiff, }; enum { fKeyOn = 1 << 0, fKeyOff = 1 << 1, fKeyedOn = 1 << 2, }; struct CInstrument { uint8_t Feedback[2]; uint8_t Panning[2]; uint8_t Algorithm; uint8_t Detune; uint8_t Volume; uint8_t RiffSpeed; uint8_t * Riff; uint8_t Operators[4][5]; }; struct CEffects { int8_t PortSlide; int8_t VolSlide; uint16_t ToneSlideFreq; uint8_t ToneSlideOct; uint8_t ToneSlideSpeed; int8_t ToneSlideDir; }; struct CChannel { uint8_t LastInstrument; CInstrument * Instrument; uint8_t Volume; uint8_t DetuneA; uint8_t DetuneB; uint8_t KeyFlags; uint16_t CurrFreq; int8_t CurrOctave; CEffects FX; struct CRiff { CEffects FX; uint8_t * Track; uint8_t * TrackStart; uint8_t Line; uint8_t Speed; uint8_t SpeedCnt; int8_t TransposeOctave; int8_t TransposeNote; uint8_t LastInstrument; } Riff, IRiff; }; public: RADPlayer() : Initialised(false) {} void Init(const void *tune, void (*opl3)(void *, uint16_t, uint8_t), void *arg); void Stop(); bool Update(); int GetHertz() const { return Hertz; } int GetPlayTimeInSeconds() const { return PlayTime / Hertz; } int GetTunePos() const { return Order; } int GetTuneLength() const { return OrderListSize; } int GetTuneLine() const { return Line; } void SetMasterVolume(int vol) { MasterVol = vol; } int GetMasterVolume() const { return MasterVol; } int GetSpeed() const { return Speed; } #if RAD_DETECT_REPEATS uint32_t ComputeTotalTime(); #endif private: bool UnpackNote(uint8_t *&s, uint8_t &last_instrument); uint8_t * GetTrack(); uint8_t * SkipToLine(uint8_t *trk, uint8_t linenum, bool chan_riff = false); void PlayLine(); void PlayNote(int channum, int8_t notenum, int8_t octave, uint16_t instnum, uint8_t cmd = 0, uint8_t param = 0, e_Source src = SNone, int op = 0); void LoadInstrumentOPL3(int channum); void PlayNoteOPL3(int channum, int8_t octave, int8_t note); void ResetFX(CEffects *fx); void TickRiff(int channum, CChannel::CRiff &riff, bool chan_riff); void ContinueFX(int channum, CEffects *fx); void SetVolume(int channum, uint8_t vol); void GetSlideDir(int channum, CEffects *fx); void LoadInstMultiplierOPL3(int channum, int op, uint8_t mult); void LoadInstVolumeOPL3(int channum, int op, uint8_t vol); void LoadInstFeedbackOPL3(int channum, int which, uint8_t fb); void Portamento(uint16_t channum, CEffects *fx, int8_t amount, bool toneslide); void Transpose(int8_t note, int8_t octave); void SetOPL3(uint16_t reg, uint8_t val) { OPL3Regs[reg] = val; OPL3(OPL3Arg, reg, val); } uint8_t GetOPL3(uint16_t reg) const { return OPL3Regs[reg]; } void (*OPL3)(void *, uint16_t, uint8_t); void * OPL3Arg; CInstrument Instruments[kInstruments]; CChannel Channels[kChannels]; uint32_t PlayTime; #if RAD_DETECT_REPEATS uint32_t OrderMap[4]; bool Repeating; #endif int16_t Hertz; uint8_t * OrderList; uint8_t * Tracks[kTracks]; uint8_t * Riffs[kRiffTracks][kChannels]; uint8_t * Track; bool Initialised; uint8_t Speed; uint8_t OrderListSize; uint8_t SpeedCnt; uint8_t Order; uint8_t Line; int8_t Entrances; uint8_t MasterVol; int8_t LineJump; uint8_t OPL3Regs[512]; // Values exported by UnpackNote() int8_t NoteNum; int8_t OctaveNum; uint8_t InstNum; uint8_t EffectNum; uint8_t Param; bool LastNote; static const int8_t NoteSize[]; static const uint16_t ChanOffsets3[9], Chn2Offsets3[9]; static const uint16_t NoteFreq[]; static const uint16_t OpOffsets3[9][4]; static const bool AlgCarriers[7][4]; }; #endif