Files
sa2/include/lib/m4a/m4a_internal.h
T
JaceCearandOliver Bell 1f8bee518d Implement m4a for PC (#166)
* Refactor m4a for better names
* Bring in m4a PC backend code
* Update songs data to work on 64bit
* Move m4a to it's own folder
* Add linker map to sdl build

---------

Co-authored-by: Oliver Bell <freshollie@gmail.com>
2024-10-28 11:07:36 +00:00

469 lines
14 KiB
C

#ifndef GUARD_GBA_M4A_INTERNAL_H
#define GUARD_GBA_M4A_INTERNAL_H
#include "gba/gba.h"
// ASCII encoding of 'Smsh' in reverse
// This is presumably short for SMASH, the developer of MKS4AGB.
#define ID_NUMBER 0x68736D53
#define C_V 0x40 // center value for PAN, BEND, and TUNE
#define SOUND_MODE_REVERB_VAL 0x0000007F
#define SOUND_MODE_REVERB_SET 0x00000080
#define SOUND_MODE_MAXCHN 0x00000F00
#define SOUND_MODE_MAXCHN_SHIFT 8
#define SOUND_MODE_MASVOL 0x0000F000
#define SOUND_MODE_MASVOL_SHIFT 12
#define SOUND_MODE_FREQ_05734 0x00010000
#define SOUND_MODE_FREQ_07884 0x00020000
#define SOUND_MODE_FREQ_10512 0x00030000
#define SOUND_MODE_FREQ_13379 0x00040000
#define SOUND_MODE_FREQ_15768 0x00050000
#define SOUND_MODE_FREQ_18157 0x00060000
#define SOUND_MODE_FREQ_21024 0x00070000
#define SOUND_MODE_FREQ_26758 0x00080000
#define SOUND_MODE_FREQ_31536 0x00090000
#define SOUND_MODE_FREQ_36314 0x000A0000
#define SOUND_MODE_FREQ_40137 0x000B0000
#define SOUND_MODE_FREQ_42048 0x000C0000
#define SOUND_MODE_FREQ 0x000F0000
#define SOUND_MODE_FREQ_SHIFT 16
#define SOUND_MODE_DA_BIT_9 0x00800000
#define SOUND_MODE_DA_BIT_8 0x00900000
#define SOUND_MODE_DA_BIT_7 0x00A00000
#define SOUND_MODE_DA_BIT_6 0x00B00000
#define SOUND_MODE_DA_BIT 0x00B00000
#define SOUND_MODE_DA_BIT_SHIFT 20
#define DEFAULT_SOUND_MODE (SOUND_MODE_DA_BIT_8 | SOUND_MODE_FREQ_10512 | (15 << SOUND_MODE_MASVOL_SHIFT) | (5 << SOUND_MODE_MAXCHN_SHIFT))
#define TONEDATA_TYPE_CGB 0x07
#define TONEDATA_TYPE_FIX 0x08
#define TONEDATA_TYPE_SPL 0x40 // key split
#define TONEDATA_TYPE_RHY 0x80 // rhythm
#define TONEDATA_P_S_PAN 0xc0
#define TONEDATA_P_S_PAM TONEDATA_P_S_PAN
#define SOUND_CHANNEL_SF_START 0x80
#define SOUND_CHANNEL_SF_STOP 0x40
#define SOUND_CHANNEL_SF_LOOP 0x10
#define SOUND_CHANNEL_SF_IEC 0x04
#define SOUND_CHANNEL_SF_ENV 0x03
#define SOUND_CHANNEL_SF_ENV_ATTACK 0x03
#define SOUND_CHANNEL_SF_ENV_DECAY 0x02
#define SOUND_CHANNEL_SF_ENV_SUSTAIN 0x01
#define SOUND_CHANNEL_SF_ENV_RELEASE 0x00
#define SOUND_CHANNEL_SF_ON (SOUND_CHANNEL_SF_START | SOUND_CHANNEL_SF_STOP | SOUND_CHANNEL_SF_IEC | SOUND_CHANNEL_SF_ENV)
#define CGB_CHANNEL_MO_PIT 0x02
#define CGB_CHANNEL_MO_VOL 0x01
#define CGB_NRx2_ENV_DIR_DEC 0x00
#define CGB_NRx2_ENV_DIR_INC 0x08
#define MPT_FLG_VOLSET 0x01
#define MPT_FLG_VOLCHG 0x03
#define MPT_FLG_PITSET 0x04
#define MPT_FLG_PITCHG 0x0C
#define MPT_FLG_START 0x40
#define MPT_FLG_EXIST 0x80
#define MUSICPLAYER_STATUS_TRACK 0x0000ffff
#define MUSICPLAYER_STATUS_PAUSE 0x80000000
#define MAX_MUSICPLAYER_TRACKS 16
#define TRACKS_ALL 0xFFFF
#define TEMPORARY_FADE 0x0001
#define FADE_IN 0x0002
#define FADE_VOL_MAX 64
#define FADE_VOL_SHIFT 2
#define MAX_DIRECTSOUND_CHANNELS 12
#if PLATFORM_GBA
#define PCM_DMA_BUF_SIZE 1584 // size of Direct Sound buffer
#else
#define PCM_DMA_BUF_SIZE 4907 // size of Direct Sound buffer
#endif
#if PLATFORM_GBA
#define NUM_MUSIC_PLAYERS ((u16)gNumMusicPlayers)
#define MAX_LINES ((u32)gMaxLines)
#else
#define NUM_MUSIC_PLAYERS 4
#define MAX_LINES 0
#endif
struct MP2KTrack;
struct MP2KPlayerState;
typedef void (*MPlayFunc)();
typedef void (*MP2KEventNoteFunc)(u8, struct MP2KPlayerState *, struct MP2KTrack *);
typedef void (*MP2KEventFunc)(struct MP2KPlayerState *, struct MP2KTrack *);
typedef void (*CgbSoundFunc)(void);
typedef void (*CgbOscOffFunc)(u8);
typedef u32 (*MidiKeyToCgbFreqFunc)(u8, u8, u8);
typedef void (*ExtVolPitFunc)(void);
typedef void (*MPlayMainFunc)(struct MP2KPlayerState *);
struct MixerSource {
u8 status;
u8 type;
u8 rightVol;
u8 leftVol;
union {
struct {
u8 attack;
u8 decay;
u8 sustain;
u8 release;
u8 key;
u8 envelopeVol;
u8 envelopeGoal;
u8 envelopeCtr;
u8 echoVol;
u8 echoLen;
u8 padding1;
u8 padding2;
u8 gateTime;
u8 untransposedKey;
u8 velocity;
u8 priority;
u8 rhythmPan;
u8 padding3;
u8 padding4;
u8 padding5;
u8 padding6;
u8 sustainGoal;
u8 nrx4;
u8 pan;
u8 panMask;
u8 cgbStatus;
u8 length;
u8 sweep;
u32 freq;
} cgb;
struct {
u8 attack;
u8 decay;
u8 sustain;
u8 release;
u8 key;
u8 envelopeVol;
u8 envelopeVolR;
u8 envelopeVolL;
u8 echoVol;
u8 echoLen;
u8 padding1;
u8 padding2;
u8 gateTime;
u8 untransposedKey;
u8 velocity;
u8 priority;
u8 rhythmPan;
u8 padding3;
u8 padding4;
u8 padding5;
u32 ct;
float fw;
u32 freq;
} sound;
} data;
void *wav; // The next peice of data to be loading
void *current; // The working pointer from wav
struct MP2KTrack *track;
struct MixerSource *prev;
struct MixerSource *next;
u32 padding7; // d4
u32 blockCount; // bdpcm block count
};
struct SoundMixerState {
// This field is normally equal to ID_NUMBER but it is set to other
// values during sensitive operations for locking purposes.
u32 lockStatus;
vu8 dmaCounter;
// Direct Sound
u8 reverb;
u8 numChans;
u8 masterVol;
u8 freqOption;
u8 extensionFlags;
u8 cgbCounter15; // periodically counts from 14 down to 0 (15 states)
u8 framesPerDmaCycle; // number of V-blanks per PCM DMA
u8 maxScanlines;
u8 gap[3];
s32 samplesPerFrame;
s32 sampleRate;
#if PLATFORM_GBA
s32 sampleRateReciprocal;
#else
float sampleRateReciprocal;
#endif
struct MixerSource *cgbChans;
MPlayMainFunc MPlayMainHead;
struct MP2KPlayerState *musicPlayerHead;
CgbSoundFunc CgbSound;
CgbOscOffFunc CgbOscOff;
MidiKeyToCgbFreqFunc MidiKeyToCgbFreq;
MPlayFunc *MPlayJumpTable;
MP2KEventNoteFunc plynote;
ExtVolPitFunc ExtVolPit;
void *reserved2;
void *reserved3;
void *reversed4;
void *reserved5;
struct MixerSource chans[MAX_DIRECTSOUND_CHANNELS];
#if PLATFORM_GBA
s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2];
#else
float pcmBuffer[PCM_DMA_BUF_SIZE * 2];
#endif
};
struct MP2KVoiceGroup {
u8 type;
u8 drumKey;
u8 cgbLength;
u8 pan_sweep; // pan or sweep (compatible sound ch. 1)
union {
struct {
struct WaveData *wav;
u8 attack;
u8 decay;
u8 sustain;
u8 release;
} sound;
struct {
struct MP2KVoiceGroup *group;
u8 *keySplitTable;
} keySplit;
} data;
};
struct WaveData {
u16 type;
u16 status;
u32 freq;
u32 loopStart;
u32 size; // number of samples
s8 data[1]; // samples
};
struct MP2KSongHeader {
u8 trackCount;
u8 blockCount;
u8 priority;
u8 reverb;
struct MP2KVoiceGroup *voicegroup;
u8 *part[1];
};
struct MP2KTrack {
u8 status;
u8 wait;
u8 patternLevel;
u8 repeatCount;
u8 gateTime; // 0 if TIE
u8 key;
u8 velocity;
u8 runningStatus;
s8 keyShiftCalculated; // Calculated by TrkVolPitSet using fields below. Units: semitones
u8 pitchCalculated; // Calculated by TrkVolPitSet using fields below. Units: 256ths of a semitone
s8 keyShift; // Units: semitones
s8 keyShiftPublic; // Units: semitones
s8 tune; // Units: 64ths of a semitone
u8 pitchPublic; // Units: 256ths of a semitone
s8 bend; // Units: (bendRange / 64)ths of a semitone
u8 bendRange;
u8 volRightCalculated;
u8 volLeftCalculated;
u8 vol;
u8 volPublic; // Used both for fades and MPlayVolumeControl
s8 pan;
s8 panPublic;
s8 modCalculated; // Pitch units: 16ths of a semitone
u8 modDepth;
u8 modType;
u8 lfoSpeed;
u8 lfoSpeedCounter;
u8 lfoDelay;
u8 lfoDelayCounter;
u8 priority;
u8 echoVolume;
u8 echoLength;
struct MixerSource *chan;
struct MP2KVoiceGroup voicegroup;
u8 gap[10];
u16 unk_3A;
u32 unk_3C;
u8 *cmdPtr;
u8 *patternStack[3];
};
struct MP2KPlayerState {
struct MP2KSongHeader *songHeader;
u32 status;
u8 trackCount;
u8 priority;
u8 cmd;
bool8 checkSongPriority;
u32 clock;
u8 padding[8];
u8 *memAccArea;
u16 tempoRawBPM; // 150 initially... this doesn't seem right but whatever
u16 tempoScale; // 0x100 initially
u16 tempoInterval; // 150 initially
u16 tempoCounter;
u16 fadeInterval;
u16 fadeCounter;
u16 fadeOV;
struct MP2KTrack *tracks;
struct MP2KVoiceGroup *voicegroup;
u32 lockStatus;
MPlayMainFunc nextPlayerFunc;
struct MP2KPlayerState *nextPlayer;
};
struct MusicPlayer {
struct MP2KPlayerState *info;
struct MP2KTrack *track;
u8 numTracks;
u16 unk_A;
};
struct Song {
struct MP2KSongHeader *header;
u16 ms;
u16 me;
};
typedef void (*XcmdFunc)(struct MP2KPlayerState *, struct MP2KTrack *);
extern char SoundMainRAM[];
extern u8 gMPlayMemAccArea[];
extern MPlayFunc gMPlayJumpTable[];
extern struct MixerSource gCgbChans[];
extern const struct MusicPlayer gMPlayTable[];
extern const struct Song gSongTable[];
extern const XcmdFunc gXcmdTable[];
extern const u8 gClockTable[];
extern const u8 gScaleTable[];
extern const u32 gFreqTable[];
extern const u16 gPcmSamplesPerVBlankTable[];
extern void *const gMPlayJumpTableTemplate[];
extern const u8 gCgbScaleTable[];
extern const s16 gCgbFreqTable[];
extern const u8 gNoiseTable[];
extern const u8 gCgb3Vol[];
#if PLATFORM_GBA
extern char gNumMusicPlayers[];
extern char gMaxLines[];
#endif
u32 MidiKeyToFreq(struct WaveData *wav, u8 key, u8 fineAdjust);
u32 umul3232H32(u32 multiplier, u32 multiplicand);
void SoundMain(void);
void SoundMainBTM(void *ptr);
void TrackStop(struct MP2KPlayerState *player, struct MP2KTrack *track);
void MP2KPlayerMain(struct MP2KPlayerState *);
void ClearChain(struct MixerSource *chan);
void MP2KClearChain(struct MixerSource *chan);
void MPlayContinue(struct MP2KPlayerState *mplayInfo);
void MPlayStart(struct MP2KPlayerState *mplayInfo, struct MP2KSongHeader *songHeader);
void MPlayStop(struct MP2KPlayerState *mplayInfo);
void FadeOutBody(struct MP2KPlayerState *mplayInfo);
void TrkVolPitSet(struct MP2KPlayerState *mplayInfo, struct MP2KTrack *track);
void MPlayFadeOut(struct MP2KPlayerState *mplayInfo, u16 speed);
void Clear64byte(void *addr);
void SoundInit(struct SoundMixerState *soundInfo);
void MPlayExtender(struct MixerSource *cgbChans);
void m4aSoundMode(u32 mode);
void MPlayOpen(struct MP2KPlayerState *mplayInfo, struct MP2KTrack *tracks, u8 trackCount);
void CgbSound(void);
void CgbOscOff(u8);
void CgbModVol(struct MixerSource *chan);
u32 MidiKeyToCgbFreq(u8, u8, u8);
void MPlayJumpTableCopy(void **mplayJumpTable);
void SampleFreqSet(u32 freq);
void m4aSoundVSyncOn(void);
void m4aSoundVSyncOff(void);
void m4aMPlayTempoControl(struct MP2KPlayerState *mplayInfo, u16 tempo);
void m4aMPlayVolumeControl(struct MP2KPlayerState *mplayInfo, u16 trackBits, u16 volume);
void m4aMPlayPitchControl(struct MP2KPlayerState *mplayInfo, u16 trackBits, s16 pitch);
void m4aMPlayPanpotControl(struct MP2KPlayerState *mplayInfo, u16 trackBits, s8 pan);
void ClearModM(struct MP2KTrack *track);
void m4aMPlayModDepthSet(struct MP2KPlayerState *mplayInfo, u16 trackBits, u8 modDepth);
void m4aMPlayLFOSpeedSet(struct MP2KPlayerState *mplayInfo, u16 trackBits, u8 lfoSpeed);
// sound command handler functions
void MP2K_event_fine(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_goto(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_patt(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_pend(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_rept(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_memacc(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_prio(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_tempo(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_keysh(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_voice(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_vol(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_pan(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_bend(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_bendr(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_lfos(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_lfodl(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_mod(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_modt(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_tune(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_port(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xcmd(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_endtie(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_nxx(u8 clock, struct MP2KPlayerState *, struct MP2KTrack *);
// extended sound command handler functions
void MP2K_event_xxx(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xwave(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xtype(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xatta(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xdeca(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xsust(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xrele(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xiecv(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xiecl(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xleng(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xswee(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xcmd_0C(struct MP2KPlayerState *, struct MP2KTrack *);
void MP2K_event_xcmd_0D(struct MP2KPlayerState *, struct MP2KTrack *);
#endif // GUARD_GBA_M4A_INTERNAL_H