mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-17 20:17:38 +01:00
546 lines
12 KiB
C
546 lines
12 KiB
C
#include "gba/m4a_internal.h"
|
|
|
|
void m4aMPlayTempoControl(struct MusicPlayerInfo *mplayInfo, u16 tempo)
|
|
{
|
|
if (mplayInfo->ident == ID_NUMBER)
|
|
{
|
|
mplayInfo->ident++;
|
|
mplayInfo->tempoU = tempo;
|
|
mplayInfo->tempoI = (mplayInfo->tempoD * mplayInfo->tempoU) >> 8;
|
|
mplayInfo->ident = ID_NUMBER;
|
|
}
|
|
}
|
|
|
|
void m4aMPlayVolumeControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u16 volume)
|
|
{
|
|
s32 i;
|
|
u32 bit;
|
|
struct MusicPlayerTrack *track;
|
|
|
|
if (mplayInfo->ident != ID_NUMBER)
|
|
return;
|
|
|
|
mplayInfo->ident++;
|
|
|
|
i = mplayInfo->trackCount;
|
|
track = mplayInfo->tracks;
|
|
bit = 1;
|
|
|
|
while (i > 0)
|
|
{
|
|
if (trackBits & bit)
|
|
{
|
|
if (track->flags & MPT_FLG_EXIST)
|
|
{
|
|
track->volX = volume / 4;
|
|
track->flags |= MPT_FLG_VOLCHG;
|
|
}
|
|
}
|
|
|
|
i--;
|
|
track++;
|
|
bit <<= 1;
|
|
}
|
|
|
|
mplayInfo->ident = ID_NUMBER;
|
|
}
|
|
|
|
void m4aMPlayPitchControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u16 pitch)
|
|
{
|
|
s32 i;
|
|
u32 bit;
|
|
struct MusicPlayerTrack *track;
|
|
|
|
if (mplayInfo->ident != ID_NUMBER)
|
|
return;
|
|
|
|
mplayInfo->ident++;
|
|
|
|
i = mplayInfo->trackCount;
|
|
track = mplayInfo->tracks;
|
|
bit = 1;
|
|
|
|
while (i > 0)
|
|
{
|
|
if (trackBits & bit)
|
|
{
|
|
if (track->flags & MPT_FLG_EXIST)
|
|
{
|
|
track->keyShiftX = (s16)pitch >> 8;
|
|
track->pitX = pitch;
|
|
track->flags |= MPT_FLG_PITCHG;
|
|
}
|
|
}
|
|
|
|
i--;
|
|
track++;
|
|
bit <<= 1;
|
|
}
|
|
|
|
mplayInfo->ident = ID_NUMBER;
|
|
}
|
|
|
|
void m4aMPlayPanpotControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s8 pan)
|
|
{
|
|
s32 i;
|
|
u32 bit;
|
|
struct MusicPlayerTrack *track;
|
|
|
|
if (mplayInfo->ident != ID_NUMBER)
|
|
return;
|
|
|
|
mplayInfo->ident++;
|
|
|
|
i = mplayInfo->trackCount;
|
|
track = mplayInfo->tracks;
|
|
bit = 1;
|
|
|
|
while (i > 0)
|
|
{
|
|
if (trackBits & bit)
|
|
{
|
|
if (track->flags & MPT_FLG_EXIST)
|
|
{
|
|
track->panX = pan;
|
|
track->flags |= MPT_FLG_VOLCHG;
|
|
}
|
|
}
|
|
|
|
i--;
|
|
track++;
|
|
bit <<= 1;
|
|
}
|
|
|
|
mplayInfo->ident = ID_NUMBER;
|
|
}
|
|
|
|
void ClearModM(struct MusicPlayerTrack *track)
|
|
{
|
|
track->lfoSpeedC = 0;
|
|
track->modM = 0;
|
|
|
|
if (track->modT == 0)
|
|
track->flags |= MPT_FLG_PITCHG;
|
|
else
|
|
track->flags |= MPT_FLG_VOLCHG;
|
|
}
|
|
|
|
void m4aMPlayModDepthSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 modDepth)
|
|
{
|
|
s32 i;
|
|
u32 bit;
|
|
struct MusicPlayerTrack *track;
|
|
|
|
if (mplayInfo->ident != ID_NUMBER)
|
|
return;
|
|
|
|
mplayInfo->ident++;
|
|
|
|
i = mplayInfo->trackCount;
|
|
track = mplayInfo->tracks;
|
|
bit = 1;
|
|
|
|
while (i > 0)
|
|
{
|
|
if (trackBits & bit)
|
|
{
|
|
if (track->flags & MPT_FLG_EXIST)
|
|
{
|
|
track->mod = modDepth;
|
|
|
|
if (!track->mod)
|
|
ClearModM(track);
|
|
}
|
|
}
|
|
|
|
i--;
|
|
track++;
|
|
bit <<= 1;
|
|
}
|
|
|
|
mplayInfo->ident = ID_NUMBER;
|
|
}
|
|
|
|
void m4aMPlayLFOSpeedSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 lfoSpeed)
|
|
{
|
|
s32 i;
|
|
u32 bit;
|
|
struct MusicPlayerTrack *track;
|
|
|
|
if (mplayInfo->ident != ID_NUMBER)
|
|
return;
|
|
|
|
mplayInfo->ident++;
|
|
|
|
i = mplayInfo->trackCount;
|
|
track = mplayInfo->tracks;
|
|
bit = 1;
|
|
|
|
while (i > 0)
|
|
{
|
|
if (trackBits & bit)
|
|
{
|
|
if (track->flags & MPT_FLG_EXIST)
|
|
{
|
|
track->lfoSpeed = lfoSpeed;
|
|
|
|
if (!track->lfoSpeed)
|
|
ClearModM(track);
|
|
}
|
|
}
|
|
|
|
i--;
|
|
track++;
|
|
bit <<= 1;
|
|
}
|
|
|
|
mplayInfo->ident = ID_NUMBER;
|
|
}
|
|
|
|
#define MEMACC_COND_JUMP(cond) \
|
|
if (cond) \
|
|
goto cond_true; \
|
|
else \
|
|
goto cond_false; \
|
|
|
|
void ply_memacc(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
u32 op;
|
|
u8 *addr;
|
|
u8 data;
|
|
|
|
op = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
|
|
addr = mplayInfo->memAccArea + *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
|
|
data = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
|
|
switch (op)
|
|
{
|
|
case 0:
|
|
*addr = data;
|
|
return;
|
|
case 1:
|
|
*addr += data;
|
|
return;
|
|
case 2:
|
|
*addr -= data;
|
|
return;
|
|
case 3:
|
|
*addr = mplayInfo->memAccArea[data];
|
|
return;
|
|
case 4:
|
|
*addr += mplayInfo->memAccArea[data];
|
|
return;
|
|
case 5:
|
|
*addr -= mplayInfo->memAccArea[data];
|
|
return;
|
|
case 6:
|
|
MEMACC_COND_JUMP(*addr == data)
|
|
return;
|
|
case 7:
|
|
MEMACC_COND_JUMP(*addr != data)
|
|
return;
|
|
case 8:
|
|
MEMACC_COND_JUMP(*addr > data)
|
|
return;
|
|
case 9:
|
|
MEMACC_COND_JUMP(*addr >= data)
|
|
return;
|
|
case 10:
|
|
MEMACC_COND_JUMP(*addr <= data)
|
|
return;
|
|
case 11:
|
|
MEMACC_COND_JUMP(*addr < data)
|
|
return;
|
|
case 12:
|
|
MEMACC_COND_JUMP(*addr == mplayInfo->memAccArea[data])
|
|
return;
|
|
case 13:
|
|
MEMACC_COND_JUMP(*addr != mplayInfo->memAccArea[data])
|
|
return;
|
|
case 14:
|
|
MEMACC_COND_JUMP(*addr > mplayInfo->memAccArea[data])
|
|
return;
|
|
case 15:
|
|
MEMACC_COND_JUMP(*addr >= mplayInfo->memAccArea[data])
|
|
return;
|
|
case 16:
|
|
MEMACC_COND_JUMP(*addr <= mplayInfo->memAccArea[data])
|
|
return;
|
|
case 17:
|
|
MEMACC_COND_JUMP(*addr < mplayInfo->memAccArea[data])
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
cond_true:
|
|
{
|
|
void (*func)(struct MusicPlayerInfo *, struct MusicPlayerTrack *) = *(&gMPlayJumpTable[1]);
|
|
func(mplayInfo, track);
|
|
return;
|
|
}
|
|
|
|
cond_false:
|
|
track->cmdPtr += 4;
|
|
}
|
|
|
|
void ply_xcmd(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
u32 n = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
|
|
gXcmdTable[n](mplayInfo, track);
|
|
}
|
|
|
|
void ply_xxx(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
void (*func)(struct MusicPlayerInfo *, struct MusicPlayerTrack *) = *(&gMPlayJumpTable[0]);
|
|
func(mplayInfo, track);
|
|
}
|
|
|
|
#define READ_XCMD_BYTE(var, n) \
|
|
{ \
|
|
u32 byte = track->cmdPtr[(n)]; \
|
|
byte <<= n * 8; \
|
|
(var) &= ~(0xFF << (n * 8)); \
|
|
(var) |= byte; \
|
|
}
|
|
|
|
void ply_xwave(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
u32 wav;
|
|
|
|
READ_XCMD_BYTE(wav, 0) // UB: uninitialized variable
|
|
READ_XCMD_BYTE(wav, 1)
|
|
READ_XCMD_BYTE(wav, 2)
|
|
READ_XCMD_BYTE(wav, 3)
|
|
|
|
track->tone.wav = (struct WaveData *)wav;
|
|
track->cmdPtr += 4;
|
|
}
|
|
|
|
void ply_xtype(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->tone.type = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xatta(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->tone.attack = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xdeca(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->tone.decay = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xsust(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->tone.sustain = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xrele(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->tone.release = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xiecv(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->echoVolume = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xiecl(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->echoLength = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xleng(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->tone.length = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xswee(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
track->tone.pan_sweep = *track->cmdPtr;
|
|
track->cmdPtr++;
|
|
}
|
|
|
|
void ply_xcmd_0C(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
u32 unk;
|
|
|
|
READ_XCMD_BYTE(unk, 0) // UB: uninitialized variable
|
|
READ_XCMD_BYTE(unk, 1)
|
|
|
|
if (track->unk_3A < (u16)unk)
|
|
{
|
|
track->unk_3A++;
|
|
track->cmdPtr -= 2;
|
|
track->wait = 1;
|
|
}
|
|
else
|
|
{
|
|
track->unk_3A = 0;
|
|
track->cmdPtr += 2;
|
|
}
|
|
}
|
|
|
|
void ply_xcmd_0D(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
|
|
{
|
|
u32 unk;
|
|
|
|
READ_XCMD_BYTE(unk, 0) // UB: uninitialized variable
|
|
READ_XCMD_BYTE(unk, 1)
|
|
READ_XCMD_BYTE(unk, 2)
|
|
READ_XCMD_BYTE(unk, 3)
|
|
|
|
track->unk_3C = unk;
|
|
track->cmdPtr += 4;
|
|
}
|
|
|
|
void DummyFunc(void)
|
|
{
|
|
}
|
|
|
|
struct MusicPlayerInfo *SetPokemonCryTone(struct ToneData *tone)
|
|
{
|
|
u32 maxClock = 0;
|
|
s32 maxClockIndex = 0;
|
|
s32 i;
|
|
struct MusicPlayerInfo *mplayInfo;
|
|
|
|
for (i = 0; i < MAX_POKEMON_CRIES; i++)
|
|
{
|
|
struct MusicPlayerTrack *track = &gPokemonCryTracks[i * 2];
|
|
|
|
if (!track->flags && (!track->chan || track->chan->track != track))
|
|
goto start_song;
|
|
|
|
if (maxClock < gPokemonCryMusicPlayers[i].clock)
|
|
{
|
|
maxClock = gPokemonCryMusicPlayers[i].clock;
|
|
maxClockIndex = i;
|
|
}
|
|
}
|
|
|
|
i = maxClockIndex;
|
|
|
|
start_song:
|
|
mplayInfo = &gPokemonCryMusicPlayers[i];
|
|
mplayInfo->ident++;
|
|
|
|
#define CRY ((s32)&gPokemonCrySongs + i * sizeof(struct PokemonCrySong))
|
|
#define CRY_OFS(field) offsetof(struct PokemonCrySong, field)
|
|
|
|
memcpy((void *)CRY, &gPokemonCrySong, sizeof(struct PokemonCrySong));
|
|
|
|
*(u32 *)(CRY + CRY_OFS(tone)) = (u32)tone;
|
|
*(u32 *)(CRY + CRY_OFS(part)) = CRY + CRY_OFS(part0);
|
|
*(u32 *)(CRY + CRY_OFS(part) + 4) = CRY + CRY_OFS(part1);
|
|
*(u32 *)(CRY + CRY_OFS(gotoTarget)) = CRY + CRY_OFS(cont);
|
|
|
|
#undef CRY_OFS
|
|
#undef CRY
|
|
|
|
mplayInfo->ident = ID_NUMBER;
|
|
|
|
MPlayStart(mplayInfo, (struct SongHeader *)(&gPokemonCrySongs[i]));
|
|
|
|
return mplayInfo;
|
|
}
|
|
|
|
void SetPokemonCryVolume(u8 val)
|
|
{
|
|
gPokemonCrySong.volumeValue = val & 0x7F;
|
|
}
|
|
|
|
void SetPokemonCryPanpot(s8 val)
|
|
{
|
|
gPokemonCrySong.panValue = (val + C_V) & 0x7F;
|
|
}
|
|
|
|
void SetPokemonCryPitch(s16 val)
|
|
{
|
|
s16 b = val + 0x80;
|
|
u8 a = gPokemonCrySong.tuneValue2 - gPokemonCrySong.tuneValue;
|
|
gPokemonCrySong.tieKeyValue = (b >> 8) & 0x7F;
|
|
gPokemonCrySong.tuneValue = (b >> 1) & 0x7F;
|
|
gPokemonCrySong.tuneValue2 = (a + ((b >> 1) & 0x7F)) & 0x7F;
|
|
}
|
|
|
|
void SetPokemonCryLength(u16 val)
|
|
{
|
|
gPokemonCrySong.unkCmd0CParam = val;
|
|
}
|
|
|
|
void SetPokemonCryRelease(u8 val)
|
|
{
|
|
gPokemonCrySong.releaseValue = val;
|
|
}
|
|
|
|
void SetPokemonCryProgress(u32 val)
|
|
{
|
|
gPokemonCrySong.unkCmd0DParam = val;
|
|
}
|
|
|
|
int IsPokemonCryPlaying(struct MusicPlayerInfo *mplayInfo)
|
|
{
|
|
struct MusicPlayerTrack *track = mplayInfo->tracks;
|
|
|
|
if (track->chan && track->chan->track == track)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void SetPokemonCryChorus(s8 val)
|
|
{
|
|
if (val)
|
|
{
|
|
gPokemonCrySong.trackCount = 2;
|
|
gPokemonCrySong.tuneValue2 = (val + gPokemonCrySong.tuneValue) & 0x7F;
|
|
}
|
|
else
|
|
{
|
|
gPokemonCrySong.trackCount = 1;
|
|
}
|
|
}
|
|
|
|
void SetPokemonCryStereo(u32 val)
|
|
{
|
|
struct SoundInfo *soundInfo = SOUND_INFO_PTR;
|
|
|
|
if (val)
|
|
{
|
|
REG_SOUNDCNT_H = SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT
|
|
| SOUND_A_TIMER_0 | SOUND_A_RIGHT_OUTPUT
|
|
| SOUND_ALL_MIX_FULL;
|
|
soundInfo->mode &= ~1;
|
|
}
|
|
else
|
|
{
|
|
REG_SOUNDCNT_H = SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT | SOUND_B_RIGHT_OUTPUT
|
|
| SOUND_A_TIMER_0 | SOUND_A_LEFT_OUTPUT | SOUND_A_RIGHT_OUTPUT
|
|
| SOUND_B_MIX_HALF | SOUND_A_MIX_HALF | SOUND_CGB_MIX_FULL;
|
|
soundInfo->mode |= 1;
|
|
}
|
|
}
|
|
|
|
void SetPokemonCryPriority(u8 val)
|
|
{
|
|
gPokemonCrySong.priority = val;
|
|
}
|