mirror of
https://github.com/sonicdcer/sf64.git
synced 2024-11-26 22:40:42 +00:00
Improve audio docs and partial audio disassembly support (#268)
* audiodiasm * start of sound disasm * disasm * source
This commit is contained in:
parent
9dd58cd924
commit
83c5442915
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,6 +18,7 @@ ctx.c.m2c
|
|||||||
*.otr
|
*.otr
|
||||||
*.eeprom
|
*.eeprom
|
||||||
assets/yaml/us/ast_test.yaml
|
assets/yaml/us/ast_test.yaml
|
||||||
|
/audio_data
|
||||||
src/assets/*
|
src/assets/*
|
||||||
include/assets/*
|
include/assets/*
|
||||||
/build
|
/build
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#define ALIGN64(val) (((val) + 0x3F) & ~0x3F)
|
#define ALIGN64(val) (((val) + 0x3F) & ~0x3F)
|
||||||
#define ALIGN256(val) (((val) + 0xFF) & ~0xFF)
|
#define ALIGN256(val) (((val) + 0xFF) & ~0xFF)
|
||||||
|
|
||||||
|
#define ALIGN16_ALT(val) (((val) & ~0xF) + 0x10)
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define ALIGNED8 __attribute__ ((aligned (8)))
|
#define ALIGNED8 __attribute__ ((aligned (8)))
|
||||||
#else
|
#else
|
||||||
|
@ -9,7 +9,8 @@ typedef enum {
|
|||||||
/* 0 */ SEQ_PLAYER_BGM,
|
/* 0 */ SEQ_PLAYER_BGM,
|
||||||
/* 1 */ SEQ_PLAYER_FANFARE,
|
/* 1 */ SEQ_PLAYER_FANFARE,
|
||||||
/* 2 */ SEQ_PLAYER_SFX,
|
/* 2 */ SEQ_PLAYER_SFX,
|
||||||
/* 3 */ SEQ_PLAYER_VOICE
|
/* 3 */ SEQ_PLAYER_VOICE,
|
||||||
|
/* 4 */ SEQ_PLAYER_MAX,
|
||||||
} SequencePlayerId;
|
} SequencePlayerId;
|
||||||
|
|
||||||
// ==== Primary commands ====
|
// ==== Primary commands ====
|
||||||
|
@ -42,7 +42,9 @@ typedef enum {
|
|||||||
/* 0x81 */ AUDIOCMD_OP_GLOBAL_SYNC_LOAD_SEQ_PARTS = 0x81,
|
/* 0x81 */ AUDIOCMD_OP_GLOBAL_SYNC_LOAD_SEQ_PARTS = 0x81,
|
||||||
/* 0x82 */ AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER,
|
/* 0x82 */ AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER,
|
||||||
/* 0x83 */ AUDIOCMD_OP_GLOBAL_DISABLE_SEQPLAYER,
|
/* 0x83 */ AUDIOCMD_OP_GLOBAL_DISABLE_SEQPLAYER,
|
||||||
/* 0x85 */ AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER_SKIP_TICKS = 0x85,
|
/* 0x84 */ AUDIOCMD_OP_GLOBAL_UNK_84,
|
||||||
|
/* 0x85 */ AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER_SKIP_TICKS,
|
||||||
|
/* 0x88 */ AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER_ALT = 0x88,
|
||||||
/* 0x90 */ AUDIOCMD_OP_GLOBAL_SET_CHANNEL_MASK = 0x90,
|
/* 0x90 */ AUDIOCMD_OP_GLOBAL_SET_CHANNEL_MASK = 0x90,
|
||||||
/* 0xE0 */ AUDIOCMD_OP_GLOBAL_SET_DRUM_FONT = 0xE0,
|
/* 0xE0 */ AUDIOCMD_OP_GLOBAL_SET_DRUM_FONT = 0xE0,
|
||||||
/* 0xE1 */ AUDIOCMD_OP_GLOBAL_SET_SFX_FONT,
|
/* 0xE1 */ AUDIOCMD_OP_GLOBAL_SET_SFX_FONT,
|
||||||
@ -410,7 +412,7 @@ typedef enum {
|
|||||||
/**
|
/**
|
||||||
* Pop the persistent cache of the specified table
|
* Pop the persistent cache of the specified table
|
||||||
*
|
*
|
||||||
* @param tableType (s32) see the `SampleBankTableType` enum
|
* @param tableType (s32) see the `AudioTableType` enum
|
||||||
*/
|
*/
|
||||||
#define AUDIOCMD_GLOBAL_POP_PERSISTENT_CACHE(tableType) \
|
#define AUDIOCMD_GLOBAL_POP_PERSISTENT_CACHE(tableType) \
|
||||||
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_POP_PERSISTENT_CACHE, 0, 0, 0), tableType)
|
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_POP_PERSISTENT_CACHE, 0, 0, 0), tableType)
|
||||||
|
@ -70,6 +70,9 @@ typedef void (*AudioCustomUpdateFunction)(void);
|
|||||||
|
|
||||||
#define AUDIO_RELOCATED_ADDRESS_START K0BASE
|
#define AUDIO_RELOCATED_ADDRESS_START K0BASE
|
||||||
|
|
||||||
|
#define AUDIOLOAD_SYNC 0
|
||||||
|
#define AUDIOLOAD_ASYNC 1
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* 0 */ ADSR_STATE_DISABLED,
|
/* 0 */ ADSR_STATE_DISABLED,
|
||||||
/* 1 */ ADSR_STATE_INITIAL,
|
/* 1 */ ADSR_STATE_INITIAL,
|
||||||
@ -98,11 +101,22 @@ typedef enum {
|
|||||||
/* 5 */ CODEC_S16
|
/* 5 */ CODEC_S16
|
||||||
} SampleCodec;
|
} SampleCodec;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* 0 */ SAMPLES_SFX,
|
||||||
|
/* 1 */ SAMPLES_MAP,
|
||||||
|
/* 2 */ SAMPLES_VOICE,
|
||||||
|
/* 3 */ SAMPLES_INST,
|
||||||
|
/* 4 */ SAMPLES_MAX,
|
||||||
|
/* -1 */ SAMPLES_NONE = 255,
|
||||||
|
} SampleBank;
|
||||||
|
|
||||||
|
#define SAMPLES_NONE_U 255U
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* 0 */ SEQUENCE_TABLE,
|
/* 0 */ SEQUENCE_TABLE,
|
||||||
/* 1 */ FONT_TABLE,
|
/* 1 */ FONT_TABLE,
|
||||||
/* 2 */ SAMPLE_TABLE
|
/* 2 */ SAMPLE_TABLE
|
||||||
} SampleBankTableType;
|
} AudioTableType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* 0 */ CACHE_TEMPORARY,
|
/* 0 */ CACHE_TEMPORARY,
|
||||||
@ -111,6 +125,14 @@ typedef enum {
|
|||||||
/* 3 */ CACHE_PERMANENT
|
/* 3 */ CACHE_PERMANENT
|
||||||
} AudioCacheType;
|
} AudioCacheType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* 0 */ CACHEPOLICY_0,
|
||||||
|
/* 1 */ CACHEPOLICY_1,
|
||||||
|
/* 2 */ CACHEPOLICY_2,
|
||||||
|
/* 3 */ CACHEPOLICY_3,
|
||||||
|
/* 4 */ CACHEPOLICY_4,
|
||||||
|
} AudioCachePolicy;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* 0 */ LOAD_STATUS_NOT_LOADED, // the entry data is not loaded
|
/* 0 */ LOAD_STATUS_NOT_LOADED, // the entry data is not loaded
|
||||||
/* 1 */ LOAD_STATUS_IN_PROGRESS, // the entry data is being loaded asynchronously
|
/* 1 */ LOAD_STATUS_IN_PROGRESS, // the entry data is being loaded asynchronously
|
||||||
@ -122,6 +144,20 @@ typedef enum {
|
|||||||
/* 5 */ LOAD_STATUS_PERMANENTLY_LOADED // the entry data is loaded in the permanent pool, it won't be discarded
|
/* 5 */ LOAD_STATUS_PERMANENTLY_LOADED // the entry data is loaded in the permanent pool, it won't be discarded
|
||||||
} AudioLoadStatus;
|
} AudioLoadStatus;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* 0 */ SLOW_LOAD_WAITING,
|
||||||
|
/* 1 */ SLOW_LOAD_START,
|
||||||
|
/* 2 */ SLOW_LOAD_LOADING,
|
||||||
|
/* 3 */ SLOW_LOAD_DONE
|
||||||
|
} SlowLoadState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* 0 */ SLOW_LOAD_STATUS_0,
|
||||||
|
/* 1 */ SLOW_LOAD_STATUS_1,
|
||||||
|
/* 2 */ SLOW_LOAD_STATUS_2,
|
||||||
|
/* 3 */ SLOW_LOAD_STATUS_3
|
||||||
|
} SlowLoadStatus;
|
||||||
|
|
||||||
typedef enum AudioResetStatus {
|
typedef enum AudioResetStatus {
|
||||||
/* 0 */ AUDIORESET_READY,
|
/* 0 */ AUDIORESET_READY,
|
||||||
/* 1 */ AUDIORESET_WAIT,
|
/* 1 */ AUDIORESET_WAIT,
|
||||||
@ -321,7 +357,7 @@ typedef struct {
|
|||||||
/* 0x02C */ f32 fadeVolumeMod;
|
/* 0x02C */ f32 fadeVolumeMod;
|
||||||
/* 0x030 */ f32 appliedFadeVolume;
|
/* 0x030 */ f32 appliedFadeVolume;
|
||||||
// /* 0x034 */ f32 bend;
|
// /* 0x034 */ f32 bend;
|
||||||
/* 0x034 */ struct SequenceChannel* channels[16];
|
/* 0x034 */ struct SequenceChannel* channels[SEQ_NUM_CHANNELS];
|
||||||
/* 0x074 */ SeqScriptState scriptState;
|
/* 0x074 */ SeqScriptState scriptState;
|
||||||
/* 0x090 */ u8* shortNoteVelocityTable;
|
/* 0x090 */ u8* shortNoteVelocityTable;
|
||||||
/* 0x094 */ u8* shortNoteGateTimeTable;
|
/* 0x094 */ u8* shortNoteGateTimeTable;
|
||||||
@ -794,6 +830,13 @@ typedef struct {
|
|||||||
/* 0x0E */ s16 shortData3;
|
/* 0x0E */ s16 shortData3;
|
||||||
} AudioTableEntry; // size = 0x10
|
} AudioTableEntry; // size = 0x10
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* 0x00 */ s16 numEntries;
|
||||||
|
/* 0x02 */ s16 unkMediumParam;
|
||||||
|
/* 0x04 */ u32 romAddr;
|
||||||
|
/* 0x08 */ char pad[0x8];
|
||||||
|
} AudioTableBase;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x00 */ s16 numEntries;
|
/* 0x00 */ s16 numEntries;
|
||||||
/* 0x02 */ s16 unkMediumParam;
|
/* 0x02 */ s16 unkMediumParam;
|
||||||
@ -1000,7 +1043,7 @@ void* AudioHeap_Alloc(AudioAllocPool* pool, u32 size);
|
|||||||
void AudioHeap_InitPool(AudioAllocPool* pool, void* ramAddr, u32 size);
|
void AudioHeap_InitPool(AudioAllocPool* pool, void* ramAddr, u32 size);
|
||||||
void AudioHeap_InitMainPools(s32 initPoolSize);
|
void AudioHeap_InitMainPools(s32 initPoolSize);
|
||||||
void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id);
|
void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id);
|
||||||
s32 AudioHeap_SearchCaches(s32 tableType, s32 cache, s32 id);
|
void* AudioHeap_SearchCaches(s32 tableType, s32 cache, s32 id);
|
||||||
s32 AudioHeap_ResetStep(void);
|
s32 AudioHeap_ResetStep(void);
|
||||||
void* AudioHeap_SearchPermanentCache(s32 tableType, s32 id);
|
void* AudioHeap_SearchPermanentCache(s32 tableType, s32 id);
|
||||||
u8* AudioHeap_AllocPermanent(s32 tableType, s32 id, u32 size);
|
u8* AudioHeap_AllocPermanent(s32 tableType, s32 id, u32 size);
|
||||||
@ -1054,11 +1097,11 @@ bool AudioThread_ResetComplete(void);
|
|||||||
void AudioThread_ResetAudioHeap(s32);
|
void AudioThread_ResetAudioHeap(s32);
|
||||||
void AudioThread_Init(void);
|
void AudioThread_Init(void);
|
||||||
|
|
||||||
extern AudioTable gSampleBankTableInit;
|
extern AudioTableBase gSampleBankTableInit;
|
||||||
// extern AudioTableEntry gSampleBankTableInitEntries[];
|
// extern AudioTableEntry gSampleBankTableInitEntries[];
|
||||||
extern AudioTable gSeqTableInit;
|
extern AudioTableBase gSeqTableInit;
|
||||||
// extern AudioTableEntry gSeqTableInitEntries[];
|
// extern AudioTableEntry gSeqTableInitEntries[];
|
||||||
extern AudioTable gSoundFontTableInit;
|
extern AudioTableBase gSoundFontTableInit;
|
||||||
// extern AudioTableEntry gSoundFontTableInitEntries[];
|
// extern AudioTableEntry gSoundFontTableInitEntries[];
|
||||||
extern u8 gSeqFontTableInit[];
|
extern u8 gSeqFontTableInit[];
|
||||||
|
|
||||||
@ -1104,7 +1147,7 @@ extern AudioCommonPoolSplit gTemporaryCommonPoolSplit;
|
|||||||
extern u8 gSampleFontLoadStatus[64];
|
extern u8 gSampleFontLoadStatus[64];
|
||||||
extern u8 gFontLoadStatus[64];
|
extern u8 gFontLoadStatus[64];
|
||||||
extern u8 gSeqLoadStatus[256];
|
extern u8 gSeqLoadStatus[256];
|
||||||
extern volatile u8 gResetStatus;
|
extern volatile u8 gAudioResetStep;
|
||||||
extern u8 gAudioSpecId;
|
extern u8 gAudioSpecId;
|
||||||
extern s32 gResetFadeoutFramesLeft;
|
extern s32 gResetFadeoutFramesLeft;
|
||||||
extern u8 sAudioContextPad1000[0x1000];// 0x1000 gap
|
extern u8 sAudioContextPad1000[0x1000];// 0x1000 gap
|
||||||
@ -1170,7 +1213,7 @@ extern s16* gAiBuffers[3];
|
|||||||
extern s16 gAiBuffLengths[3];
|
extern s16 gAiBuffLengths[3];
|
||||||
extern u32 gAudioRandom;
|
extern u32 gAudioRandom;
|
||||||
extern u32 D_80155D88;
|
extern u32 D_80155D88;
|
||||||
extern volatile u32 gResetTimer;
|
extern volatile u32 gAudioResetTimer;
|
||||||
|
|
||||||
extern u64 gAudioContextEnd[];
|
extern u64 gAudioContextEnd[];
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ D_80160000 = 0x80160000;//ignore:true
|
|||||||
D_800D0000 = 0x800D0000;//ignore:true
|
D_800D0000 = 0x800D0000;//ignore:true
|
||||||
D_7FFFFFFE = 0x7FFFFFFE;//ignore:true
|
D_7FFFFFFE = 0x7FFFFFFE;//ignore:true
|
||||||
D_1000000 = 0x01000000;//ignore:true
|
D_1000000 = 0x01000000;//ignore:true
|
||||||
|
D_01000100 = 0x01000100;//ignore:true
|
||||||
|
D_01010100 = 0x01010100;//ignore:true
|
||||||
|
|
||||||
// mirage symbols
|
// mirage symbols
|
||||||
D_A000000 = 0x0A000000;//ignore:true
|
D_A000000 = 0x0A000000;//ignore:true
|
||||||
@ -134,12 +136,8 @@ Save_Read = 0x800C3194;
|
|||||||
sOvlUnused_Unk = 0x800CBD3C;
|
sOvlUnused_Unk = 0x800CBD3C;
|
||||||
|
|
||||||
// hardcoded address used in sys_rdram
|
// hardcoded address used in sys_rdram
|
||||||
D_A0300000 = 0xA0300000;
|
D_A0300000 = 0xA0300000; // ignore:true
|
||||||
|
D_A4000000 = 0xA4000000; // ignore:true
|
||||||
//hardware addresses. should probably be in hardware_regs
|
|
||||||
D_A4000000 = 0xA4000000;
|
|
||||||
D_A5000508 = 0xA5000508;
|
|
||||||
D_A5000510 = 0xA5000510;
|
|
||||||
|
|
||||||
D_edisplay_800CFA54 = 0x800CFA54;
|
D_edisplay_800CFA54 = 0x800CFA54;
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ gTemporaryCommonPoolSplit = 0x8014D398;//size:0xC
|
|||||||
gSampleFontLoadStatus = 0x8014D3A8;//size:0x40
|
gSampleFontLoadStatus = 0x8014D3A8;//size:0x40
|
||||||
gFontLoadStatus = 0x8014D3E8;//size:0x40
|
gFontLoadStatus = 0x8014D3E8;//size:0x40
|
||||||
gSeqLoadStatus = 0x8014D428;//size:0x100
|
gSeqLoadStatus = 0x8014D428;//size:0x100
|
||||||
gResetStatus = 0x8014D528;
|
gAudioResetStep = 0x8014D528;
|
||||||
gAudioSpecId = 0x8014D529;
|
gAudioSpecId = 0x8014D529;
|
||||||
gResetFadeoutFramesLeft = 0x8014D52C;
|
gResetFadeoutFramesLeft = 0x8014D52C;
|
||||||
gNotes = 0x8014E530;
|
gNotes = 0x8014E530;
|
||||||
@ -207,7 +207,7 @@ gAiBuffers = 0x80155D70;//size:0xC
|
|||||||
gAiBuffLengths = 0x80155D7C;//size:0x8
|
gAiBuffLengths = 0x80155D7C;//size:0x8
|
||||||
gAudioRandom = 0x80155D84;
|
gAudioRandom = 0x80155D84;
|
||||||
D_80155D88 = 0x80155D88;
|
D_80155D88 = 0x80155D88;
|
||||||
gResetTimer = 0x80155D8C;
|
gAudioResetTimer = 0x80155D8C;
|
||||||
gAudioContextEnd = 0x80155D90;//size:0x10
|
gAudioContextEnd = 0x80155D90;//size:0x10
|
||||||
|
|
||||||
sAudioTaskStartQueue = 0x80155DA0;
|
sAudioTaskStartQueue = 0x80155DA0;
|
||||||
|
@ -33,11 +33,3 @@
|
|||||||
// func_84001728 = 0x84001728;
|
// func_84001728 = 0x84001728;
|
||||||
// func_840017D8 = 0x840017D8;
|
// func_840017D8 = 0x840017D8;
|
||||||
// func_840017AC = 0x840017AC;
|
// func_840017AC = 0x840017AC;
|
||||||
|
|
||||||
D_A0300000 = 0xA0300000;
|
|
||||||
D_A4000000 = 0xA4000000;
|
|
||||||
D_A5000508 = 0xA5000508;
|
|
||||||
D_A5000510 = 0xA5000510;
|
|
||||||
|
|
||||||
D_01000100 = 0x01000100;
|
|
||||||
D_01010100 = 0x01010100;
|
|
||||||
|
@ -34,13 +34,13 @@ AudioCommonPoolSplit gTemporaryCommonPoolSplit;
|
|||||||
u8 gSampleFontLoadStatus[64];
|
u8 gSampleFontLoadStatus[64];
|
||||||
u8 gFontLoadStatus[64];
|
u8 gFontLoadStatus[64];
|
||||||
u8 gSeqLoadStatus[256];
|
u8 gSeqLoadStatus[256];
|
||||||
volatile u8 gResetStatus;
|
volatile u8 gAudioResetStep;
|
||||||
u8 gAudioSpecId;
|
u8 gAudioSpecId;
|
||||||
s32 gResetFadeoutFramesLeft;
|
s32 gResetFadeoutFramesLeft;
|
||||||
u8 sAudioContextPad1000[0x1000]; // 0x1000 gap
|
u8 sAudioContextPad1000[0x1000]; // 0x1000 gap
|
||||||
Note* gNotes;
|
Note* gNotes;
|
||||||
// 0x4
|
// 0x4
|
||||||
SequencePlayer gSeqPlayers[4];
|
SequencePlayer gSeqPlayers[SEQ_PLAYER_MAX];
|
||||||
SequenceChannel gSeqChannels[48];
|
SequenceChannel gSeqChannels[48];
|
||||||
SequenceLayer gSeqLayers[64];
|
SequenceLayer gSeqLayers[64];
|
||||||
SequenceChannel gSeqChannelNone;
|
SequenceChannel gSeqChannelNone;
|
||||||
@ -100,7 +100,7 @@ s16* gAiBuffers[3];
|
|||||||
s16 gAiBuffLengths[3];
|
s16 gAiBuffLengths[3];
|
||||||
u32 gAudioRandom;
|
u32 gAudioRandom;
|
||||||
u32 D_80155D88;
|
u32 D_80155D88;
|
||||||
volatile u32 gResetTimer;
|
volatile u32 gAudioResetTimer;
|
||||||
|
|
||||||
u64 gAudioContextEnd[2];
|
u64 gAudioContextEnd[2];
|
||||||
|
|
||||||
|
@ -146,31 +146,31 @@ void func_80013A18(Note* note) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void func_80013A84(Note* note) {
|
void func_80013A84(Note* note) {
|
||||||
NotePlaybackState* temp_v0_3 = ¬e->playbackState;
|
NotePlaybackState* noteState = ¬e->playbackState;
|
||||||
VibratoState* temp_v1 = &temp_v0_3->vibratoState;
|
VibratoState* vibrato = ¬eState->vibratoState;
|
||||||
|
|
||||||
temp_v1->active = 1;
|
vibrato->active = 1;
|
||||||
temp_v1->time = 0;
|
vibrato->time = 0;
|
||||||
temp_v0_3->vibratoFreqMod = 1.0f;
|
noteState->vibratoFreqMod = 1.0f;
|
||||||
temp_v0_3->portamentoFreqMod = 1.0f;
|
noteState->portamentoFreqMod = 1.0f;
|
||||||
|
|
||||||
temp_v1->curve = gWaveSamples[2];
|
vibrato->curve = gWaveSamples[2];
|
||||||
|
|
||||||
temp_v1->channel = temp_v0_3->parentLayer->channel;
|
vibrato->channel = noteState->parentLayer->channel;
|
||||||
|
|
||||||
if ((temp_v1->depthChangeTimer = temp_v1->channel->vibratoDepthChangeDelay) == 0) {
|
if ((vibrato->depthChangeTimer = vibrato->channel->vibratoDepthChangeDelay) == 0) {
|
||||||
temp_v1->depth = (s32) temp_v1->channel->vibratoDepthTarget;
|
vibrato->depth = (s32) vibrato->channel->vibratoDepthTarget;
|
||||||
} else {
|
} else {
|
||||||
temp_v1->depth = (s32) temp_v1->channel->vibratoDepthStart;
|
vibrato->depth = (s32) vibrato->channel->vibratoDepthStart;
|
||||||
}
|
}
|
||||||
if ((temp_v1->rateChangeTimer = temp_v1->channel->vibratoRateChangeDelay) == 0) {
|
if ((vibrato->rateChangeTimer = vibrato->channel->vibratoRateChangeDelay) == 0) {
|
||||||
temp_v1->rate = (s32) temp_v1->channel->vibratoRateTarget;
|
vibrato->rate = (s32) vibrato->channel->vibratoRateTarget;
|
||||||
} else {
|
} else {
|
||||||
temp_v1->rate = (s32) temp_v1->channel->vibratoRateStart;
|
vibrato->rate = (s32) vibrato->channel->vibratoRateStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp_v1->delay = temp_v1->channel->vibratoDelay;
|
vibrato->delay = vibrato->channel->vibratoDelay;
|
||||||
temp_v0_3->portamento = temp_v0_3->parentLayer->portamento;
|
noteState->portamento = noteState->parentLayer->portamento;
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_80013B6C(AdsrState* adsr, EnvelopePoint* envelope, s16* arg2) {
|
void func_80013B6C(AdsrState* adsr, EnvelopePoint* envelope, s16* arg2) {
|
||||||
@ -187,31 +187,31 @@ f32 func_80013B90(AdsrState* adsr) {
|
|||||||
u8 state = adsr->state;
|
u8 state = adsr->state;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 0:
|
case ADSR_STATE_DISABLED:
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
case 1:
|
case ADSR_STATE_INITIAL:
|
||||||
if (action & 0x40) {
|
if (action & 0x40) {
|
||||||
adsr->state = 5;
|
adsr->state = ADSR_STATE_HANG;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case ADSR_STATE_START_LOOP:
|
||||||
adsr->envIndex = 0;
|
adsr->envIndex = 0;
|
||||||
adsr->state = 3;
|
adsr->state = ADSR_STATE_LOOP;
|
||||||
case_3:
|
case_ADSR_STATE_LOOP:
|
||||||
case 3:
|
case ADSR_STATE_LOOP:
|
||||||
adsr->delay = adsr->envelope[adsr->envIndex].delay;
|
adsr->delay = adsr->envelope[adsr->envIndex].delay;
|
||||||
switch (adsr->delay) {
|
switch (adsr->delay) {
|
||||||
case 0:
|
case ADSR_DISABLE:
|
||||||
adsr->state = 0;
|
adsr->state = ADSR_STATE_DISABLED;
|
||||||
break;
|
break;
|
||||||
case -1:
|
case ADSR_HANG:
|
||||||
adsr->state = 5;
|
adsr->state = ADSR_STATE_HANG;
|
||||||
break;
|
break;
|
||||||
case -2:
|
case ADSR_GOTO:
|
||||||
adsr->envIndex = adsr->envelope[adsr->envIndex].arg;
|
adsr->envIndex = adsr->envelope[adsr->envIndex].arg;
|
||||||
goto case_3;
|
goto case_ADSR_STATE_LOOP;
|
||||||
case -3:
|
case ADSR_RESTART:
|
||||||
adsr->state = 1;
|
adsr->state = ADSR_STATE_INITIAL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (adsr->delay >= 4) {
|
if (adsr->delay >= 4) {
|
||||||
@ -224,47 +224,47 @@ f32 func_80013B90(AdsrState* adsr) {
|
|||||||
adsr->target = adsr->envelope[adsr->envIndex].arg / 32767.0f;
|
adsr->target = adsr->envelope[adsr->envIndex].arg / 32767.0f;
|
||||||
adsr->target = SQ(adsr->target);
|
adsr->target = SQ(adsr->target);
|
||||||
adsr->velocity = (adsr->target - adsr->current) / adsr->delay;
|
adsr->velocity = (adsr->target - adsr->current) / adsr->delay;
|
||||||
adsr->state = 4;
|
adsr->state = ADSR_STATE_FADE;
|
||||||
adsr->envIndex++;
|
adsr->envIndex++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (adsr->state != 4) {
|
if (adsr->state != ADSR_STATE_FADE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
case ADSR_STATE_FADE:
|
||||||
adsr->delay -= 1;
|
adsr->delay--;
|
||||||
adsr->current += adsr->velocity;
|
adsr->current += adsr->velocity;
|
||||||
if (adsr->delay <= 0) {
|
if (adsr->delay <= 0) {
|
||||||
adsr->state = 3;
|
adsr->state = ADSR_STATE_LOOP;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case ADSR_STATE_DECAY:
|
||||||
case 7:
|
case ADSR_STATE_RELEASE:
|
||||||
adsr->current -= adsr->fadeOutVel;
|
adsr->current -= adsr->fadeOutVel;
|
||||||
if ((adsr->sustain != 0.0f) && (state == 6)) {
|
if ((adsr->sustain != 0.0f) && (state == ADSR_STATE_DECAY)) {
|
||||||
if (adsr->current < adsr->sustain) {
|
if (adsr->current < adsr->sustain) {
|
||||||
adsr->current = adsr->sustain;
|
adsr->current = adsr->sustain;
|
||||||
adsr->delay = 0x80;
|
adsr->delay = 0x80;
|
||||||
adsr->state = 8;
|
adsr->state = ADSR_STATE_SUSTAIN;
|
||||||
}
|
}
|
||||||
} else if (adsr->current < 0.00001f) {
|
} else if (adsr->current < 0.00001f) {
|
||||||
adsr->current = 0.0f;
|
adsr->current = 0.0f;
|
||||||
adsr->state = 0;
|
adsr->state = ADSR_STATE_DISABLED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case ADSR_STATE_SUSTAIN:
|
||||||
adsr->delay--;
|
adsr->delay--;
|
||||||
if (adsr->delay == 0) {
|
if (adsr->delay == 0) {
|
||||||
adsr->state = 7;
|
adsr->state = ADSR_STATE_RELEASE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (action & 0x20) {
|
if (action & 0x20) {
|
||||||
adsr->state = 6;
|
adsr->state = ADSR_STATE_DECAY;
|
||||||
adsr->action.asByte = action & ~0x20;
|
adsr->action.asByte = action & ~0x20;
|
||||||
}
|
}
|
||||||
if (action & 0x10) {
|
if (action & 0x10) {
|
||||||
adsr->state = 7;
|
adsr->state = ADSR_STATE_RELEASE;
|
||||||
adsr->action.asByte = action & ~0x10;
|
adsr->action.asByte = action & ~0x10;
|
||||||
}
|
}
|
||||||
if (adsr->current < 0.0f) {
|
if (adsr->current < 0.0f) {
|
||||||
|
@ -50,10 +50,10 @@ f32 sAnalyzerBuffer1[256];
|
|||||||
f32 sAnalyzerBuffer2[384];
|
f32 sAnalyzerBuffer2[384];
|
||||||
f32 sNewFreqAmplitudes[32];
|
f32 sNewFreqAmplitudes[32];
|
||||||
u8 sFreqAnalyzerBars[32];
|
u8 sFreqAnalyzerBars[32];
|
||||||
SeqRequest sSeqRequests[4][5];
|
SeqRequest sSeqRequests[SEQ_PLAYER_MAX][5];
|
||||||
u8 sNumSeqRequests[4];
|
u8 sNumSeqRequests[SEQ_PLAYER_MAX];
|
||||||
s32 sAudioSeqCmds[256];
|
s32 sAudioSeqCmds[256];
|
||||||
ActiveSequence sActiveSequences[4];
|
ActiveSequence sActiveSequences[SEQ_PLAYER_MAX];
|
||||||
u16 sDelayedSeqCmdFlags;
|
u16 sDelayedSeqCmdFlags;
|
||||||
DelayedSeqCmd sDelayedSeqCmds[16];
|
DelayedSeqCmd sDelayedSeqCmds[16];
|
||||||
SfxChannelState sSfxChannelState[16];
|
SfxChannelState sSfxChannelState[16];
|
||||||
@ -761,12 +761,12 @@ void Audio_ProcessSeqCmd(u32 seqCmd) {
|
|||||||
seqNumber = seqCmd & 0xFF;
|
seqNumber = seqCmd & 0xFF;
|
||||||
seqArgs = (seqCmd & 0xFF00) >> 8;
|
seqArgs = (seqCmd & 0xFF00) >> 8;
|
||||||
fadeTimer = (seqCmd & 0xFF0000) >> 13;
|
fadeTimer = (seqCmd & 0xFF0000) >> 13;
|
||||||
if (sActiveSequences[seqPlayId].isWaitingForFonts == 0) {
|
if (!sActiveSequences[seqPlayId].isWaitingForFonts) {
|
||||||
if (seqArgs < 0x80) {
|
if (seqArgs < 0x80) {
|
||||||
Audio_StartSequence(seqPlayId, seqNumber, seqArgs, fadeTimer);
|
Audio_StartSequence(seqPlayId, seqNumber, seqArgs, fadeTimer);
|
||||||
} else {
|
} else {
|
||||||
sActiveSequences[seqPlayId].startSeqCmd = seqCmd & ~0x8000;
|
sActiveSequences[seqPlayId].startSeqCmd = seqCmd & ~0x8000;
|
||||||
sActiveSequences[seqPlayId].isWaitingForFonts = 1;
|
sActiveSequences[seqPlayId].isWaitingForFonts = true;
|
||||||
Audio_StopSequence(seqPlayId, 1);
|
Audio_StopSequence(seqPlayId, 1);
|
||||||
if (sActiveSequences[seqPlayId].prevSeqId != SEQ_ID_NONE) {
|
if (sActiveSequences[seqPlayId].prevSeqId != SEQ_ID_NONE) {
|
||||||
tempptr = AudioThread_GetFontsForSequence(seqNumber, &sp4C);
|
tempptr = AudioThread_GetFontsForSequence(seqNumber, &sp4C);
|
||||||
@ -1054,23 +1054,23 @@ void Audio_UpdateActiveSequences(void) {
|
|||||||
s32 temp;
|
s32 temp;
|
||||||
u32 cmd;
|
u32 cmd;
|
||||||
f32 fadeMod;
|
f32 fadeMod;
|
||||||
u32 sp70;
|
u32 out;
|
||||||
s32 pad1;
|
s32 pad1;
|
||||||
s32 pad2;
|
s32 pad2;
|
||||||
|
|
||||||
for (seqPlayId = 0; seqPlayId < 4; seqPlayId++) {
|
for (seqPlayId = 0; seqPlayId < SEQ_PLAYER_MAX; seqPlayId++) {
|
||||||
if ((sActiveSequences[seqPlayId].isWaitingForFonts != 0)) {
|
if (sActiveSequences[seqPlayId].isWaitingForFonts) {
|
||||||
switch ((s32) AudioThread_GetAsyncLoadStatus(&sp70)) {
|
switch ((s32) AudioThread_GetAsyncLoadStatus(&out)) {
|
||||||
case SEQ_PLAYER_BGM + 1:
|
case SEQ_PLAYER_BGM + 1:
|
||||||
case SEQ_PLAYER_FANFARE + 1:
|
case SEQ_PLAYER_FANFARE + 1:
|
||||||
case SEQ_PLAYER_SFX + 1:
|
case SEQ_PLAYER_SFX + 1:
|
||||||
case SEQ_PLAYER_VOICE + 1:
|
case SEQ_PLAYER_VOICE + 1:
|
||||||
sActiveSequences[seqPlayId].isWaitingForFonts = 0;
|
sActiveSequences[seqPlayId].isWaitingForFonts = false;
|
||||||
Audio_ProcessSeqCmd(sActiveSequences[seqPlayId].startSeqCmd);
|
Audio_ProcessSeqCmd(sActiveSequences[seqPlayId].startSeqCmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sActiveSequences[seqPlayId].mainVolume.fadeActive != 0) {
|
if (sActiveSequences[seqPlayId].mainVolume.fadeActive) {
|
||||||
fadeMod = 1.0f;
|
fadeMod = 1.0f;
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
fadeMod *= sActiveSequences[seqPlayId].mainVolume.fadeMod[i] / 127.0f;
|
fadeMod *= sActiveSequences[seqPlayId].mainVolume.fadeMod[i] / 127.0f;
|
||||||
@ -2671,16 +2671,16 @@ void Audio_RestoreVolumeSettings(u8 audioType) {
|
|||||||
u8 i;
|
u8 i;
|
||||||
|
|
||||||
switch (audioType) {
|
switch (audioType) {
|
||||||
case 0:
|
case AUDIO_TYPE_MUSIC:
|
||||||
Audio_SetSequenceFade(SEQ_PLAYER_BGM, 0, volume, 1);
|
Audio_SetSequenceFade(SEQ_PLAYER_BGM, 0, volume, 1);
|
||||||
Audio_SetSequenceFade(SEQ_PLAYER_FANFARE, 0, volume, 1);
|
Audio_SetSequenceFade(SEQ_PLAYER_FANFARE, 0, volume, 1);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case AUDIO_TYPE_SFX:
|
||||||
for (i = 0; i < 15; i++) {
|
for (i = 0; i < 15; i++) {
|
||||||
AUDIOCMD_CHANNEL_SET_VOL(SEQ_PLAYER_SFX, (u32) i, volume / 127.0f);
|
AUDIOCMD_CHANNEL_SET_VOL(SEQ_PLAYER_SFX, (u32) i, volume / 127.0f);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case AUDIO_TYPE_VOICE:
|
||||||
AUDIOCMD_CHANNEL_SET_VOL(SEQ_PLAYER_VOICE, 15, volume / 127.0f);
|
AUDIOCMD_CHANNEL_SET_VOL(SEQ_PLAYER_VOICE, 15, volume / 127.0f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2773,8 +2773,8 @@ void Audio_InitSounds(void) {
|
|||||||
Audio_ResetSfxChannelState();
|
Audio_ResetSfxChannelState();
|
||||||
Audio_ResetActiveSequencesAndVolume();
|
Audio_ResetActiveSequencesAndVolume();
|
||||||
Audio_ResetSfx();
|
Audio_ResetSfx();
|
||||||
Audio_StartSequence(SEQ_PLAYER_VOICE, NA_BGM_VO, 0xFF, 1);
|
Audio_StartSequence(SEQ_PLAYER_VOICE, NA_BGM_VO, -1, 1);
|
||||||
Audio_StartSequence(SEQ_PLAYER_SFX, NA_BGM_SE, 0xFF, 10);
|
Audio_StartSequence(SEQ_PLAYER_SFX, NA_BGM_SE, -1, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio_RestartSeqPlayers(void) {
|
void Audio_RestartSeqPlayers(void) {
|
||||||
@ -2782,13 +2782,13 @@ void Audio_RestartSeqPlayers(void) {
|
|||||||
s32 pad2;
|
s32 pad2;
|
||||||
u16 fadeIn = 1;
|
u16 fadeIn = 1;
|
||||||
|
|
||||||
Audio_StartSequence(SEQ_PLAYER_VOICE, NA_BGM_VO, 0xFF, 1);
|
Audio_StartSequence(SEQ_PLAYER_VOICE, NA_BGM_VO, -1, 1);
|
||||||
if (sAudioSpecId == AUDIOSPEC_12) {
|
if (sAudioSpecId == AUDIOSPEC_12) {
|
||||||
fadeIn = 360;
|
fadeIn = 360;
|
||||||
} else if (sAudioSpecId < AUDIOSPEC_23) {
|
} else if (sAudioSpecId < AUDIOSPEC_23) {
|
||||||
fadeIn = 90;
|
fadeIn = 90;
|
||||||
}
|
}
|
||||||
Audio_StartSequence(SEQ_PLAYER_SFX, NA_BGM_SE, 0xFF, fadeIn);
|
Audio_StartSequence(SEQ_PLAYER_SFX, NA_BGM_SE, -1, fadeIn);
|
||||||
Audio_LoadInstruments();
|
Audio_LoadInstruments();
|
||||||
Audio_LoadAquasSequence();
|
Audio_LoadAquasSequence();
|
||||||
SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_SFX, 0, 127);
|
SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_SFX, 0, 127);
|
||||||
@ -2797,9 +2797,9 @@ void Audio_RestartSeqPlayers(void) {
|
|||||||
AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
|
AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
|
||||||
AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
|
AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
|
||||||
AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
|
AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
|
||||||
Audio_RestoreVolumeSettings(0);
|
Audio_RestoreVolumeSettings(AUDIO_TYPE_MUSIC);
|
||||||
Audio_RestoreVolumeSettings(2);
|
Audio_RestoreVolumeSettings(AUDIO_TYPE_SFX);
|
||||||
Audio_RestoreVolumeSettings(1);
|
Audio_RestoreVolumeSettings(AUDIO_TYPE_VOICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio_StartReset(u8 oldSpecId) {
|
void Audio_StartReset(u8 oldSpecId) {
|
||||||
|
@ -230,20 +230,20 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
u8* loadStatus;
|
u8* loadStatus;
|
||||||
|
|
||||||
switch (tableType) {
|
switch (tableType) {
|
||||||
case 0:
|
case SEQUENCE_TABLE:
|
||||||
loadedCache = &gSeqCache;
|
loadedCache = &gSeqCache;
|
||||||
loadStatus = gSeqLoadStatus;
|
loadStatus = gSeqLoadStatus;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FONT_TABLE:
|
||||||
loadedCache = &gFontCache;
|
loadedCache = &gFontCache;
|
||||||
loadStatus = gFontLoadStatus;
|
loadStatus = gFontLoadStatus;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case SAMPLE_TABLE:
|
||||||
loadedCache = &gSampleBankCache;
|
loadedCache = &gSampleBankCache;
|
||||||
loadStatus = gSampleFontLoadStatus;
|
loadStatus = gSampleFontLoadStatus;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (cache == 0) {
|
if (cache == CACHE_TEMPORARY) {
|
||||||
temporaryCache = &loadedCache->temporary;
|
temporaryCache = &loadedCache->temporary;
|
||||||
temporaryPool = &temporaryCache->pool;
|
temporaryPool = &temporaryCache->pool;
|
||||||
if (loadedCache->temporary.entries[0].id == -1) {
|
if (loadedCache->temporary.entries[0].id == -1) {
|
||||||
@ -256,7 +256,7 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
} else {
|
} else {
|
||||||
loadStatusEntry1 = loadStatus[temporaryCache->entries[1].id];
|
loadStatusEntry1 = loadStatus[temporaryCache->entries[1].id];
|
||||||
}
|
}
|
||||||
if (tableType == 1) {
|
if (tableType == FONT_TABLE) {
|
||||||
if (loadStatusEntry0 == 4) {
|
if (loadStatusEntry0 == 4) {
|
||||||
for (i = 0; i < gNumNotes; i++) {
|
for (i = 0; i < gNumNotes; i++) {
|
||||||
if ((gNotes[i].playbackState.fontId == temporaryCache->entries[0].id) &&
|
if ((gNotes[i].playbackState.fontId == temporaryCache->entries[0].id) &&
|
||||||
@ -298,7 +298,7 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
temporaryCache->nextSide = 1;
|
temporaryCache->nextSide = 1;
|
||||||
} else {
|
} else {
|
||||||
// Check if there is a side which isn't in active use, if so, evict that one.
|
// Check if there is a side which isn't in active use, if so, evict that one.
|
||||||
if (tableType == 0) {
|
if (tableType == SEQUENCE_TABLE) {
|
||||||
if (loadStatusEntry0 == 2) {
|
if (loadStatusEntry0 == 2) {
|
||||||
for (i = 0; i < ARRAY_COUNT(gSeqPlayers); i++) {
|
for (i = 0; i < ARRAY_COUNT(gSeqPlayers); i++) {
|
||||||
if (gSeqPlayers[i].enabled && (gSeqPlayers[i].seqId == temporaryCache->entries[0].id)) {
|
if (gSeqPlayers[i].enabled && (gSeqPlayers[i].seqId == temporaryCache->entries[0].id)) {
|
||||||
@ -321,7 +321,7 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
goto block_85;
|
goto block_85;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (tableType == 1) {
|
} else if (tableType == FONT_TABLE) {
|
||||||
if (loadStatusEntry0 == 2) {
|
if (loadStatusEntry0 == 2) {
|
||||||
for (i = 0; i < gNumNotes; i++) {
|
for (i = 0; i < gNumNotes; i++) {
|
||||||
if ((gNotes[i].playbackState.fontId == temporaryCache->entries[0].id) &&
|
if ((gNotes[i].playbackState.fontId == temporaryCache->entries[0].id) &&
|
||||||
@ -373,7 +373,7 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
|
|
||||||
if (temporaryCache->entries[temporaryCache->nextSide].id != -1) {
|
if (temporaryCache->entries[temporaryCache->nextSide].id != -1) {
|
||||||
loadStatus[temporaryCache->entries[temporaryCache->nextSide].id] = 0;
|
loadStatus[temporaryCache->entries[temporaryCache->nextSide].id] = 0;
|
||||||
if (tableType == 1) {
|
if (tableType == FONT_TABLE) {
|
||||||
AudioHeap_DiscardFont(temporaryCache->entries[temporaryCache->nextSide].id);
|
AudioHeap_DiscardFont(temporaryCache->entries[temporaryCache->nextSide].id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,10 +387,10 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
(temporaryCache->entries[1].ramAddr < temporaryPool->curRamAddr)) {
|
(temporaryCache->entries[1].ramAddr < temporaryPool->curRamAddr)) {
|
||||||
loadStatus[temporaryCache->entries[1].id] = 0;
|
loadStatus[temporaryCache->entries[1].id] = 0;
|
||||||
switch (tableType) {
|
switch (tableType) {
|
||||||
case 0:
|
case SEQUENCE_TABLE:
|
||||||
AudioHeap_DiscardSequence(temporaryCache->entries[1].id);
|
AudioHeap_DiscardSequence(temporaryCache->entries[1].id);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FONT_TABLE:
|
||||||
AudioHeap_DiscardFont(temporaryCache->entries[1].id);
|
AudioHeap_DiscardFont(temporaryCache->entries[1].id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -408,10 +408,10 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
(temporaryCache->entries[1].ramAddr < temporaryPool->curRamAddr)) {
|
(temporaryCache->entries[1].ramAddr < temporaryPool->curRamAddr)) {
|
||||||
loadStatus[temporaryCache->entries[0].id] = 0;
|
loadStatus[temporaryCache->entries[0].id] = 0;
|
||||||
switch (tableType) {
|
switch (tableType) {
|
||||||
case 0:
|
case SEQUENCE_TABLE:
|
||||||
AudioHeap_DiscardSequence(temporaryCache->entries[0].id);
|
AudioHeap_DiscardSequence(temporaryCache->entries[0].id);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FONT_TABLE:
|
||||||
AudioHeap_DiscardFont(temporaryCache->entries[0].id);
|
AudioHeap_DiscardFont(temporaryCache->entries[0].id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -430,10 +430,10 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
loadedCache->persistent.entries[loadedCache->persistent.numEntries].ramAddr = persistentRamAddr;
|
loadedCache->persistent.entries[loadedCache->persistent.numEntries].ramAddr = persistentRamAddr;
|
||||||
if (persistentRamAddr == NULL) {
|
if (persistentRamAddr == NULL) {
|
||||||
switch (cache) {
|
switch (cache) {
|
||||||
case 2:
|
case CACHE_EITHER:
|
||||||
return AudioHeap_AllocCached(tableType, size, 0, id);
|
return AudioHeap_AllocCached(tableType, size, CACHE_TEMPORARY, id);
|
||||||
case 0:
|
case CACHE_TEMPORARY:
|
||||||
case 1:
|
case CACHE_PERSISTENT:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -442,7 +442,7 @@ void* AudioHeap_AllocCached(s32 tableType, s32 size, s32 cache, s32 id) {
|
|||||||
return loadedCache->persistent.entries[loadedCache->persistent.numEntries++].ramAddr;
|
return loadedCache->persistent.entries[loadedCache->persistent.numEntries++].ramAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 AudioHeap_SearchCaches(s32 tableType, s32 cache, s32 id) {
|
void* AudioHeap_SearchCaches(s32 tableType, s32 cache, s32 id) {
|
||||||
void* ramAddr;
|
void* ramAddr;
|
||||||
|
|
||||||
// Always search the permanent cache in addition to the regular ones.
|
// Always search the permanent cache in addition to the regular ones.
|
||||||
@ -568,13 +568,13 @@ s32 AudioHeap_ResetStep(void) {
|
|||||||
} else {
|
} else {
|
||||||
sp24 = 1;
|
sp24 = 1;
|
||||||
}
|
}
|
||||||
switch (gResetStatus) {
|
switch (gAudioResetStep) {
|
||||||
case 5:
|
case 5:
|
||||||
for (i = 0; i < ARRAY_COUNT(gSeqPlayers); i++) {
|
for (i = 0; i < ARRAY_COUNT(gSeqPlayers); i++) {
|
||||||
func_800144E4(&gSeqPlayers[i]);
|
func_800144E4(&gSeqPlayers[i]);
|
||||||
}
|
}
|
||||||
gResetFadeoutFramesLeft = 4 / sp24;
|
gResetFadeoutFramesLeft = 4 / sp24;
|
||||||
gResetStatus--;
|
gAudioResetStep--;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if (gResetFadeoutFramesLeft != 0) {
|
if (gResetFadeoutFramesLeft != 0) {
|
||||||
@ -589,7 +589,7 @@ s32 AudioHeap_ResetStep(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gResetFadeoutFramesLeft = 16 / sp24;
|
gResetFadeoutFramesLeft = 16 / sp24;
|
||||||
gResetStatus--;
|
gAudioResetStep--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
@ -603,7 +603,7 @@ s32 AudioHeap_ResetStep(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
gResetFadeoutFramesLeft = 4 / sp24;
|
gResetFadeoutFramesLeft = 4 / sp24;
|
||||||
gResetStatus--;
|
gAudioResetStep--;
|
||||||
break; // needed to match
|
break; // needed to match
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -612,13 +612,13 @@ s32 AudioHeap_ResetStep(void) {
|
|||||||
if (gResetFadeoutFramesLeft != 0) {
|
if (gResetFadeoutFramesLeft != 0) {
|
||||||
gResetFadeoutFramesLeft--;
|
gResetFadeoutFramesLeft--;
|
||||||
} else {
|
} else {
|
||||||
gResetStatus--;
|
gAudioResetStep--;
|
||||||
AudioHeap_DiscardSampleCaches();
|
AudioHeap_DiscardSampleCaches();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
AudioHeap_Init();
|
AudioHeap_Init();
|
||||||
gResetStatus = 0;
|
gAudioResetStep = 0;
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
gAiBuffLengths[i] = gAudioBufferParams.maxAiBufferLength;
|
gAiBuffLengths[i] = gAudioBufferParams.maxAiBufferLength;
|
||||||
for (j = 0; j < AIBUF_LEN; j++) {
|
for (j = 0; j < AIBUF_LEN; j++) {
|
||||||
@ -627,7 +627,7 @@ s32 AudioHeap_ResetStep(void) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (gResetStatus < 3) {
|
if (gAudioResetStep < 3) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -919,9 +919,11 @@ void AudioHeap_DiscardSampleCacheEntry(SampleCacheEntry* entry) {
|
|||||||
for (fondId = 0; fondId < numFonts; fondId++) {
|
for (fondId = 0; fondId < numFonts; fondId++) {
|
||||||
sampleBankId1 = gSoundFontList[fondId].sampleBankId1;
|
sampleBankId1 = gSoundFontList[fondId].sampleBankId1;
|
||||||
sampleBankId2 = gSoundFontList[fondId].sampleBankId2;
|
sampleBankId2 = gSoundFontList[fondId].sampleBankId2;
|
||||||
if (((sampleBankId1 != 0xFF) && (entry->sampleBankId == sampleBankId1)) ||
|
if (((sampleBankId1 != SAMPLES_NONE) && (entry->sampleBankId == sampleBankId1)) ||
|
||||||
((sampleBankId2 != 0xFF) && (entry->sampleBankId == sampleBankId2)) || (entry->sampleBankId == 0)) {
|
((sampleBankId2 != SAMPLES_NONE) && (entry->sampleBankId == sampleBankId2)) ||
|
||||||
if ((AudioHeap_SearchCaches(1, 2, fondId) != NULL) && ((gFontLoadStatus[fondId] > 1) != 0)) {
|
(entry->sampleBankId == SAMPLES_SFX)) {
|
||||||
|
if ((AudioHeap_SearchCaches(FONT_TABLE, CACHE_EITHER, fondId) != NULL) &&
|
||||||
|
((gFontLoadStatus[fondId] > 1) != 0)) {
|
||||||
for (instId = 0; instId < gSoundFontList[fondId].numInstruments; instId++) {
|
for (instId = 0; instId < gSoundFontList[fondId].numInstruments; instId++) {
|
||||||
instrument = Audio_GetInstrument(fondId, instId);
|
instrument = Audio_GetInstrument(fondId, instId);
|
||||||
if (instrument != NULL) {
|
if (instrument != NULL) {
|
||||||
@ -989,9 +991,11 @@ void AudioHeap_DiscardSampleCaches(void) {
|
|||||||
for (fontId = 0; fontId < numFonts; fontId++) {
|
for (fontId = 0; fontId < numFonts; fontId++) {
|
||||||
sampleBankId1 = gSoundFontList[fontId].sampleBankId1;
|
sampleBankId1 = gSoundFontList[fontId].sampleBankId1;
|
||||||
sampleBankId2 = gSoundFontList[fontId].sampleBankId2;
|
sampleBankId2 = gSoundFontList[fontId].sampleBankId2;
|
||||||
if (((sampleBankId1 != 0xFFU) && (entry->sampleBankId == sampleBankId1)) ||
|
if (((sampleBankId1 != SAMPLES_NONE_U) && (entry->sampleBankId == sampleBankId1)) ||
|
||||||
((sampleBankId2 != 0xFF) && (entry->sampleBankId == sampleBankId2)) || (entry->sampleBankId == 0)) {
|
((sampleBankId2 != SAMPLES_NONE) && (entry->sampleBankId == sampleBankId2)) ||
|
||||||
if ((AudioHeap_SearchCaches(1, 3, fontId) != NULL) && ((gFontLoadStatus[fontId] > 1) != 0)) {
|
(entry->sampleBankId == SAMPLES_SFX)) {
|
||||||
|
if ((AudioHeap_SearchCaches(FONT_TABLE, CACHE_PERMANENT, fontId) != NULL) &&
|
||||||
|
((gFontLoadStatus[fontId] > 1) != 0)) {
|
||||||
for (i = 0; i < gPersistentSampleCache.numEntries; i++) {
|
for (i = 0; i < gPersistentSampleCache.numEntries; i++) {
|
||||||
entry = &gPersistentSampleCache.entries[i];
|
entry = &gPersistentSampleCache.entries[i];
|
||||||
for (instId = 0; instId < gSoundFontList[fontId].numInstruments; instId++) {
|
for (instId = 0; instId < gSoundFontList[fontId].numInstruments; instId++) {
|
||||||
|
@ -218,7 +218,7 @@ void AudioLoad_InitTable(AudioTable* table, u8* romAddr, u16 unkMediumParam) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* AudioLoad_SyncLoadSeqFonts(s32 seqId, u32* outFontId) {
|
void* AudioLoad_SyncLoadSeqFonts(s32 seqId, u32* outFontId) {
|
||||||
s32 index = ((u16*) gSeqFontTable)[AudioLoad_GetLoadTableIndex(0, seqId)];
|
s32 index = ((u16*) gSeqFontTable)[AudioLoad_GetLoadTableIndex(SEQUENCE_TABLE, seqId)];
|
||||||
s32 fontId = 0xFF;
|
s32 fontId = 0xFF;
|
||||||
s32 numFonts = gSeqFontTable[index++];
|
s32 numFonts = gSeqFontTable[index++];
|
||||||
void* soundFontData;
|
void* soundFontData;
|
||||||
@ -235,7 +235,7 @@ void AudioLoad_SyncLoadSeqParts(s32 seqId, s32 flags) {
|
|||||||
s32 pad;
|
s32 pad;
|
||||||
u32 fontId;
|
u32 fontId;
|
||||||
|
|
||||||
seqId = AudioLoad_GetLoadTableIndex(0, seqId);
|
seqId = AudioLoad_GetLoadTableIndex(SEQUENCE_TABLE, seqId);
|
||||||
if (flags & 2) {
|
if (flags & 2) {
|
||||||
AudioLoad_SyncLoadSeqFonts(seqId, &fontId);
|
AudioLoad_SyncLoadSeqFonts(seqId, &fontId);
|
||||||
}
|
}
|
||||||
@ -289,22 +289,24 @@ s32 AudioLoad_SyncLoadInstrument(s32 fontId, s32 instId, s32 drumId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioLoad_AsyncLoadSampleBank(s32 sampleBankId, s32 nChunks, s32 retData, OSMesgQueue* retQueue) {
|
void AudioLoad_AsyncLoadSampleBank(s32 sampleBankId, s32 nChunks, s32 retData, OSMesgQueue* retQueue) {
|
||||||
if (AudioLoad_AsyncLoadInner(2, AudioLoad_GetLoadTableIndex(2, sampleBankId), nChunks, retData, retQueue) == NULL) {
|
if (AudioLoad_AsyncLoadInner(SAMPLE_TABLE, AudioLoad_GetLoadTableIndex(SAMPLE_TABLE, sampleBankId), nChunks,
|
||||||
|
retData, retQueue) == NULL) {
|
||||||
osSendMesg(retQueue, NULL, OS_MESG_NOBLOCK);
|
osSendMesg(retQueue, NULL, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLoad_AsyncLoadSeq(s32 seqId, s32 nChunks, s32 retData, OSMesgQueue* retQueue) {
|
void AudioLoad_AsyncLoadSeq(s32 seqId, s32 nChunks, s32 retData, OSMesgQueue* retQueue) {
|
||||||
s32 index = ((u16*) gSeqFontTable)[AudioLoad_GetLoadTableIndex(0, seqId)];
|
s32 index = ((u16*) gSeqFontTable)[AudioLoad_GetLoadTableIndex(SEQUENCE_TABLE, seqId)];
|
||||||
s32 fontsLeft = gSeqFontTable[index++];
|
s32 fontsLeft = gSeqFontTable[index++];
|
||||||
|
|
||||||
for (fontsLeft; fontsLeft > 0; fontsLeft--) {
|
for (fontsLeft; fontsLeft > 0; fontsLeft--) {
|
||||||
AudioLoad_AsyncLoadInner(1, AudioLoad_GetLoadTableIndex(1, gSeqFontTable[index++]), nChunks, retData, retQueue);
|
AudioLoad_AsyncLoadInner(FONT_TABLE, AudioLoad_GetLoadTableIndex(FONT_TABLE, gSeqFontTable[index++]), nChunks,
|
||||||
|
retData, retQueue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts) {
|
u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts) {
|
||||||
s32 index = ((u16*) gSeqFontTable)[AudioLoad_GetLoadTableIndex(0, seqId)];
|
s32 index = ((u16*) gSeqFontTable)[AudioLoad_GetLoadTableIndex(SEQUENCE_TABLE, seqId)];
|
||||||
|
|
||||||
*outNumFonts = gSeqFontTable[index++];
|
*outNumFonts = gSeqFontTable[index++];
|
||||||
if (*outNumFonts == 0) {
|
if (*outNumFonts == 0) {
|
||||||
@ -314,13 +316,13 @@ u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioLoad_DiscardSeqFonts(s32 seqId) {
|
void AudioLoad_DiscardSeqFonts(s32 seqId) {
|
||||||
s32 index = ((u16*) gSeqFontTable)[AudioLoad_GetLoadTableIndex(0, seqId)];
|
s32 index = ((u16*) gSeqFontTable)[AudioLoad_GetLoadTableIndex(SEQUENCE_TABLE, seqId)];
|
||||||
s32 numFonts = gSeqFontTable[index++];
|
s32 numFonts = gSeqFontTable[index++];
|
||||||
u32 fontId;
|
u32 fontId;
|
||||||
|
|
||||||
while (numFonts > 0) {
|
while (numFonts > 0) {
|
||||||
numFonts--;
|
numFonts--;
|
||||||
fontId = AudioLoad_GetLoadTableIndex(1, gSeqFontTable[index++]);
|
fontId = AudioLoad_GetLoadTableIndex(FONT_TABLE, gSeqFontTable[index++]);
|
||||||
if (AudioHeap_SearchPermanentCache(1, fontId) == NULL) {
|
if (AudioHeap_SearchPermanentCache(1, fontId) == NULL) {
|
||||||
AudioLoad_DiscardFont(fontId);
|
AudioLoad_DiscardFont(fontId);
|
||||||
if (gFontLoadStatus[fontId] != 5) {
|
if (gFontLoadStatus[fontId] != 5) {
|
||||||
@ -363,7 +365,7 @@ void AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) {
|
|||||||
s32 fontId;
|
s32 fontId;
|
||||||
s32 i;
|
s32 i;
|
||||||
|
|
||||||
seqId = AudioLoad_GetLoadTableIndex(0, seqId);
|
seqId = AudioLoad_GetLoadTableIndex(SEQUENCE_TABLE, seqId);
|
||||||
func_800144E4(&gSeqPlayers[playerIdx]);
|
func_800144E4(&gSeqPlayers[playerIdx]);
|
||||||
index = ((u16*) gSeqFontTable)[seqId];
|
index = ((u16*) gSeqFontTable)[seqId];
|
||||||
numFonts = gSeqFontTable[index++];
|
numFonts = gSeqFontTable[index++];
|
||||||
@ -388,7 +390,7 @@ void AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* AudioLoad_SyncLoadSeq(s32 seqId) {
|
void* AudioLoad_SyncLoadSeq(s32 seqId) {
|
||||||
s32 seqIdx = AudioLoad_GetLoadTableIndex(0, seqId);
|
s32 seqIdx = AudioLoad_GetLoadTableIndex(SEQUENCE_TABLE, seqId);
|
||||||
s32 didAllocate;
|
s32 didAllocate;
|
||||||
|
|
||||||
return AudioLoad_SyncLoad(0, seqIdx, &didAllocate);
|
return AudioLoad_SyncLoad(0, seqIdx, &didAllocate);
|
||||||
@ -400,7 +402,7 @@ void* AudioLoad_SyncLoadSampleBank(u32 sampleBankId, s32* outMedium) {
|
|||||||
s32 cachePolicy;
|
s32 cachePolicy;
|
||||||
s32 noLoad;
|
s32 noLoad;
|
||||||
|
|
||||||
sampleBankId = AudioLoad_GetLoadTableIndex(2, sampleBankId);
|
sampleBankId = AudioLoad_GetLoadTableIndex(SAMPLE_TABLE, sampleBankId);
|
||||||
ramAddr = AudioLoad_SearchCaches(2, sampleBankId);
|
ramAddr = AudioLoad_SearchCaches(2, sampleBankId);
|
||||||
if (ramAddr != NULL) {
|
if (ramAddr != NULL) {
|
||||||
if (gSampleFontLoadStatus[sampleBankId] != 5) {
|
if (gSampleFontLoadStatus[sampleBankId] != 5) {
|
||||||
@ -410,7 +412,7 @@ void* AudioLoad_SyncLoadSampleBank(u32 sampleBankId, s32* outMedium) {
|
|||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
cachePolicy = sampleBankTable->entries[sampleBankId].cachePolicy;
|
cachePolicy = sampleBankTable->entries[sampleBankId].cachePolicy;
|
||||||
if (cachePolicy == 4) {
|
if (cachePolicy == CACHEPOLICY_4) {
|
||||||
*outMedium = sampleBankTable->entries[sampleBankId].medium;
|
*outMedium = sampleBankTable->entries[sampleBankId].medium;
|
||||||
return sampleBankTable->entries[sampleBankId].romAddr;
|
return sampleBankTable->entries[sampleBankId].romAddr;
|
||||||
}
|
}
|
||||||
@ -430,18 +432,18 @@ void* AudioLoad_SyncLoadFont(s32 fontId) {
|
|||||||
s32 didAllocate;
|
s32 didAllocate;
|
||||||
SampleBankRelocInfo relocInfo;
|
SampleBankRelocInfo relocInfo;
|
||||||
|
|
||||||
fontId = AudioLoad_GetLoadTableIndex(1, fontId);
|
fontId = AudioLoad_GetLoadTableIndex(FONT_TABLE, fontId);
|
||||||
sampleBankId1 = gSoundFontList[fontId].sampleBankId1;
|
sampleBankId1 = gSoundFontList[fontId].sampleBankId1;
|
||||||
sampleBankId2 = gSoundFontList[fontId].sampleBankId2;
|
sampleBankId2 = gSoundFontList[fontId].sampleBankId2;
|
||||||
|
|
||||||
relocInfo.sampleBankId1 = sampleBankId1;
|
relocInfo.sampleBankId1 = sampleBankId1;
|
||||||
relocInfo.sampleBankId2 = sampleBankId2;
|
relocInfo.sampleBankId2 = sampleBankId2;
|
||||||
if (sampleBankId1 != 0xFF) {
|
if (sampleBankId1 != SAMPLES_NONE) {
|
||||||
relocInfo.baseAddr1 = AudioLoad_SyncLoadSampleBank(sampleBankId1, &relocInfo.medium1);
|
relocInfo.baseAddr1 = AudioLoad_SyncLoadSampleBank(sampleBankId1, &relocInfo.medium1);
|
||||||
} else {
|
} else {
|
||||||
relocInfo.baseAddr1 = NULL;
|
relocInfo.baseAddr1 = NULL;
|
||||||
}
|
}
|
||||||
if (sampleBankId2 != 0xFF) {
|
if (sampleBankId2 != SAMPLES_NONE) {
|
||||||
relocInfo.baseAddr2 = AudioLoad_SyncLoadSampleBank(sampleBankId2, &relocInfo.medium2);
|
relocInfo.baseAddr2 = AudioLoad_SyncLoadSampleBank(sampleBankId2, &relocInfo.medium2);
|
||||||
} else {
|
} else {
|
||||||
relocInfo.baseAddr2 = NULL;
|
relocInfo.baseAddr2 = NULL;
|
||||||
@ -451,7 +453,7 @@ void* AudioLoad_SyncLoadFont(s32 fontId) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (didAllocate == 1) {
|
if (didAllocate == 1) {
|
||||||
AudioLoad_RelocateFontAndPreloadSamples(fontId, fontData, &relocInfo, 0);
|
AudioLoad_RelocateFontAndPreloadSamples(fontId, fontData, &relocInfo, AUDIOLOAD_SYNC);
|
||||||
}
|
}
|
||||||
return fontData;
|
return fontData;
|
||||||
}
|
}
|
||||||
@ -478,27 +480,27 @@ void* AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
|
|||||||
cachePolicy = table->entries[id].cachePolicy;
|
cachePolicy = table->entries[id].cachePolicy;
|
||||||
romAddr = table->entries[id].romAddr;
|
romAddr = table->entries[id].romAddr;
|
||||||
switch (cachePolicy) {
|
switch (cachePolicy) {
|
||||||
case 0:
|
case CACHEPOLICY_0:
|
||||||
ramAddr = AudioHeap_AllocPermanent(tableType, id, size);
|
ramAddr = AudioHeap_AllocPermanent(tableType, id, size);
|
||||||
if (ramAddr == NULL) {
|
if (ramAddr == NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case CACHEPOLICY_1:
|
||||||
ramAddr = AudioHeap_AllocCached(tableType, size, 1, id);
|
ramAddr = AudioHeap_AllocCached(tableType, size, CACHE_PERSISTENT, id);
|
||||||
if (ramAddr == NULL) {
|
if (ramAddr == NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case CACHEPOLICY_2:
|
||||||
ramAddr = AudioHeap_AllocCached(tableType, size, 0, id);
|
ramAddr = AudioHeap_AllocCached(tableType, size, CACHE_TEMPORARY, id);
|
||||||
if (ramAddr == NULL) {
|
if (ramAddr == NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case CACHEPOLICY_3:
|
||||||
case 4:
|
case CACHEPOLICY_4:
|
||||||
ramAddr = AudioHeap_AllocCached(tableType, size, 2, id);
|
ramAddr = AudioHeap_AllocCached(tableType, size, CACHE_EITHER, id);
|
||||||
if (ramAddr == NULL) {
|
if (ramAddr == NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
@ -511,7 +513,7 @@ void* AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
|
|||||||
} else {
|
} else {
|
||||||
AudioLoad_SyncDma(romAddr, ramAddr, size, medium);
|
AudioLoad_SyncDma(romAddr, ramAddr, size, medium);
|
||||||
}
|
}
|
||||||
loadStatus = (cachePolicy == 0) ? 5 : 2;
|
loadStatus = (cachePolicy == CACHEPOLICY_0) ? 5 : 2;
|
||||||
}
|
}
|
||||||
switch (tableType) {
|
switch (tableType) {
|
||||||
case SEQUENCE_TABLE:
|
case SEQUENCE_TABLE:
|
||||||
@ -549,7 +551,7 @@ void* AudioLoad_SearchCaches(s32 tableType, s32 id) {
|
|||||||
if (ramAddr != NULL) {
|
if (ramAddr != NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
ramAddr = AudioHeap_SearchCaches(tableType, 2, id);
|
ramAddr = AudioHeap_SearchCaches(tableType, CACHE_EITHER, id);
|
||||||
if (ramAddr != NULL) {
|
if (ramAddr != NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
@ -715,17 +717,17 @@ void* AudioLoad_AsyncLoadInner(s32 tableType, s32 id, s32 nChunks, s32 retData,
|
|||||||
s32 loadStatus;
|
s32 loadStatus;
|
||||||
|
|
||||||
switch (tableType) {
|
switch (tableType) {
|
||||||
case 0:
|
case SEQUENCE_TABLE:
|
||||||
if (gSeqLoadStatus[id] == 1) {
|
if (gSeqLoadStatus[id] == 1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FONT_TABLE:
|
||||||
if (gFontLoadStatus[id] == 1) {
|
if (gFontLoadStatus[id] == 1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case SAMPLE_TABLE:
|
||||||
if (gSampleFontLoadStatus[id] == 1) {
|
if (gSampleFontLoadStatus[id] == 1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -744,28 +746,28 @@ void* AudioLoad_AsyncLoadInner(s32 tableType, s32 id, s32 nChunks, s32 retData,
|
|||||||
romAddr = table->entries[id].romAddr;
|
romAddr = table->entries[id].romAddr;
|
||||||
loadStatus = 2;
|
loadStatus = 2;
|
||||||
switch (cachePolicy) {
|
switch (cachePolicy) {
|
||||||
case 0:
|
case CACHEPOLICY_0:
|
||||||
ramAddr = AudioHeap_AllocPermanent(tableType, id, size);
|
ramAddr = AudioHeap_AllocPermanent(tableType, id, size);
|
||||||
if (ramAddr == NULL) {
|
if (ramAddr == NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
loadStatus = 5;
|
loadStatus = 5;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case CACHEPOLICY_1:
|
||||||
ramAddr = AudioHeap_AllocCached(tableType, size, 1, id);
|
ramAddr = AudioHeap_AllocCached(tableType, size, CACHE_PERSISTENT, id);
|
||||||
if (ramAddr == NULL) {
|
if (ramAddr == NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case CACHEPOLICY_2:
|
||||||
ramAddr = AudioHeap_AllocCached(tableType, size, 0, id);
|
ramAddr = AudioHeap_AllocCached(tableType, size, CACHE_TEMPORARY, id);
|
||||||
if (ramAddr == NULL) {
|
if (ramAddr == NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case CACHEPOLICY_3:
|
||||||
case 4:
|
case CACHEPOLICY_4:
|
||||||
ramAddr = AudioHeap_AllocCached(tableType, size, 2, id);
|
ramAddr = AudioHeap_AllocCached(tableType, size, CACHE_EITHER, id);
|
||||||
if (ramAddr == NULL) {
|
if (ramAddr == NULL) {
|
||||||
return ramAddr;
|
return ramAddr;
|
||||||
}
|
}
|
||||||
@ -776,17 +778,17 @@ void* AudioLoad_AsyncLoadInner(s32 tableType, s32 id, s32 nChunks, s32 retData,
|
|||||||
loadStatus = 1;
|
loadStatus = 1;
|
||||||
}
|
}
|
||||||
switch (tableType) {
|
switch (tableType) {
|
||||||
case 0:
|
case SEQUENCE_TABLE:
|
||||||
if (gSeqLoadStatus[id] != 5) {
|
if (gSeqLoadStatus[id] != 5) {
|
||||||
gSeqLoadStatus[id] = loadStatus;
|
gSeqLoadStatus[id] = loadStatus;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FONT_TABLE:
|
||||||
if (gFontLoadStatus[id] != 5) {
|
if (gFontLoadStatus[id] != 5) {
|
||||||
gFontLoadStatus[id] = loadStatus;
|
gFontLoadStatus[id] = loadStatus;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case SAMPLE_TABLE:
|
||||||
if (gSampleFontLoadStatus[id] != 5) {
|
if (gSampleFontLoadStatus[id] != 5) {
|
||||||
gSampleFontLoadStatus[id] = loadStatus;
|
gSampleFontLoadStatus[id] = loadStatus;
|
||||||
}
|
}
|
||||||
@ -823,7 +825,7 @@ void AudioLoad_Init(void) {
|
|||||||
u64* clearContext;
|
u64* clearContext;
|
||||||
void* ramAddr;
|
void* ramAddr;
|
||||||
|
|
||||||
gResetTimer = 0;
|
gAudioResetTimer = 0;
|
||||||
|
|
||||||
for (i = 0; i < gAudioHeapSize / 8; i++) {
|
for (i = 0; i < gAudioHeapSize / 8; i++) {
|
||||||
((u64*) gAudioHeap)[i] = 0;
|
((u64*) gAudioHeap)[i] = 0;
|
||||||
@ -874,11 +876,11 @@ void AudioLoad_Init(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
gAudioSpecId = AUDIOSPEC_0;
|
gAudioSpecId = AUDIOSPEC_0;
|
||||||
gResetStatus = 1;
|
gAudioResetStep = 1;
|
||||||
AudioHeap_ResetStep();
|
AudioHeap_ResetStep();
|
||||||
gSequenceTable = &gSeqTableInit;
|
gSequenceTable = (AudioTable*) &gSeqTableInit;
|
||||||
gSoundFontTable = &gSoundFontTableInit;
|
gSoundFontTable = (AudioTable*) &gSoundFontTableInit;
|
||||||
gSampleBankTable = &gSampleBankTableInit;
|
gSampleBankTable = (AudioTable*) &gSampleBankTableInit;
|
||||||
gSeqFontTable = gSeqFontTableInit;
|
gSeqFontTable = gSeqFontTableInit;
|
||||||
gNumSequences = gSequenceTable->numEntries;
|
gNumSequences = gSequenceTable->numEntries;
|
||||||
AudioLoad_InitTable(gSequenceTable, SEGMENT_ROM_START(audio_seq), gSequenceMedium);
|
AudioLoad_InitTable(gSequenceTable, SEGMENT_ROM_START(audio_seq), gSequenceMedium);
|
||||||
@ -909,16 +911,16 @@ s32 AudioLoad_SlowLoadSample(s32 fontId, u8 instId, s8* status) {
|
|||||||
|
|
||||||
sample = AudioLoad_GetFontSample(fontId, instId);
|
sample = AudioLoad_GetFontSample(fontId, instId);
|
||||||
if (sample == NULL) {
|
if (sample == NULL) {
|
||||||
*status = 0;
|
*status = SLOW_LOAD_STATUS_0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (sample->medium == MEDIUM_RAM) {
|
if (sample->medium == MEDIUM_RAM) {
|
||||||
*status = 2;
|
*status = SLOW_LOAD_STATUS_2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
slowLoad = &gSlowLoads.slowLoad[gSlowLoads.unk_00];
|
slowLoad = &gSlowLoads.slowLoad[gSlowLoads.unk_00];
|
||||||
if (slowLoad->state == 3) {
|
if (slowLoad->state == SLOW_LOAD_DONE) {
|
||||||
slowLoad->state = 0;
|
slowLoad->state = SLOW_LOAD_WAITING;
|
||||||
}
|
}
|
||||||
slowLoad->sample = *sample;
|
slowLoad->sample = *sample;
|
||||||
slowLoad->status = status;
|
slowLoad->status = status;
|
||||||
@ -926,14 +928,14 @@ s32 AudioLoad_SlowLoadSample(s32 fontId, u8 instId, s8* status) {
|
|||||||
AudioHeap_AllocTemporarySampleCache(sample->size, fontId, sample->sampleAddr, sample->medium);
|
AudioHeap_AllocTemporarySampleCache(sample->size, fontId, sample->sampleAddr, sample->medium);
|
||||||
if (slowLoad->curRamAddr == NULL) {
|
if (slowLoad->curRamAddr == NULL) {
|
||||||
if ((sample->medium == MEDIUM_UNK) || (sample->codec == 2)) {
|
if ((sample->medium == MEDIUM_UNK) || (sample->codec == 2)) {
|
||||||
*status = 0;
|
*status = SLOW_LOAD_STATUS_0;
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
*status = 3;
|
*status = SLOW_LOAD_STATUS_3;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slowLoad->state = 1;
|
slowLoad->state = SLOW_LOAD_START;
|
||||||
slowLoad->bytesRemaining = ALIGN16(sample->size);
|
slowLoad->bytesRemaining = ALIGN16(sample->size);
|
||||||
slowLoad->ramAddr = slowLoad->curRamAddr;
|
slowLoad->ramAddr = slowLoad->curRamAddr;
|
||||||
slowLoad->curDevAddr = sample->sampleAddr;
|
slowLoad->curDevAddr = sample->sampleAddr;
|
||||||
@ -986,18 +988,18 @@ void AudioLoad_ProcessSlowLoads(s32 resetStatus) {
|
|||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
slowLoad = &gSlowLoads.slowLoad[i];
|
slowLoad = &gSlowLoads.slowLoad[i];
|
||||||
switch (slowLoad->state) {
|
switch (slowLoad->state) {
|
||||||
case 2:
|
case SLOW_LOAD_LOADING:
|
||||||
MQ_WAIT_FOR_MESG(&slowLoad->mesgQueue, NULL);
|
MQ_WAIT_FOR_MESG(&slowLoad->mesgQueue, NULL);
|
||||||
if (resetStatus != 0) {
|
if (resetStatus != 0) {
|
||||||
slowLoad->state = 3;
|
slowLoad->state = SLOW_LOAD_DONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1:
|
case SLOW_LOAD_START:
|
||||||
slowLoad->state = 2;
|
slowLoad->state = SLOW_LOAD_LOADING;
|
||||||
if (slowLoad->bytesRemaining == 0) {
|
if (slowLoad->bytesRemaining == 0) {
|
||||||
AudioLoad_FinishSlowLoad(&gSlowLoads.slowLoad[i]);
|
AudioLoad_FinishSlowLoad(&gSlowLoads.slowLoad[i]);
|
||||||
slowLoad->state = 3;
|
slowLoad->state = SLOW_LOAD_DONE;
|
||||||
*slowLoad->status = 1;
|
*slowLoad->status = SLOW_LOAD_STATUS_1;
|
||||||
} else if (slowLoad->bytesRemaining < 0x1000) {
|
} else if (slowLoad->bytesRemaining < 0x1000) {
|
||||||
if (slowLoad->medium == MEDIUM_UNK) {
|
if (slowLoad->medium == MEDIUM_UNK) {
|
||||||
AudioLoad_DmaSlowCopyUnkMedium(slowLoad->curDevAddr, slowLoad->curRamAddr,
|
AudioLoad_DmaSlowCopyUnkMedium(slowLoad->curDevAddr, slowLoad->curRamAddr,
|
||||||
@ -1092,16 +1094,15 @@ void AudioLoad_ProcessAsyncLoads(s32 resetStatus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioLoad_ProcessAsyncLoad(AudioAsyncLoad* asyncLoad, s32 resetStatus) {
|
void AudioLoad_ProcessAsyncLoad(AudioAsyncLoad* asyncLoad, s32 resetStatus) {
|
||||||
AudioTable* sp5C;
|
AudioTable* sampleTable = gSampleBankTable;
|
||||||
s32 pad1;
|
s32 tableType;
|
||||||
s32 pad2;
|
s32 loadStatus;
|
||||||
u32 temp;
|
u32 msg;
|
||||||
s32 sp24;
|
s32 tableIndex;
|
||||||
s32 sp48;
|
s32 sampleBankId1;
|
||||||
s32 sp44;
|
s32 sampleBankId2;
|
||||||
SampleBankRelocInfo sp2C;
|
SampleBankRelocInfo relocInfo;
|
||||||
|
|
||||||
sp5C = gSampleBankTable;
|
|
||||||
if (asyncLoad->delay > 1) {
|
if (asyncLoad->delay > 1) {
|
||||||
asyncLoad->delay--;
|
asyncLoad->delay--;
|
||||||
return;
|
return;
|
||||||
@ -1119,64 +1120,62 @@ void AudioLoad_ProcessAsyncLoad(AudioAsyncLoad* asyncLoad, s32 resetStatus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (asyncLoad->bytesRemaining == 0) {
|
if (asyncLoad->bytesRemaining == 0) {
|
||||||
temp = asyncLoad->retMsg;
|
msg = asyncLoad->retMsg;
|
||||||
pad1 = (temp >> 0x10) & 0xFF;
|
tableType = (msg >> 0x10) & 0xFF;
|
||||||
sp24 = (temp >> 8) & 0xFF;
|
tableIndex = (msg >> 8) & 0xFF;
|
||||||
pad2 = temp & 0xFF;
|
loadStatus = msg & 0xFF;
|
||||||
switch (pad1) {
|
switch (tableType) {
|
||||||
case 0:
|
case SEQUENCE_TABLE:
|
||||||
if (gSeqLoadStatus[sp24] != 5) {
|
if (gSeqLoadStatus[tableIndex] != 5) {
|
||||||
gSeqLoadStatus[sp24] = pad2;
|
gSeqLoadStatus[tableIndex] = loadStatus;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case SAMPLE_TABLE:
|
||||||
if (gSampleFontLoadStatus[sp24] != 5) {
|
if (gSampleFontLoadStatus[tableIndex] != 5) {
|
||||||
gSampleFontLoadStatus[sp24] = pad2;
|
gSampleFontLoadStatus[tableIndex] = loadStatus;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case FONT_TABLE:
|
||||||
if (gFontLoadStatus[sp24] != 5) {
|
if (gFontLoadStatus[tableIndex] != 5) {
|
||||||
gFontLoadStatus[sp24] = pad2;
|
gFontLoadStatus[tableIndex] = loadStatus;
|
||||||
}
|
}
|
||||||
sp48 = gSoundFontList[sp24].sampleBankId1;
|
sampleBankId1 = gSoundFontList[tableIndex].sampleBankId1;
|
||||||
sp44 = gSoundFontList[sp24].sampleBankId2;
|
sampleBankId2 = gSoundFontList[tableIndex].sampleBankId2;
|
||||||
sp2C.sampleBankId1 = sp48;
|
relocInfo.sampleBankId1 = sampleBankId1;
|
||||||
sp2C.sampleBankId2 = sp44;
|
relocInfo.sampleBankId2 = sampleBankId2;
|
||||||
if (sp48 != 0xFF) {
|
if (sampleBankId1 != SAMPLES_NONE) {
|
||||||
sp2C.baseAddr1 = AudioLoad_SyncLoadSampleBank(sp48, &sp2C.medium1);
|
relocInfo.baseAddr1 = AudioLoad_SyncLoadSampleBank(sampleBankId1, &relocInfo.medium1);
|
||||||
} else {
|
} else {
|
||||||
sp2C.baseAddr1 = NULL;
|
relocInfo.baseAddr1 = NULL;
|
||||||
}
|
}
|
||||||
if (sp44 != 0xFF) {
|
if (sampleBankId2 != SAMPLES_NONE) {
|
||||||
sp2C.baseAddr2 = AudioLoad_SyncLoadSampleBank(sp44, &sp2C.medium2);
|
relocInfo.baseAddr2 = AudioLoad_SyncLoadSampleBank(sampleBankId2, &relocInfo.medium2);
|
||||||
} else {
|
} else {
|
||||||
sp2C.baseAddr2 = NULL;
|
relocInfo.baseAddr2 = NULL;
|
||||||
}
|
}
|
||||||
AudioLoad_RelocateFontAndPreloadSamples(sp24, asyncLoad->ramAddr, &sp2C, 1);
|
AudioLoad_RelocateFontAndPreloadSamples(tableIndex, asyncLoad->ramAddr, &relocInfo, AUDIOLOAD_ASYNC);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
asyncLoad->status = 0;
|
asyncLoad->status = 0;
|
||||||
osSendMesg(asyncLoad->retQueue, asyncLoad->retMsg, OS_MESG_NOBLOCK);
|
osSendMesg(asyncLoad->retQueue, asyncLoad->retMsg, OS_MESG_NOBLOCK);
|
||||||
} else {
|
} else if (asyncLoad->bytesRemaining < asyncLoad->chunkSize) {
|
||||||
if (asyncLoad->bytesRemaining < asyncLoad->chunkSize) {
|
if (asyncLoad->medium == MEDIUM_UNK) {
|
||||||
if (asyncLoad->medium == MEDIUM_UNK) {
|
AudioLoad_AsyncDmaUnkMedium(asyncLoad->curDevAddr, asyncLoad->curRamAddr, asyncLoad->bytesRemaining,
|
||||||
AudioLoad_AsyncDmaUnkMedium(asyncLoad->curDevAddr, asyncLoad->curRamAddr, asyncLoad->bytesRemaining,
|
sampleTable->unkMediumParam);
|
||||||
sp5C->unkMediumParam);
|
|
||||||
} else {
|
|
||||||
AudioLoad_AsyncDma(asyncLoad, asyncLoad->bytesRemaining);
|
|
||||||
}
|
|
||||||
asyncLoad->bytesRemaining = 0;
|
|
||||||
} else {
|
} else {
|
||||||
if (asyncLoad->medium == MEDIUM_UNK) {
|
AudioLoad_AsyncDma(asyncLoad, asyncLoad->bytesRemaining);
|
||||||
AudioLoad_AsyncDmaUnkMedium(asyncLoad->curDevAddr, asyncLoad->curRamAddr, asyncLoad->chunkSize,
|
|
||||||
sp5C->unkMediumParam);
|
|
||||||
} else {
|
|
||||||
AudioLoad_AsyncDma(asyncLoad, asyncLoad->chunkSize);
|
|
||||||
}
|
|
||||||
asyncLoad->bytesRemaining -= asyncLoad->chunkSize;
|
|
||||||
asyncLoad->curDevAddr += asyncLoad->chunkSize;
|
|
||||||
asyncLoad->curRamAddr += asyncLoad->chunkSize;
|
|
||||||
}
|
}
|
||||||
|
asyncLoad->bytesRemaining = 0;
|
||||||
|
} else {
|
||||||
|
if (asyncLoad->medium == MEDIUM_UNK) {
|
||||||
|
AudioLoad_AsyncDmaUnkMedium(asyncLoad->curDevAddr, asyncLoad->curRamAddr, asyncLoad->chunkSize,
|
||||||
|
sampleTable->unkMediumParam);
|
||||||
|
} else {
|
||||||
|
AudioLoad_AsyncDma(asyncLoad, asyncLoad->chunkSize);
|
||||||
|
}
|
||||||
|
asyncLoad->bytesRemaining -= asyncLoad->chunkSize;
|
||||||
|
asyncLoad->curDevAddr += asyncLoad->chunkSize;
|
||||||
|
asyncLoad->curRamAddr += asyncLoad->chunkSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1271,7 +1270,7 @@ s32 AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, u32 fontDataAddr, Sample
|
|||||||
#endif
|
#endif
|
||||||
//! Bug: Those are assignments, not equality checks.
|
//! Bug: Those are assignments, not equality checks.
|
||||||
switch (isAsync) {
|
switch (isAsync) {
|
||||||
case 0:
|
case AUDIOLOAD_SYNC:
|
||||||
if (sample->medium = relocData->medium1) {
|
if (sample->medium = relocData->medium1) {
|
||||||
sampleRamAddr = AudioHeap_AllocPersistentSampleCache(sample->size, relocData->sampleBankId1,
|
sampleRamAddr = AudioHeap_AllocPersistentSampleCache(sample->size, relocData->sampleBankId1,
|
||||||
sample->sampleAddr, sample->medium);
|
sample->sampleAddr, sample->medium);
|
||||||
@ -1280,7 +1279,7 @@ s32 AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, u32 fontDataAddr, Sample
|
|||||||
sample->sampleAddr, sample->medium);
|
sample->sampleAddr, sample->medium);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case AUDIOLOAD_ASYNC:
|
||||||
if (sample->medium = relocData->medium1) {
|
if (sample->medium = relocData->medium1) {
|
||||||
sampleRamAddr = AudioHeap_AllocTemporarySampleCache(sample->size, relocData->sampleBankId1,
|
sampleRamAddr = AudioHeap_AllocTemporarySampleCache(sample->size, relocData->sampleBankId1,
|
||||||
sample->sampleAddr, sample->medium);
|
sample->sampleAddr, sample->medium);
|
||||||
@ -1294,7 +1293,7 @@ s32 AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, u32 fontDataAddr, Sample
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (isAsync) {
|
switch (isAsync) {
|
||||||
case 0:
|
case AUDIOLOAD_SYNC:
|
||||||
if (sample->medium == MEDIUM_UNK) {
|
if (sample->medium == MEDIUM_UNK) {
|
||||||
AudioLoad_SyncDmaUnkMedium(sample->sampleAddr, sampleRamAddr, sample->size,
|
AudioLoad_SyncDmaUnkMedium(sample->sampleAddr, sampleRamAddr, sample->size,
|
||||||
gSampleBankTable->unkMediumParam);
|
gSampleBankTable->unkMediumParam);
|
||||||
@ -1306,7 +1305,7 @@ s32 AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, u32 fontDataAddr, Sample
|
|||||||
sample->medium = MEDIUM_RAM;
|
sample->medium = MEDIUM_RAM;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case AUDIOLOAD_ASYNC:
|
||||||
size = gPreloadSampleStackTop;
|
size = gPreloadSampleStackTop;
|
||||||
gPreloadSampleStack[size].sample = sample;
|
gPreloadSampleStack[size].sample = sample;
|
||||||
gPreloadSampleStack[size].ramAddr = sampleRamAddr;
|
gPreloadSampleStack[size].ramAddr = sampleRamAddr;
|
||||||
|
@ -375,47 +375,47 @@ void func_80012438(SequenceLayer* layer, s32 arg1) {
|
|||||||
note->playbackState.adsr.fadeOutVel = gAudioBufferParams.ticksPerUpdateInv;
|
note->playbackState.adsr.fadeOutVel = gAudioBufferParams.ticksPerUpdateInv;
|
||||||
note->playbackState.adsr.action.asByte |= 0x10;
|
note->playbackState.adsr.action.asByte |= 0x10;
|
||||||
}
|
}
|
||||||
return;
|
} else {
|
||||||
}
|
noteAttr = ¬e->playbackState.attributes;
|
||||||
noteAttr = ¬e->playbackState.attributes;
|
if (note->playbackState.adsr.state != 6) {
|
||||||
if (note->playbackState.adsr.state != 6) {
|
noteAttr->freqMod = layer->noteFreqMod;
|
||||||
noteAttr->freqMod = layer->noteFreqMod;
|
noteAttr->velocity = layer->noteVelocity;
|
||||||
noteAttr->velocity = layer->noteVelocity;
|
noteAttr->pan = layer->notePan;
|
||||||
noteAttr->pan = layer->notePan;
|
noteAttr->stereo = layer->stereo;
|
||||||
noteAttr->stereo = layer->stereo;
|
if (layer->channel != NULL) {
|
||||||
if (layer->channel != NULL) {
|
noteAttr->reverb = layer->channel->targetReverbVol;
|
||||||
noteAttr->reverb = layer->channel->targetReverbVol;
|
noteAttr->gain = layer->channel->reverbIndex;
|
||||||
noteAttr->gain = layer->channel->reverbIndex;
|
if (layer->channel->seqPlayer->muted && (layer->channel->muteBehavior & 8)) {
|
||||||
if (layer->channel->seqPlayer->muted && (layer->channel->muteBehavior & 8)) {
|
note->noteSubEu.bitField0.finished = 1;
|
||||||
note->noteSubEu.bitField0.finished = 1;
|
}
|
||||||
}
|
}
|
||||||
}
|
note->playbackState.priority = 1;
|
||||||
note->playbackState.priority = 1;
|
note->playbackState.prevParentLayer = note->playbackState.parentLayer;
|
||||||
note->playbackState.prevParentLayer = note->playbackState.parentLayer;
|
note->playbackState.parentLayer = NO_LAYER;
|
||||||
note->playbackState.parentLayer = NO_LAYER;
|
|
||||||
|
|
||||||
if (arg1 == 7) {
|
if (arg1 == 7) {
|
||||||
note->playbackState.adsr.fadeOutVel = gAudioBufferParams.ticksPerUpdateInv;
|
note->playbackState.adsr.fadeOutVel = gAudioBufferParams.ticksPerUpdateInv;
|
||||||
note->playbackState.adsr.action.asByte |= 0x10;
|
note->playbackState.adsr.action.asByte |= 0x10;
|
||||||
note->playbackState.unk_04 = 2;
|
note->playbackState.unk_04 = 2;
|
||||||
|
|
||||||
} else {
|
|
||||||
note->playbackState.unk_04 = 1;
|
|
||||||
note->playbackState.adsr.action.asByte |= 0x20;
|
|
||||||
if (layer->adsr.decayIndex == 0) {
|
|
||||||
note->playbackState.adsr.fadeOutVel =
|
|
||||||
layer->channel->adsr.decayIndex * gAudioBufferParams.ticksPerUpdateInvScaled;
|
|
||||||
} else {
|
} else {
|
||||||
note->playbackState.adsr.fadeOutVel =
|
note->playbackState.unk_04 = 1;
|
||||||
layer->adsr.decayIndex * gAudioBufferParams.ticksPerUpdateInvScaled;
|
note->playbackState.adsr.action.asByte |= 0x20;
|
||||||
|
if (layer->adsr.decayIndex == 0) {
|
||||||
|
note->playbackState.adsr.fadeOutVel =
|
||||||
|
layer->channel->adsr.decayIndex * gAudioBufferParams.ticksPerUpdateInvScaled;
|
||||||
|
} else {
|
||||||
|
note->playbackState.adsr.fadeOutVel =
|
||||||
|
layer->adsr.decayIndex * gAudioBufferParams.ticksPerUpdateInvScaled;
|
||||||
|
}
|
||||||
|
note->playbackState.adsr.sustain =
|
||||||
|
(s32) layer->channel->adsr.sustain * note->playbackState.adsr.current / 256.0f;
|
||||||
}
|
}
|
||||||
note->playbackState.adsr.sustain =
|
|
||||||
(s32) layer->channel->adsr.sustain * note->playbackState.adsr.current / 256.0f;
|
|
||||||
}
|
}
|
||||||
}
|
if (arg1 == 6) {
|
||||||
if (arg1 == 6) {
|
func_80012C40(note);
|
||||||
func_80012C40(note);
|
func_80012C00(¬e->listItem.pool->decaying, ¬e->listItem);
|
||||||
func_80012C00(¬e->listItem.pool->decaying, ¬e->listItem);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,37 +502,37 @@ void func_800128B4(void) {
|
|||||||
|
|
||||||
void func_80012964(NotePool* pool) {
|
void func_80012964(NotePool* pool) {
|
||||||
s32 poolType;
|
s32 poolType;
|
||||||
AudioListItem* sp48;
|
AudioListItem* poolItem;
|
||||||
AudioListItem* var_s0;
|
AudioListItem* nextPoolItem;
|
||||||
AudioListItem* sp40;
|
AudioListItem* freeList;
|
||||||
|
|
||||||
for (poolType = 0; poolType < 4; poolType++) {
|
for (poolType = 0; poolType < 4; poolType++) {
|
||||||
switch (poolType) {
|
switch (poolType) {
|
||||||
case 0:
|
case 0:
|
||||||
sp48 = &pool->disabled;
|
poolItem = &pool->disabled;
|
||||||
sp40 = &gNoteFreeLists.disabled;
|
freeList = &gNoteFreeLists.disabled;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sp48 = &pool->decaying;
|
poolItem = &pool->decaying;
|
||||||
sp40 = &gNoteFreeLists.decaying;
|
freeList = &gNoteFreeLists.decaying;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sp48 = &pool->releasing;
|
poolItem = &pool->releasing;
|
||||||
sp40 = &gNoteFreeLists.releasing;
|
freeList = &gNoteFreeLists.releasing;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sp48 = &pool->active;
|
poolItem = &pool->active;
|
||||||
sp40 = &gNoteFreeLists.active;
|
freeList = &gNoteFreeLists.active;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var_s0 = sp48->next;
|
nextPoolItem = poolItem->next;
|
||||||
if ((var_s0 == sp48) || (var_s0 == NULL)) {
|
if ((nextPoolItem == poolItem) || (nextPoolItem == NULL)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
func_80012C40((Note*) var_s0);
|
func_80012C40((Note*) nextPoolItem);
|
||||||
func_800145BC(sp40, var_s0);
|
func_800145BC(freeList, nextPoolItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -540,9 +540,9 @@ void func_80012964(NotePool* pool) {
|
|||||||
void func_80012AC4(NotePool* pool, s32 arg1) {
|
void func_80012AC4(NotePool* pool, s32 arg1) {
|
||||||
s32 var_s0;
|
s32 var_s0;
|
||||||
s32 poolType;
|
s32 poolType;
|
||||||
AudioListItem* temp_v0;
|
AudioListItem* note;
|
||||||
AudioListItem* sp48;
|
AudioListItem* freeList;
|
||||||
AudioListItem* sp44;
|
AudioListItem* poolList;
|
||||||
|
|
||||||
func_80012964(pool);
|
func_80012964(pool);
|
||||||
poolType = 0;
|
poolType = 0;
|
||||||
@ -553,28 +553,28 @@ void func_80012AC4(NotePool* pool, s32 arg1) {
|
|||||||
}
|
}
|
||||||
switch (poolType) {
|
switch (poolType) {
|
||||||
case 0:
|
case 0:
|
||||||
sp48 = &gNoteFreeLists.disabled;
|
freeList = &gNoteFreeLists.disabled;
|
||||||
sp44 = &pool->disabled;
|
poolList = &pool->disabled;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sp48 = &gNoteFreeLists.decaying;
|
freeList = &gNoteFreeLists.decaying;
|
||||||
sp44 = &pool->decaying;
|
poolList = &pool->decaying;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sp48 = &gNoteFreeLists.releasing;
|
freeList = &gNoteFreeLists.releasing;
|
||||||
sp44 = &pool->releasing;
|
poolList = &pool->releasing;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
sp48 = &gNoteFreeLists.active;
|
freeList = &gNoteFreeLists.active;
|
||||||
sp44 = &pool->active;
|
poolList = &pool->active;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while (var_s0 < arg1) {
|
while (var_s0 < arg1) {
|
||||||
temp_v0 = func_800145FC(sp48);
|
note = func_800145FC(freeList);
|
||||||
if (temp_v0 == NULL) {
|
if (note == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
func_800145BC(sp44, temp_v0);
|
func_800145BC(poolList, note);
|
||||||
var_s0++;
|
var_s0++;
|
||||||
}
|
}
|
||||||
poolType++;
|
poolType++;
|
||||||
|
@ -44,7 +44,7 @@ void func_80013EA0(SequenceChannel* channel) {
|
|||||||
channel->finished = 0;
|
channel->finished = 0;
|
||||||
channel->stopScript = 0;
|
channel->stopScript = 0;
|
||||||
channel->muted = 0;
|
channel->muted = 0;
|
||||||
channel->hasInstrument = 0;
|
channel->hasInstrument = false;
|
||||||
channel->stereoHeadsetEffects = 0;
|
channel->stereoHeadsetEffects = 0;
|
||||||
channel->transposition = 0;
|
channel->transposition = 0;
|
||||||
channel->largeNotes = 0;
|
channel->largeNotes = 0;
|
||||||
@ -688,11 +688,11 @@ void func_80015330(SequenceChannel* channel, u8 arg1) {
|
|||||||
channel->instrument = (Instrument*) 1;
|
channel->instrument = (Instrument*) 1;
|
||||||
} else {
|
} else {
|
||||||
if ((channel->instOrWave = func_800152C0(channel, arg1, &channel->instrument, &channel->adsr)) == 0) {
|
if ((channel->instOrWave = func_800152C0(channel, arg1, &channel->instrument, &channel->adsr)) == 0) {
|
||||||
channel->hasInstrument = 0;
|
channel->hasInstrument = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
channel->hasInstrument = 1;
|
channel->hasInstrument = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_800153C4(SequenceChannel* channel, u8 arg1) {
|
void func_800153C4(SequenceChannel* channel, u8 arg1) {
|
||||||
@ -825,7 +825,7 @@ void func_800153E8(SequenceChannel* channel) {
|
|||||||
sp52 = ((u16*) gSeqFontTable)[seqPlayer->seqId];
|
sp52 = ((u16*) gSeqFontTable)[seqPlayer->seqId];
|
||||||
loBits = gSeqFontTable[sp52];
|
loBits = gSeqFontTable[sp52];
|
||||||
cmd = gSeqFontTable[sp52 + loBits - cmd];
|
cmd = gSeqFontTable[sp52 + loBits - cmd];
|
||||||
if (AudioHeap_SearchCaches(1, 2, cmd) != 0) {
|
if (AudioHeap_SearchCaches(FONT_TABLE, CACHE_EITHER, cmd) != NULL) {
|
||||||
channel->fontId = cmd;
|
channel->fontId = cmd;
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
@ -912,7 +912,7 @@ void func_800153E8(SequenceChannel* channel) {
|
|||||||
sp52 = ((u16*) gSeqFontTable)[seqPlayer->seqId];
|
sp52 = ((u16*) gSeqFontTable)[seqPlayer->seqId];
|
||||||
loBits = gSeqFontTable[sp52];
|
loBits = gSeqFontTable[sp52];
|
||||||
cmd = gSeqFontTable[sp52 + loBits - cmd];
|
cmd = gSeqFontTable[sp52 + loBits - cmd];
|
||||||
if (AudioHeap_SearchCaches(1, 2, cmd) != 0) {
|
if (AudioHeap_SearchCaches(FONT_TABLE, CACHE_EITHER, cmd) != NULL) {
|
||||||
channel->fontId = cmd;
|
channel->fontId = cmd;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1387,7 +1387,7 @@ void func_800168BC(void) {
|
|||||||
s32 i;
|
s32 i;
|
||||||
s32 j;
|
s32 j;
|
||||||
|
|
||||||
for (i = 0; i < 48; i++) {
|
for (i = 0; i < ARRAY_COUNT(gSeqChannels); i++) {
|
||||||
gSeqChannels[i].seqPlayer = NULL;
|
gSeqChannels[i].seqPlayer = NULL;
|
||||||
gSeqChannels[i].enabled = false;
|
gSeqChannels[i].enabled = false;
|
||||||
#ifdef AVOID_UB
|
#ifdef AVOID_UB
|
||||||
@ -1400,7 +1400,7 @@ void func_800168BC(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func_8001463C();
|
func_8001463C();
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < ARRAY_COUNT(gSeqLayers); i++) {
|
||||||
gSeqLayers[i].channel = NULL;
|
gSeqLayers[i].channel = NULL;
|
||||||
gSeqLayers[i].enabled = false;
|
gSeqLayers[i].enabled = false;
|
||||||
}
|
}
|
||||||
|
@ -1,99 +1,119 @@
|
|||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
#include "sf64audio_external.h"
|
#include "sf64audio_provisional.h"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* 0x00 */ s16 numEntries;
|
|
||||||
/* 0x02 */ s16 unkMediumParam;
|
|
||||||
/* 0x04 */ u32 romAddr;
|
|
||||||
/* 0x08 */ char pad[0x8];
|
|
||||||
} AudioTableBase;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* 0x00 */ u32 romAddr;
|
|
||||||
/* 0x04 */ u32 size;
|
|
||||||
/* 0x08 */ s8 medium;
|
|
||||||
/* 0x09 */ s8 cachePolicy;
|
|
||||||
/* 0x0A */ s16 shortData1;
|
|
||||||
/* 0x0C */ s16 shortData2;
|
|
||||||
/* 0x0E */ s16 shortData3;
|
|
||||||
} AudioTableEntry; // size = 0x10
|
|
||||||
|
|
||||||
AudioTableBase gSampleBankTableInit = { 4, 0, 0 };
|
AudioTableBase gSampleBankTableInit = { 4, 0, 0 };
|
||||||
AudioTableEntry gSampleBankTableInitEntries[4] = {
|
AudioTableEntry gSampleBankTableInitEntries[4] = {
|
||||||
{ 0, 0xE1E30, 2, 4, 0, 0, 0 },
|
{ 0x000000, 0x0E1E30, MEDIUM_CART, CACHEPOLICY_4 },
|
||||||
{ 0xE1E30, 0xFF9D0, 2, 4, 0, 0, 0 },
|
{ 0x0E1E30, 0x0FF9D0, MEDIUM_CART, CACHEPOLICY_4 },
|
||||||
{ 0x1E1800, 0x497480, 2, 4, 0, 0, 0 },
|
{ 0x1E1800, 0x497480, MEDIUM_CART, CACHEPOLICY_4 },
|
||||||
{ 0x678C80, 0xC3900, 2, 4, 0, 0, 0 },
|
{ 0x678C80, 0x0C3900, MEDIUM_CART, CACHEPOLICY_4 },
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioTableBase gSeqTableInit = { 66, 0, 0 };
|
AudioTableBase gSeqTableInit = { SEQ_ID_MAX, 0, 0 };
|
||||||
AudioTableEntry gSeqTableInitEntries[66] = {
|
AudioTableEntry gSeqTableInitEntries[SEQ_ID_MAX] = {
|
||||||
{ 0x00000, 0x3AF0, 2, 0, 0, 0, 0 }, { 0x03AF0, 0x56B0, 2, 0, 0, 0, 0 },
|
{ 0x00000, 0x3AF0, MEDIUM_CART, CACHEPOLICY_0 }, { 0x03AF0, 0x56B0, MEDIUM_CART, CACHEPOLICY_0 },
|
||||||
{ 0x091A0, 0x2D80, 2, 3, 0, 0, 0 }, { 0x0BF20, 0x1410, 2, 3, 0, 0, 0 },
|
{ 0x091A0, 0x2D80, MEDIUM_CART, CACHEPOLICY_3 }, { 0x0BF20, 0x1410, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x0D330, 0x1600, 2, 3, 0, 0, 0 }, { 0x0E930, 0xF20, 2, 3, 0, 0, 0 },
|
{ 0x0D330, 0x1600, MEDIUM_CART, CACHEPOLICY_3 }, { 0x0E930, 0xF20, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x0F850, 0x13A0, 2, 3, 0, 0, 0 }, { 0x010BF0, 0x1100, 2, 3, 0, 0, 0 },
|
{ 0x0F850, 0x13A0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x10BF0, 0x1100, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x011CF0, 0x19E0, 2, 3, 0, 0, 0 }, { 0x0136D0, 0x13E0, 2, 3, 0, 0, 0 },
|
{ 0x11CF0, 0x19E0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x136D0, 0x13E0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x014AB0, 0x12F0, 2, 3, 0, 0, 0 }, { SEQ_ID_SECTOR_Y, 0, 2, 3, 0, 0, 0 },
|
{ 0x14AB0, 0x12F0, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_SECTOR_Y, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x15DA0, 0xB70, 2, 3, 0, 0, 0 }, { 0x16910, 0x2460, 2, 3, 0, 0, 0 },
|
{ 0x15DA0, 0xB70, MEDIUM_CART, CACHEPOLICY_3 }, { 0x16910, 0x2460, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x18D70, 0xD40, 2, 3, 0, 0, 0 }, { SEQ_ID_FORTUNA, 0, 2, 3, 0, 0, 0 },
|
{ 0x18D70, 0xD40, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_FORTUNA, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_TITANIA, 0, 2, 3, 0, 0, 0 }, { 0x19AB0, 0x7F0, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_TITANIA, 0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x19AB0, 0x7F0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x1A2A0, 0x1440, 2, 3, 0, 0, 0 }, { 0x1B6E0, 0x1B20, 2, 3, 0, 0, 0 },
|
{ 0x1A2A0, 0x1440, MEDIUM_CART, CACHEPOLICY_3 }, { 0x1B6E0, 0x1B20, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_BOSS_ME, 0, 2, 3, 0, 0, 0 }, { SEQ_ID_BOSS_CO_1, 0, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_BOSS_ME, 0, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_BOSS_CO_1, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_BOSS_CO_1, 0, 2, 3, 0, 0, 0 }, { SEQ_ID_BOSS_ME, 0, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_BOSS_CO_1, 0, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_BOSS_ME, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_BOSS_ME, 0, 2, 3, 0, 0, 0 }, { 0x1D200, 0x1B30, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_BOSS_ME, 0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x1D200, 0x1B30, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_BOSS_CO_1, 0, 2, 3, 0, 0, 0 }, { SEQ_ID_BOSS_ME, 0, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_BOSS_CO_1, 0, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_BOSS_ME, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x1ED30, 0x10B0, 2, 3, 0, 0, 0 }, { SEQ_ID_BOSS_BO, 0, 2, 3, 0, 0, 0 },
|
{ 0x1ED30, 0x10B0, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_BOSS_BO, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_BOSS_ME, 0, 2, 3, 0, 0, 0 }, { SEQ_ID_BOSS_BO, 0, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_BOSS_ME, 0, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_BOSS_BO, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_BOSS_ME, 0, 2, 3, 0, 0, 0 }, { 0x1FDE0, 0x1410, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_BOSS_ME, 0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x1FDE0, 0x1410, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x211F0, 0xF30, 2, 3, 0, 0, 0 }, { 0x22120, 0x2B30, 2, 3, 0, 0, 0 },
|
{ 0x211F0, 0xF30, MEDIUM_CART, CACHEPOLICY_3 }, { 0x22120, 0x2B30, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x24C50, 0x7F0, 2, 3, 0, 0, 0 }, { 0x25440, 0x13B0, 2, 3, 0, 0, 0 },
|
{ 0x24C50, 0x7F0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x25440, 0x13B0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x267F0, 0xC70, 2, 3, 0, 0, 0 }, { 0x27460, 0x180, 2, 3, 0, 0, 0 },
|
{ 0x267F0, 0xC70, MEDIUM_CART, CACHEPOLICY_3 }, { 0x27460, 0x180, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x275E0, 0x5C0, 2, 3, 0, 0, 0 }, { SEQ_ID_TITLE, 0, 2, 3, 0, 0, 0 },
|
{ 0x275E0, 0x5C0, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_TITLE, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x27BA0, 0x4E40, 2, 3, 0, 0, 0 }, { 0x2C9E0, 0x14E0, 2, 3, 0, 0, 0 },
|
{ 0x27BA0, 0x4E40, MEDIUM_CART, CACHEPOLICY_3 }, { 0x2C9E0, 0x14E0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x2DEC0, 0x400, 2, 3, 0, 0, 0 }, { 0x2E2C0, 0x800, 2, 3, 0, 0, 0 },
|
{ 0x2DEC0, 0x400, MEDIUM_CART, CACHEPOLICY_3 }, { 0x2E2C0, 0x800, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x2EAC0, 0x1AB0, 2, 3, 0, 0, 0 }, { 0x30570, 0x1AA0, 2, 3, 0, 0, 0 },
|
{ 0x2EAC0, 0x1AB0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x30570, 0x1AA0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_BOSS_ME, 0, 2, 3, 0, 0, 0 }, { 0x32010, 0x1370, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_BOSS_ME, 0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x32010, 0x1370, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x33380, 0xB80, 2, 3, 0, 0, 0 }, { 0x33F00, 0x5C0, 2, 3, 0, 0, 0 },
|
{ 0x33380, 0xB80, MEDIUM_CART, CACHEPOLICY_3 }, { 0x33F00, 0x5C0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ SEQ_ID_CO_INTRO, 0, 2, 3, 0, 0, 0 }, { SEQ_ID_CO_INTRO, 0, 2, 3, 0, 0, 0 },
|
{ SEQ_ID_CO_INTRO, 0, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_CO_INTRO, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x344C0, 0x550, 2, 3, 0, 0, 0 }, { 0x34A10, 0x360, 2, 3, 0, 0, 0 },
|
{ 0x344C0, 0x550, MEDIUM_CART, CACHEPOLICY_3 }, { 0x34A10, 0x360, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x34D70, 0x620, 2, 3, 0, 0, 0 }, { SEQ_ID_VS_MENU, 0, 2, 3, 0, 0, 0 },
|
{ 0x34D70, 0x620, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_VS_MENU, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x35390, 0xA70, 2, 3, 0, 0, 0 }, { SEQ_ID_STAR_WOLF, 0, 2, 3, 0, 0, 0 },
|
{ 0x35390, 0xA70, MEDIUM_CART, CACHEPOLICY_3 }, { SEQ_ID_STAR_WOLF, 0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x35E00, 0xAB0, 2, 3, 0, 0, 0 }, { 0x368B0, 0x13D0, 2, 3, 0, 0, 0 },
|
{ 0x35E00, 0xAB0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x368B0, 0x13D0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x37C80, 0x250, 2, 3, 0, 0, 0 }, { 0x37ED0, 0x6F0, 2, 3, 0, 0, 0 },
|
{ 0x37C80, 0x250, MEDIUM_CART, CACHEPOLICY_3 }, { 0x37ED0, 0x6F0, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
{ 0x385C0, 0xFB0, 2, 3, 0, 0, 0 }, { 0x39570, 0x1780, 2, 3, 0, 0, 0 },
|
{ 0x385C0, 0xFB0, MEDIUM_CART, CACHEPOLICY_3 }, { 0x39570, 0x1780, MEDIUM_CART, CACHEPOLICY_3 },
|
||||||
};
|
};
|
||||||
|
#define SOUNDFONT_ENTRY(offset, size, medium, cachePolicy, bank1, bank2, numInst, numDrums) \
|
||||||
|
{ \
|
||||||
|
offset, size, medium, cachePolicy, (((bank1) &0xFF) << 8) | ((bank2) &0xFF), \
|
||||||
|
(((numInst) &0xFF) << 8) | ((numDrums) &0xFF) \
|
||||||
|
}
|
||||||
|
|
||||||
AudioTableBase gSoundFontTableInit = { 33, 0, 0 };
|
AudioTableBase gSoundFontTableInit = { 33, 0, 0 };
|
||||||
AudioTableEntry gSoundFontTableInitEntries[33] = {
|
AudioTableEntry gSoundFontTableInitEntries[33] = {
|
||||||
{ 0, 0x2F00, 2, 0, 0xFF, 0x7F00, 0 }, { 0x2F00, 0xFE0, 2, 0, 0x1FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x00000, 0x2F00, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_SFX, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x3EE0, 0x640, 2, 0, 0x2FF, 0x7F00, 0 }, { 0x4520, 0x1560, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x02F00, 0x0FE0, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_MAP, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x5A80, 0xC00, 2, 0, 0x2FF, 0x7F00, 0 }, { 0x6680, 0xDE0, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x03EE0, 0x0640, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x7460, 0x1200, 2, 0, 0x2FF, 0x7F00, 0 }, { 0x8660, 0x1040, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x04520, 0x1560, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x96A0, 0xE40, 2, 0, 0x2FF, 0x7F00, 0 }, { 0xA4E0, 0xC20, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x05A80, 0x0C00, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0xB100, 0x1920, 2, 0, 0x2FF, 0x7F00, 0 }, { 0xCA20, 0xA20, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x06680, 0x0DE0, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0xD440, 0xA00, 2, 0, 0x2FF, 0x7F00, 0 }, { 0xDE40, 0xD60, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x07460, 0x1200, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0xEBA0, 0xC20, 2, 0, 0x2FF, 0x7F00, 0 }, { 0xF7C0, 0xF00, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x08660, 0x1040, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x106C0, 0xF20, 2, 0, 0x2FF, 0x7F00, 0 }, { 0x115E0, 0xE20, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x096A0, 0x0E40, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x12400, 0x10A0, 2, 0, 0x2FF, 0x7F00, 0 }, { 0x134A0, 0x2580, 2, 0, 0x2FF, 0x7F00, 0 },
|
SOUNDFONT_ENTRY(0x0A4E0, 0x0C20, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x15A20, 0x9E0, 2, 0, 0x2FF, 0x7F00, 0 }, { 0x16400, 0x1220, 2, 3, 0x3FF, 0x1040, 0 },
|
SOUNDFONT_ENTRY(0x0B100, 0x1920, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x17620, 0x180, 2, 3, 0x3FF, 0x300, 0 }, { 0x177A0, 0x11C0, 2, 3, 0x3FF, 0x1040, 0 },
|
SOUNDFONT_ENTRY(0x0CA20, 0x0A20, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x18960, 0x940, 2, 3, 0x3FF, 0xA40, 0 }, { 0x192A0, 0x9E0, 2, 3, 0x3FF, 0xA40, 0 },
|
SOUNDFONT_ENTRY(0x0D440, 0x0A00, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x19C80, 0x920, 2, 3, 0x3FF, 0xA40, 0 }, { 0x1A5A0, 0x9E0, 2, 3, 0x3FF, 0xA40, 0 },
|
SOUNDFONT_ENTRY(0x0DE40, 0x0D60, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x1AF80, 0x9E0, 2, 3, 0x3FF, 0xA40, 0 }, { 0x1B960, 0xA10, 2, 3, 0x3FF, 0xA40, 0 },
|
SOUNDFONT_ENTRY(0x0EBA0, 0x0C20, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x1C370, 0x9E0, 2, 3, 0x3FF, 0xA40, 0 }, { 0x1CD50, 0xA00, 2, 3, 0x3FF, 0xA40, 0 },
|
SOUNDFONT_ENTRY(0x0F7C0, 0x0F00, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
{ 0x1D750, 0x8D0, 2, 3, 0x3FF, 0xA40, 0 },
|
SOUNDFONT_ENTRY(0x106C0, 0x0F20, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
|
SOUNDFONT_ENTRY(0x115E0, 0x0E20, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
|
SOUNDFONT_ENTRY(0x12400, 0x10A0, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
|
SOUNDFONT_ENTRY(0x134A0, 0x2580, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
|
SOUNDFONT_ENTRY(0x15A20, 0x09E0, MEDIUM_CART, CACHEPOLICY_0, SAMPLES_VOICE, SAMPLES_NONE, 127, 0),
|
||||||
|
SOUNDFONT_ENTRY(0x16400, 0x1220, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 16, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x17620, 0x0180, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 3, 0),
|
||||||
|
SOUNDFONT_ENTRY(0x177A0, 0x11C0, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 16, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x18960, 0x0940, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x192A0, 0x09E0, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x19C80, 0x0920, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x1A5A0, 0x09E0, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x1AF80, 0x09E0, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x1B960, 0x0A10, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x1C370, 0x09E0, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x1CD50, 0x0A00, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
|
SOUNDFONT_ENTRY(0x1D750, 0x08D0, MEDIUM_CART, CACHEPOLICY_3, SAMPLES_INST, SAMPLES_NONE, 10, 64),
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 gSeqFontTableInit[288] = {
|
#define AS_BYTES(x) (((x) >> 8) & 0xFF), ((x) &0xFF)
|
||||||
0, 132, 0, 134, 0, 155, 0, 157, 0, 159, 0, 161, 0, 163, 0, 165, 0, 167, 0, 169, 0, 171, 0, 173,
|
|
||||||
0, 175, 0, 177, 0, 179, 0, 181, 0, 183, 0, 185, 0, 187, 0, 189, 0, 191, 0, 193, 0, 195, 0, 197,
|
// clang-format off
|
||||||
0, 199, 0, 201, 0, 203, 0, 205, 0, 207, 0, 209, 0, 211, 0, 213, 0, 215, 0, 217, 0, 219, 0, 221,
|
|
||||||
0, 223, 0, 225, 0, 227, 0, 229, 0, 231, 0, 233, 0, 235, 0, 237, 0, 239, 0, 241, 0, 243, 0, 245,
|
u8 gSeqFontTableInit[283] = {
|
||||||
0, 247, 0, 249, 0, 251, 0, 253, 0, 255, 1, 1, 1, 3, 1, 5, 1, 7, 1, 9, 1, 11, 1, 13,
|
// Offset into this table for sequence sound font list
|
||||||
1, 15, 1, 17, 1, 19, 1, 21, 1, 23, 1, 25, 1, 0, 20, 20, 19, 18, 17, 16, 15, 14, 13, 12,
|
AS_BYTES(132), AS_BYTES(134), AS_BYTES(155), AS_BYTES(157), AS_BYTES(159), AS_BYTES(161), AS_BYTES(163),
|
||||||
11, 10, 9, 8, 7, 6, 5, 4, 3, 1, 2, 1, 24, 1, 29, 1, 25, 1, 26, 1, 28, 1, 25, 1,
|
AS_BYTES(165), AS_BYTES(167), AS_BYTES(169), AS_BYTES(171), AS_BYTES(173), AS_BYTES(175), AS_BYTES(177),
|
||||||
25, 1, 29, 1, 24, 1, 29, 1, 28, 1, 25, 1, 30, 1, 24, 1, 25, 1, 28, 1, 28, 1, 31, 1,
|
AS_BYTES(179), AS_BYTES(181), AS_BYTES(183), AS_BYTES(185), AS_BYTES(187), AS_BYTES(189), AS_BYTES(191),
|
||||||
31, 1, 28, 1, 28, 1, 31, 1, 31, 1, 31, 1, 28, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1,
|
AS_BYTES(193), AS_BYTES(195), AS_BYTES(197), AS_BYTES(199), AS_BYTES(201), AS_BYTES(203), AS_BYTES(205),
|
||||||
31, 1, 32, 1, 21, 1, 21, 1, 22, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 23, 1, 25, 1,
|
AS_BYTES(207), AS_BYTES(209), AS_BYTES(211), AS_BYTES(213), AS_BYTES(215), AS_BYTES(217), AS_BYTES(219),
|
||||||
21, 1, 21, 1, 29, 1, 25, 1, 31, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1,
|
AS_BYTES(221), AS_BYTES(223), AS_BYTES(225), AS_BYTES(227), AS_BYTES(229), AS_BYTES(231), AS_BYTES(233),
|
||||||
21, 1, 21, 1, 27, 1, 25, 1, 21, 1, 25, 1, 25, 1, 25, 1, 21, 1, 31, 0, 0, 0, 0, 0,
|
AS_BYTES(235), AS_BYTES(237), AS_BYTES(239), AS_BYTES(241), AS_BYTES(243), AS_BYTES(245), AS_BYTES(247),
|
||||||
|
AS_BYTES(249), AS_BYTES(251), AS_BYTES(253), AS_BYTES(255), AS_BYTES(257), AS_BYTES(259), AS_BYTES(261),
|
||||||
|
AS_BYTES(263), AS_BYTES(265), AS_BYTES(267), AS_BYTES(269), AS_BYTES(271), AS_BYTES(273), AS_BYTES(275),
|
||||||
|
AS_BYTES(277), AS_BYTES(279), AS_BYTES(281),
|
||||||
|
|
||||||
|
// sound font for SFX sequence
|
||||||
|
1, 0,
|
||||||
|
// sound fonts voice sequence
|
||||||
|
20, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 1, 2,
|
||||||
|
// sound fonts for BGM sequences. Each sequence has a single sound font.
|
||||||
|
1, 24, 1, 29, 1, 25, 1, 26, 1, 28, 1, 25, 1, 25, 1, 29, 1, 24, 1, 29, 1, 28, 1, 25, 1, 30, 1, 24, 1, 25, 1, 28,
|
||||||
|
1, 28, 1, 31, 1, 31, 1, 28, 1, 28, 1, 31, 1, 31, 1, 31, 1, 28, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32,
|
||||||
|
1, 21, 1, 21, 1, 22, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 23, 1, 25, 1, 21, 1, 21, 1, 29, 1, 25, 1, 31, 1, 21,
|
||||||
|
1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 27, 1, 25, 1, 21, 1, 25, 1, 25, 1, 25, 1, 21, 1, 31
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
@ -42,15 +42,15 @@ static const char devstr14[] = "Error : Queue is not empty ( %x ) \n";
|
|||||||
SPTask* AudioThread_CreateTask(void) {
|
SPTask* AudioThread_CreateTask(void) {
|
||||||
static s32 gMaxAbiCmdCnt = 128;
|
static s32 gMaxAbiCmdCnt = 128;
|
||||||
static SPTask* gWaitingAudioTask = NULL;
|
static SPTask* gWaitingAudioTask = NULL;
|
||||||
u32 sp54;
|
u32 aiSamplesLeft;
|
||||||
s32 sp50;
|
s32 abiCmdCount;
|
||||||
s32 sp4C;
|
s32 aiBuffIndex;
|
||||||
s32 pad48;
|
s32 pad48;
|
||||||
OSTask_t* task;
|
OSTask_t* task;
|
||||||
u16* sp40;
|
u16* aiBuffer;
|
||||||
s32 pad3C;
|
s32 pad3C;
|
||||||
u32 sp38;
|
u32 specId;
|
||||||
u32 sp34;
|
u32 msg;
|
||||||
s32 pad30;
|
s32 pad30;
|
||||||
|
|
||||||
gAudioTaskCountQ++;
|
gAudioTaskCountQ++;
|
||||||
@ -62,54 +62,54 @@ SPTask* AudioThread_CreateTask(void) {
|
|||||||
gCurAiBuffIndex++;
|
gCurAiBuffIndex++;
|
||||||
gCurAiBuffIndex %= 3;
|
gCurAiBuffIndex %= 3;
|
||||||
|
|
||||||
sp4C = (gCurAiBuffIndex + 1) % 3;
|
aiBuffIndex = (gCurAiBuffIndex + 1) % 3;
|
||||||
sp54 = osAiGetLength() >> 2;
|
aiSamplesLeft = osAiGetLength() / 4;
|
||||||
if ((gResetTimer < 16) && (gAiBuffLengths[sp4C] != 0)) {
|
if ((gAudioResetTimer < 16) && (gAiBuffLengths[aiBuffIndex] != 0)) {
|
||||||
osAiSetNextBuffer(gAiBuffers[sp4C], gAiBuffLengths[sp4C] * 4);
|
osAiSetNextBuffer(gAiBuffers[aiBuffIndex], gAiBuffLengths[aiBuffIndex] * 4);
|
||||||
}
|
}
|
||||||
if (gCurAudioFrameDmaCount && gCurAudioFrameDmaCount) {}
|
if (gCurAudioFrameDmaCount && gCurAudioFrameDmaCount) {}
|
||||||
gCurAudioFrameDmaCount = 0;
|
gCurAudioFrameDmaCount = 0;
|
||||||
AudioLoad_DecreaseSampleDmaTtls();
|
AudioLoad_DecreaseSampleDmaTtls();
|
||||||
AudioLoad_ProcessLoads(gResetStatus);
|
AudioLoad_ProcessLoads(gAudioResetStep);
|
||||||
if (MQ_GET_MESG(gAudioSpecQueue, &sp38)) {
|
if (MQ_GET_MESG(gAudioSpecQueue, &specId)) {
|
||||||
if (gResetStatus == 0) {
|
if (gAudioResetStep == 0) {
|
||||||
gResetStatus = 5;
|
gAudioResetStep = 5;
|
||||||
}
|
}
|
||||||
gAudioSpecId = sp38;
|
gAudioSpecId = specId;
|
||||||
}
|
}
|
||||||
if ((gResetStatus != 0) && (AudioHeap_ResetStep() == 0)) {
|
if ((gAudioResetStep != 0) && (AudioHeap_ResetStep() == 0)) {
|
||||||
if (gResetStatus == 0) {
|
if (gAudioResetStep == 0) {
|
||||||
osSendMesg(gAudioResetQueue, (OSMesg) (s32) gAudioSpecId, OS_MESG_NOBLOCK);
|
osSendMesg(gAudioResetQueue, (OSMesg) (s32) gAudioSpecId, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
gWaitingAudioTask = NULL;
|
gWaitingAudioTask = NULL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (gResetTimer > 16) {
|
if (gAudioResetTimer > 16) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (gResetTimer != 0) {
|
if (gAudioResetTimer != 0) {
|
||||||
gResetTimer++;
|
gAudioResetTimer++;
|
||||||
}
|
}
|
||||||
gAudioCurTask = &gAudioRspTasks[gAudioTaskIndexQ];
|
gAudioCurTask = &gAudioRspTasks[gAudioTaskIndexQ];
|
||||||
gCurAbiCmdBuffer = gAbiCmdBuffs[gAudioTaskIndexQ];
|
gCurAbiCmdBuffer = gAbiCmdBuffs[gAudioTaskIndexQ];
|
||||||
sp4C = gCurAiBuffIndex;
|
aiBuffIndex = gCurAiBuffIndex;
|
||||||
sp40 = gAiBuffers[sp4C];
|
aiBuffer = gAiBuffers[aiBuffIndex];
|
||||||
gAiBuffLengths[sp4C] = ((gAudioBufferParams.samplesPerFrameTarget - sp54 + 0x80) & ~0xF) + 0x10;
|
gAiBuffLengths[aiBuffIndex] = ALIGN16_ALT(gAudioBufferParams.samplesPerFrameTarget - aiSamplesLeft + 0x80);
|
||||||
|
|
||||||
if (gAiBuffLengths[sp4C] < gAudioBufferParams.minAiBufferLength) {
|
if (gAiBuffLengths[aiBuffIndex] < gAudioBufferParams.minAiBufferLength) {
|
||||||
gAiBuffLengths[sp4C] = gAudioBufferParams.minAiBufferLength;
|
gAiBuffLengths[aiBuffIndex] = gAudioBufferParams.minAiBufferLength;
|
||||||
}
|
}
|
||||||
if (gAiBuffLengths[sp4C] > gAudioBufferParams.maxAiBufferLength) {
|
if (gAiBuffLengths[aiBuffIndex] > gAudioBufferParams.maxAiBufferLength) {
|
||||||
gAiBuffLengths[sp4C] = gAudioBufferParams.maxAiBufferLength;
|
gAiBuffLengths[aiBuffIndex] = gAudioBufferParams.maxAiBufferLength;
|
||||||
}
|
}
|
||||||
while (MQ_GET_MESG(gThreadCmdProcQueue, &sp34)) {
|
while (MQ_GET_MESG(gThreadCmdProcQueue, &msg)) {
|
||||||
AudioThread_ProcessCmds(sp34);
|
AudioThread_ProcessCmds(msg);
|
||||||
}
|
}
|
||||||
gCurAbiCmdBuffer = func_80009B64(gCurAbiCmdBuffer, &sp50, sp40, gAiBuffLengths[sp4C]);
|
gCurAbiCmdBuffer = func_80009B64(gCurAbiCmdBuffer, &abiCmdCount, aiBuffer, gAiBuffLengths[aiBuffIndex]);
|
||||||
gAudioRandom = osGetCount() * (gAudioRandom + gAudioTaskCountQ);
|
gAudioRandom = osGetCount() * (gAudioRandom + gAudioTaskCountQ);
|
||||||
gAudioRandom = gAiBuffers[sp4C][gAudioTaskCountQ & 0xFF] + gAudioRandom;
|
gAudioRandom = gAiBuffers[aiBuffIndex][gAudioTaskCountQ & 0xFF] + gAudioRandom;
|
||||||
|
|
||||||
sp4C = gAudioTaskIndexQ;
|
aiBuffIndex = gAudioTaskIndexQ;
|
||||||
|
|
||||||
gAudioCurTask->mesgQueue = NULL;
|
gAudioCurTask->mesgQueue = NULL;
|
||||||
gAudioCurTask->msg = NULL;
|
gAudioCurTask->msg = NULL;
|
||||||
@ -132,14 +132,14 @@ SPTask* AudioThread_CreateTask(void) {
|
|||||||
task->output_buff = NULL;
|
task->output_buff = NULL;
|
||||||
task->output_buff_size = NULL;
|
task->output_buff_size = NULL;
|
||||||
if (1) {}
|
if (1) {}
|
||||||
task->data_ptr = (u64*) gAbiCmdBuffs[sp4C];
|
task->data_ptr = (u64*) gAbiCmdBuffs[aiBuffIndex];
|
||||||
task->data_size = sp50 * sizeof(Acmd);
|
task->data_size = abiCmdCount * sizeof(Acmd);
|
||||||
|
|
||||||
task->yield_data_ptr = NULL;
|
task->yield_data_ptr = NULL;
|
||||||
task->yield_data_size = 0;
|
task->yield_data_size = 0;
|
||||||
|
|
||||||
if (gMaxAbiCmdCnt < sp50) {
|
if (gMaxAbiCmdCnt < abiCmdCount) {
|
||||||
gMaxAbiCmdCnt = sp50;
|
gMaxAbiCmdCnt = abiCmdCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gAudioBufferParams.count == 1) {
|
if (gAudioBufferParams.count == 1) {
|
||||||
@ -158,7 +158,7 @@ void AudioThread_ProcessGlobalCmd(AudioCmd* cmd) {
|
|||||||
AudioLoad_SyncLoadSeqParts(cmd->arg1, 3);
|
AudioLoad_SyncLoadSeqParts(cmd->arg1, 3);
|
||||||
break;
|
break;
|
||||||
case AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER:
|
case AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER:
|
||||||
case 0x88:
|
case AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER_ALT:
|
||||||
AudioLoad_SyncInitSeqPlayer(cmd->arg0, cmd->arg1, cmd->arg2);
|
AudioLoad_SyncInitSeqPlayer(cmd->arg0, cmd->arg1, cmd->arg2);
|
||||||
AudioThread_SetFadeInTimer(cmd->arg0, cmd->data);
|
AudioThread_SetFadeInTimer(cmd->arg0, cmd->data);
|
||||||
break;
|
break;
|
||||||
@ -171,7 +171,7 @@ void AudioThread_ProcessGlobalCmd(AudioCmd* cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x84:
|
case AUDIOCMD_OP_GLOBAL_UNK_84:
|
||||||
break;
|
break;
|
||||||
case AUDIOCMD_OP_GLOBAL_SET_SOUND_MODE:
|
case AUDIOCMD_OP_GLOBAL_SET_SOUND_MODE:
|
||||||
gAudioSoundMode = cmd->asUInt;
|
gAudioSoundMode = cmd->asUInt;
|
||||||
@ -422,9 +422,9 @@ void AudioThread_ResetAudioHeap(s32 specId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread_PreNMIReset(void) {
|
void AudioThread_PreNMIReset(void) {
|
||||||
gResetTimer = 1;
|
gAudioResetTimer = 1;
|
||||||
AudioThread_ResetAudioHeap(AUDIOSPEC_0);
|
AudioThread_ResetAudioHeap(AUDIOSPEC_0);
|
||||||
gResetStatus = 0;
|
gAudioResetStep = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread_Init(void) {
|
void AudioThread_Init(void) {
|
||||||
|
@ -1318,9 +1318,9 @@ void Option_SoundInit(void) {
|
|||||||
gVolumeSettings[AUDIO_TYPE_SFX] = 99;
|
gVolumeSettings[AUDIO_TYPE_SFX] = 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
Audio_SetVolume(0, gVolumeSettings[AUDIO_TYPE_MUSIC]);
|
Audio_SetVolume(AUDIO_TYPE_MUSIC, gVolumeSettings[AUDIO_TYPE_MUSIC]);
|
||||||
Audio_SetVolume(1, gVolumeSettings[AUDIO_TYPE_VOICE]);
|
Audio_SetVolume(AUDIO_TYPE_VOICE, gVolumeSettings[AUDIO_TYPE_VOICE]);
|
||||||
Audio_SetVolume(2, gVolumeSettings[AUDIO_TYPE_SFX]);
|
Audio_SetVolume(AUDIO_TYPE_SFX, gVolumeSettings[AUDIO_TYPE_SFX]);
|
||||||
|
|
||||||
D_menu_801AEB48[0].unk_18 = gVolumeSettings[AUDIO_TYPE_MUSIC] + 146.0f;
|
D_menu_801AEB48[0].unk_18 = gVolumeSettings[AUDIO_TYPE_MUSIC] + 146.0f;
|
||||||
D_menu_801AEB48[1].unk_18 = gVolumeSettings[AUDIO_TYPE_VOICE] + 146.0f;
|
D_menu_801AEB48[1].unk_18 = gVolumeSettings[AUDIO_TYPE_VOICE] + 146.0f;
|
||||||
|
BIN
tools/aifc_decode
Normal file
BIN
tools/aifc_decode
Normal file
Binary file not shown.
669
tools/aifc_decode.c
Normal file
669
tools/aifc_decode.c
Normal file
@ -0,0 +1,669 @@
|
|||||||
|
/**
|
||||||
|
* Bruteforcing decoder for converting ADPCM-encoded AIFC into AIFF, in a way
|
||||||
|
* that roundtrips with vadpcm_enc.
|
||||||
|
*/
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
typedef signed char s8;
|
||||||
|
typedef short s16;
|
||||||
|
typedef int s32;
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef unsigned long long u64;
|
||||||
|
typedef float f32;
|
||||||
|
|
||||||
|
#define bswap16(x) __builtin_bswap16(x)
|
||||||
|
#define bswap32(x) __builtin_bswap32(x)
|
||||||
|
#define BSWAP16(x) x = __builtin_bswap16(x)
|
||||||
|
#define BSWAP32(x) x = __builtin_bswap32(x)
|
||||||
|
#define BSWAP16_MANY(x, n) for (s32 _i = 0; _i < n; _i++) BSWAP16((x)[_i])
|
||||||
|
|
||||||
|
#define NORETURN __attribute__((noreturn))
|
||||||
|
#define UNUSED __attribute__((unused))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 ckID;
|
||||||
|
u32 ckSize;
|
||||||
|
} ChunkHeader;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 ckID;
|
||||||
|
u32 ckSize;
|
||||||
|
u32 formType;
|
||||||
|
} Chunk;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
s16 numChannels;
|
||||||
|
u16 numFramesH;
|
||||||
|
u16 numFramesL;
|
||||||
|
s16 sampleSize;
|
||||||
|
s16 sampleRate[5]; // 80-bit float
|
||||||
|
u16 compressionTypeH;
|
||||||
|
u16 compressionTypeL;
|
||||||
|
} CommonChunk;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
s16 MarkerID;
|
||||||
|
u16 positionH;
|
||||||
|
u16 positionL;
|
||||||
|
} Marker;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
s16 playMode;
|
||||||
|
s16 beginLoop;
|
||||||
|
s16 endLoop;
|
||||||
|
} Loop;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
s8 baseNote;
|
||||||
|
s8 detune;
|
||||||
|
s8 lowNote;
|
||||||
|
s8 highNote;
|
||||||
|
s8 lowVelocity;
|
||||||
|
s8 highVelocity;
|
||||||
|
s16 gain;
|
||||||
|
Loop sustainLoop;
|
||||||
|
Loop releaseLoop;
|
||||||
|
} InstrumentChunk;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
s32 offset;
|
||||||
|
s32 blockSize;
|
||||||
|
} SoundDataChunk;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
s16 version;
|
||||||
|
s16 order;
|
||||||
|
s16 nEntries;
|
||||||
|
} CodeChunk;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 start;
|
||||||
|
u32 end;
|
||||||
|
u32 count;
|
||||||
|
s16 state[16];
|
||||||
|
} ALADPCMloop;
|
||||||
|
|
||||||
|
|
||||||
|
static char usage[] = "input.aifc output.aiff";
|
||||||
|
static const char *progname, *infilename;
|
||||||
|
|
||||||
|
#define checked_fread(a, b, c, d) if (fread(a, b, c, d) != c) fail_parse("error parsing file")
|
||||||
|
|
||||||
|
NORETURN
|
||||||
|
void fail_parse(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char *formatted = NULL;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
int size = vsnprintf(NULL, 0, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
if (size >= 0) {
|
||||||
|
size++;
|
||||||
|
formatted = malloc(size);
|
||||||
|
if (formatted != NULL) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
size = vsnprintf(formatted, size, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
if (size < 0) {
|
||||||
|
free(formatted);
|
||||||
|
formatted = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formatted != NULL) {
|
||||||
|
fprintf(stderr, "%s: %s [%s]\n", progname, formatted, infilename);
|
||||||
|
free(formatted);
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 myrand()
|
||||||
|
{
|
||||||
|
static u64 state = 1619236481962341ULL;
|
||||||
|
state *= 3123692312231ULL;
|
||||||
|
state++;
|
||||||
|
return state >> 33;
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 qsample(s32 x, s32 scale)
|
||||||
|
{
|
||||||
|
// Compute x / 2^scale rounded to the nearest integer, breaking ties towards zero.
|
||||||
|
if (scale == 0) return x;
|
||||||
|
return (x + (1 << (scale - 1)) - (x > 0)) >> scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 clamp_to_s16(s32 x)
|
||||||
|
{
|
||||||
|
if (x < -0x8000) return -0x8000;
|
||||||
|
if (x > 0x7fff) return 0x7fff;
|
||||||
|
return (s16) x;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 toi4(s32 x)
|
||||||
|
{
|
||||||
|
if (x >= 8) return x - 16;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 readaifccodebook(FILE *fhandle, s32 ****table, s16 *order, s16 *npredictors)
|
||||||
|
{
|
||||||
|
checked_fread(order, sizeof(s16), 1, fhandle);
|
||||||
|
BSWAP16(*order);
|
||||||
|
checked_fread(npredictors, sizeof(s16), 1, fhandle);
|
||||||
|
BSWAP16(*npredictors);
|
||||||
|
*table = malloc(*npredictors * sizeof(s32 **));
|
||||||
|
for (s32 i = 0; i < *npredictors; i++) {
|
||||||
|
(*table)[i] = malloc(8 * sizeof(s32 *));
|
||||||
|
for (s32 j = 0; j < 8; j++) {
|
||||||
|
(*table)[i][j] = malloc((*order + 8) * sizeof(s32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < *npredictors; i++) {
|
||||||
|
s32 **table_entry = (*table)[i];
|
||||||
|
for (s32 j = 0; j < *order; j++) {
|
||||||
|
for (s32 k = 0; k < 8; k++) {
|
||||||
|
s16 ts;
|
||||||
|
checked_fread(&ts, sizeof(s16), 1, fhandle);
|
||||||
|
BSWAP16(ts);
|
||||||
|
table_entry[k][j] = ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 k = 1; k < 8; k++) {
|
||||||
|
table_entry[k][*order] = table_entry[k - 1][*order - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
table_entry[0][*order] = 1 << 11;
|
||||||
|
|
||||||
|
for (s32 k = 1; k < 8; k++) {
|
||||||
|
s32 j = 0;
|
||||||
|
for (; j < k; j++) {
|
||||||
|
table_entry[j][k + *order] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; j < 8; j++) {
|
||||||
|
table_entry[j][k + *order] = table_entry[j - k][*order];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALADPCMloop *readlooppoints(FILE *ifile, s16 *nloops)
|
||||||
|
{
|
||||||
|
checked_fread(nloops, sizeof(s16), 1, ifile);
|
||||||
|
BSWAP16(*nloops);
|
||||||
|
ALADPCMloop *al = malloc(*nloops * sizeof(ALADPCMloop));
|
||||||
|
for (s32 i = 0; i < *nloops; i++) {
|
||||||
|
checked_fread(&al[i], sizeof(ALADPCMloop), 1, ifile);
|
||||||
|
BSWAP32(al[i].start);
|
||||||
|
BSWAP32(al[i].end);
|
||||||
|
BSWAP32(al[i].count);
|
||||||
|
BSWAP16_MANY(al[i].state, 16);
|
||||||
|
}
|
||||||
|
return al;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 inner_product(s32 length, s32 *v1, s32 *v2)
|
||||||
|
{
|
||||||
|
s32 out = 0;
|
||||||
|
for (s32 i = 0; i < length; i++) {
|
||||||
|
out += v1[i] * v2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute "out / 2^11", rounded down.
|
||||||
|
s32 dout = out / (1 << 11);
|
||||||
|
s32 fiout = dout * (1 << 11);
|
||||||
|
return dout - (out - fiout < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void my_decodeframe(u8 *frame, s32 *state, s32 order, s32 ***coefTable)
|
||||||
|
{
|
||||||
|
s32 ix[16];
|
||||||
|
|
||||||
|
u8 header = frame[0];
|
||||||
|
s32 scale = 1 << (header >> 4);
|
||||||
|
s32 optimalp = header & 0xf;
|
||||||
|
|
||||||
|
for (s32 i = 0; i < 16; i += 2) {
|
||||||
|
u8 c = frame[1 + i/2];
|
||||||
|
ix[i] = c >> 4;
|
||||||
|
ix[i + 1] = c & 0xf;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < 16; i++) {
|
||||||
|
if (ix[i] >= 8) ix[i] -= 16;
|
||||||
|
ix[i] *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 j = 0; j < 2; j++) {
|
||||||
|
s32 in_vec[16];
|
||||||
|
if (j == 0) {
|
||||||
|
for (s32 i = 0; i < order; i++) {
|
||||||
|
in_vec[i] = state[16 - order + i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (s32 i = 0; i < order; i++) {
|
||||||
|
in_vec[i] = state[8 - order + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < 8; i++) {
|
||||||
|
s32 ind = j * 8 + i;
|
||||||
|
in_vec[order + i] = ix[ind];
|
||||||
|
state[ind] = inner_product(order + i, coefTable[optimalp][i], in_vec) + ix[ind];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void my_encodeframe(u8 *out, s16 *inBuffer, s32 *state, s32 ***coefTable, s32 order, s32 npredictors)
|
||||||
|
{
|
||||||
|
s16 ix[16];
|
||||||
|
s32 prediction[16];
|
||||||
|
s32 inVector[16];
|
||||||
|
s32 saveState[16];
|
||||||
|
s32 optimalp = 0;
|
||||||
|
s32 scale;
|
||||||
|
s32 ie[16];
|
||||||
|
s32 e[16];
|
||||||
|
f32 min = 1e30;
|
||||||
|
|
||||||
|
for (s32 k = 0; k < npredictors; k++) {
|
||||||
|
for (s32 j = 0; j < 2; j++) {
|
||||||
|
for (s32 i = 0; i < order; i++) {
|
||||||
|
inVector[i] = (j == 0 ? state[16 - order + i] : inBuffer[8 - order + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < 8; i++) {
|
||||||
|
prediction[j * 8 + i] = inner_product(order + i, coefTable[k][i], inVector);
|
||||||
|
e[j * 8 + i] = inVector[i + order] = inBuffer[j * 8 + i] - prediction[j * 8 + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 se = 0.0f;
|
||||||
|
for (s32 j = 0; j < 16; j++) {
|
||||||
|
se += (f32) e[j] * (f32) e[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (se < min) {
|
||||||
|
min = se;
|
||||||
|
optimalp = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 j = 0; j < 2; j++) {
|
||||||
|
for (s32 i = 0; i < order; i++) {
|
||||||
|
inVector[i] = (j == 0 ? state[16 - order + i] : inBuffer[8 - order + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < 8; i++) {
|
||||||
|
prediction[j * 8 + i] = inner_product(order + i, coefTable[optimalp][i], inVector);
|
||||||
|
e[j * 8 + i] = inVector[i + order] = inBuffer[j * 8 + i] - prediction[j * 8 + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < 16; i++) {
|
||||||
|
ie[i] = clamp_to_s16(e[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 max = 0;
|
||||||
|
for (s32 i = 0; i < 16; i++) {
|
||||||
|
if (abs(ie[i]) > abs(max)) {
|
||||||
|
max = ie[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (scale = 0; scale <= 12; scale++) {
|
||||||
|
if (max <= 7 && max >= -8) break;
|
||||||
|
max /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < 16; i++) {
|
||||||
|
saveState[i] = state[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 nIter = 0, again = 1; nIter < 2 && again; nIter++) {
|
||||||
|
again = 0;
|
||||||
|
if (nIter == 1) scale++;
|
||||||
|
if (scale > 12) {
|
||||||
|
scale = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 j = 0; j < 2; j++) {
|
||||||
|
s32 base = j * 8;
|
||||||
|
for (s32 i = 0; i < order; i++) {
|
||||||
|
inVector[i] = (j == 0 ?
|
||||||
|
saveState[16 - order + i] : state[8 - order + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < 8; i++) {
|
||||||
|
prediction[base + i] = inner_product(order + i, coefTable[optimalp][i], inVector);
|
||||||
|
s32 se = inBuffer[base + i] - prediction[base + i];
|
||||||
|
ix[base + i] = qsample(se, scale);
|
||||||
|
s32 cV = clamp_to_s16(ix[base + i]) - ix[base + i];
|
||||||
|
if (cV > 1 || cV < -1) again = 1;
|
||||||
|
ix[base + i] += cV;
|
||||||
|
inVector[i + order] = ix[base + i] * (1 << scale);
|
||||||
|
state[base + i] = prediction[base + i] + inVector[i + order];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 header = (scale << 4) | (optimalp & 0xf);
|
||||||
|
out[0] = header;
|
||||||
|
for (s32 i = 0; i < 16; i += 2) {
|
||||||
|
u8 c = ((ix[i] & 0xf) << 4) | (ix[i + 1] & 0xf);
|
||||||
|
out[1 + i/2] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void permute(s16 *out, s32 *in, s32 scale)
|
||||||
|
{
|
||||||
|
for (s32 i = 0; i < 16; i++) {
|
||||||
|
out[i] = clamp_to_s16(in[i] - scale / 2 + myrand() % (scale + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_header(FILE *ofile, const char *id, s32 size)
|
||||||
|
{
|
||||||
|
fwrite(id, 4, 1, ofile);
|
||||||
|
BSWAP32(size);
|
||||||
|
fwrite(&size, sizeof(s32), 1, ofile);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
s16 order = -1;
|
||||||
|
s16 nloops = 0;
|
||||||
|
ALADPCMloop *aloops = NULL;
|
||||||
|
s16 npredictors = -1;
|
||||||
|
s32 ***coefTable = NULL;
|
||||||
|
s32 state[16];
|
||||||
|
s32 soundPointer = -1;
|
||||||
|
s32 currPos = 0;
|
||||||
|
s32 nSamples = 0;
|
||||||
|
Chunk FormChunk;
|
||||||
|
ChunkHeader Header;
|
||||||
|
CommonChunk CommChunk;
|
||||||
|
InstrumentChunk InstChunk;
|
||||||
|
SoundDataChunk SndDChunk;
|
||||||
|
FILE *ifile;
|
||||||
|
FILE *ofile;
|
||||||
|
progname = argv[0];
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "%s %s\n", progname, usage);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
infilename = argv[1];
|
||||||
|
|
||||||
|
if ((ifile = fopen(infilename, "rb")) == NULL) {
|
||||||
|
fail_parse("AIFF-C file could not be opened");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ofile = fopen(argv[2], "wb")) == NULL) {
|
||||||
|
fprintf(stderr, "%s: output file could not be opened [%s]\n", progname, argv[2]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&InstChunk, 0, sizeof(InstChunk));
|
||||||
|
|
||||||
|
checked_fread(&FormChunk, sizeof(FormChunk), 1, ifile);
|
||||||
|
BSWAP32(FormChunk.ckID);
|
||||||
|
BSWAP32(FormChunk.formType);
|
||||||
|
if ((FormChunk.ckID != 0x464f524d) || (FormChunk.formType != 0x41494643)) { // FORM, AIFC
|
||||||
|
fail_parse("not an AIFF-C file");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
s32 num = fread(&Header, sizeof(Header), 1, ifile);
|
||||||
|
u32 ts;
|
||||||
|
if (num <= 0) break;
|
||||||
|
BSWAP32(Header.ckID);
|
||||||
|
BSWAP32(Header.ckSize);
|
||||||
|
|
||||||
|
Header.ckSize++;
|
||||||
|
Header.ckSize &= ~1;
|
||||||
|
s32 offset = ftell(ifile);
|
||||||
|
|
||||||
|
switch (Header.ckID) {
|
||||||
|
case 0x434f4d4d: // COMM
|
||||||
|
checked_fread(&CommChunk, sizeof(CommChunk), 1, ifile);
|
||||||
|
BSWAP16(CommChunk.numChannels);
|
||||||
|
BSWAP16(CommChunk.numFramesH);
|
||||||
|
BSWAP16(CommChunk.numFramesL);
|
||||||
|
BSWAP16(CommChunk.sampleSize);
|
||||||
|
BSWAP16(CommChunk.compressionTypeH);
|
||||||
|
BSWAP16(CommChunk.compressionTypeL);
|
||||||
|
s32 cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL;
|
||||||
|
if (cType != 0x56415043) { // VAPC
|
||||||
|
fail_parse("file is of the wrong compression type");
|
||||||
|
}
|
||||||
|
if (CommChunk.numChannels != 1) {
|
||||||
|
fail_parse("file contains %d channels, only 1 channel supported", CommChunk.numChannels);
|
||||||
|
}
|
||||||
|
if (CommChunk.sampleSize != 16) {
|
||||||
|
fail_parse("file contains %d bit samples, only 16 bit samples supported", CommChunk.sampleSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
nSamples = (CommChunk.numFramesH << 16) + CommChunk.numFramesL;
|
||||||
|
|
||||||
|
// Allow broken input lengths
|
||||||
|
if (nSamples % 16) {
|
||||||
|
nSamples--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nSamples % 16 != 0) {
|
||||||
|
fail_parse("number of chunks must be a multiple of 16, found %d", nSamples);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x53534e44: // SSND
|
||||||
|
checked_fread(&SndDChunk, sizeof(SndDChunk), 1, ifile);
|
||||||
|
BSWAP32(SndDChunk.offset);
|
||||||
|
BSWAP32(SndDChunk.blockSize);
|
||||||
|
assert(SndDChunk.offset == 0);
|
||||||
|
assert(SndDChunk.blockSize == 0);
|
||||||
|
soundPointer = ftell(ifile);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4150504c: // APPL
|
||||||
|
checked_fread(&ts, sizeof(u32), 1, ifile);
|
||||||
|
BSWAP32(ts);
|
||||||
|
if (ts == 0x73746f63) { // stoc
|
||||||
|
u8 len;
|
||||||
|
checked_fread(&len, 1, 1, ifile);
|
||||||
|
if (len == 11) {
|
||||||
|
char ChunkName[12];
|
||||||
|
s16 version;
|
||||||
|
checked_fread(ChunkName, 11, 1, ifile);
|
||||||
|
ChunkName[11] = '\0';
|
||||||
|
if (strcmp("VADPCMCODES", ChunkName) == 0) {
|
||||||
|
checked_fread(&version, sizeof(s16), 1, ifile);
|
||||||
|
BSWAP16(version);
|
||||||
|
if (version != 1) {
|
||||||
|
fail_parse("Unknown codebook chunk version");
|
||||||
|
}
|
||||||
|
readaifccodebook(ifile, &coefTable, &order, &npredictors);
|
||||||
|
}
|
||||||
|
else if (strcmp("VADPCMLOOPS", ChunkName) == 0) {
|
||||||
|
checked_fread(&version, sizeof(s16), 1, ifile);
|
||||||
|
BSWAP16(version);
|
||||||
|
if (version != 1) {
|
||||||
|
fail_parse("Unknown loop chunk version");
|
||||||
|
}
|
||||||
|
aloops = readlooppoints(ifile, &nloops);
|
||||||
|
if (nloops != 1) {
|
||||||
|
fail_parse("Only a single loop supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(ifile, offset + Header.ckSize, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coefTable == NULL) {
|
||||||
|
fail_parse("Codebook missing from bitstream");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < order; i++) {
|
||||||
|
state[15 - i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 outputBytes = nSamples * sizeof(s16);
|
||||||
|
u8 *outputBuf = malloc(outputBytes);
|
||||||
|
|
||||||
|
fseek(ifile, soundPointer, SEEK_SET);
|
||||||
|
while (currPos < nSamples) {
|
||||||
|
u8 input[9];
|
||||||
|
u8 encoded[9];
|
||||||
|
s32 lastState[16];
|
||||||
|
s32 decoded[16];
|
||||||
|
s16 guess[16];
|
||||||
|
s16 origGuess[16];
|
||||||
|
|
||||||
|
memcpy(lastState, state, sizeof(lastState));
|
||||||
|
checked_fread(input, 9, 1, ifile);
|
||||||
|
|
||||||
|
// Decode for real
|
||||||
|
my_decodeframe(input, state, order, coefTable);
|
||||||
|
memcpy(decoded, state, sizeof(lastState));
|
||||||
|
|
||||||
|
// Create a guess from that, by clamping to 16 bits
|
||||||
|
for (s32 i = 0; i < 16; i++) {
|
||||||
|
origGuess[i] = clamp_to_s16(state[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode the guess
|
||||||
|
memcpy(state, lastState, sizeof(lastState));
|
||||||
|
memcpy(guess, origGuess, sizeof(guess));
|
||||||
|
my_encodeframe(encoded, guess, state, coefTable, order, npredictors);
|
||||||
|
|
||||||
|
// If it doesn't match, randomly round numbers until it does.
|
||||||
|
if (memcmp(input, encoded, 9) != 0) {
|
||||||
|
s32 scale = 1 << (input[0] >> 4);
|
||||||
|
do {
|
||||||
|
permute(guess, decoded, scale);
|
||||||
|
memcpy(state, lastState, sizeof(lastState));
|
||||||
|
my_encodeframe(encoded, guess, state, coefTable, order, npredictors);
|
||||||
|
} while (memcmp(input, encoded, 9) != 0);
|
||||||
|
|
||||||
|
// Bring the matching closer to the original decode (not strictly
|
||||||
|
// necessary, but it will move us closer to the target on average).
|
||||||
|
for (s32 failures = 0; failures < 50; failures++) {
|
||||||
|
s32 ind = myrand() % 16;
|
||||||
|
s32 old = guess[ind];
|
||||||
|
if (old == origGuess[ind]) continue;
|
||||||
|
guess[ind] = origGuess[ind];
|
||||||
|
if (myrand() % 2) guess[ind] += (old - origGuess[ind]) / 2;
|
||||||
|
memcpy(state, lastState, sizeof(lastState));
|
||||||
|
my_encodeframe(encoded, guess, state, coefTable, order, npredictors);
|
||||||
|
if (memcmp(input, encoded, 9) == 0) {
|
||||||
|
failures = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
guess[ind] = old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(state, decoded, sizeof(lastState));
|
||||||
|
BSWAP16_MANY(guess, 16);
|
||||||
|
memcpy(outputBuf + currPos * 2, guess, sizeof(guess));
|
||||||
|
currPos += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write an incomplete file header. We'll fill in the size later.
|
||||||
|
fwrite("FORM\0\0\0\0AIFF", 12, 1, ofile);
|
||||||
|
|
||||||
|
// Subtract 4 from the COMM size to skip the compression field.
|
||||||
|
write_header(ofile, "COMM", sizeof(CommonChunk) - 4);
|
||||||
|
CommChunk.numFramesH = nSamples >> 16;
|
||||||
|
CommChunk.numFramesL = nSamples & 0xffff;
|
||||||
|
BSWAP16(CommChunk.numChannels);
|
||||||
|
BSWAP16(CommChunk.numFramesH);
|
||||||
|
BSWAP16(CommChunk.numFramesL);
|
||||||
|
BSWAP16(CommChunk.sampleSize);
|
||||||
|
fwrite(&CommChunk, sizeof(CommonChunk) - 4, 1, ofile);
|
||||||
|
|
||||||
|
if (nloops > 0) {
|
||||||
|
s32 startPos = aloops[0].start, endPos = aloops[0].end;
|
||||||
|
const char *markerNames[2] = {"start", "end"};
|
||||||
|
Marker markers[2] = {
|
||||||
|
{1, startPos >> 16, startPos & 0xffff},
|
||||||
|
{2, endPos >> 16, endPos & 0xffff}
|
||||||
|
};
|
||||||
|
write_header(ofile, "MARK", 2 + 2 * sizeof(Marker) + 1 + 5 + 1 + 3);
|
||||||
|
s16 numMarkers = bswap16(2);
|
||||||
|
fwrite(&numMarkers, sizeof(s16), 1, ofile);
|
||||||
|
for (s32 i = 0; i < 2; i++) {
|
||||||
|
u8 len = (u8) strlen(markerNames[i]);
|
||||||
|
BSWAP16(markers[i].MarkerID);
|
||||||
|
BSWAP16(markers[i].positionH);
|
||||||
|
BSWAP16(markers[i].positionL);
|
||||||
|
fwrite(&markers[i], sizeof(Marker), 1, ofile);
|
||||||
|
fwrite(&len, 1, 1, ofile);
|
||||||
|
fwrite(markerNames[i], len, 1, ofile);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_header(ofile, "INST", sizeof(InstrumentChunk));
|
||||||
|
InstChunk.sustainLoop.playMode = bswap16(1);
|
||||||
|
InstChunk.sustainLoop.beginLoop = bswap16(1);
|
||||||
|
InstChunk.sustainLoop.endLoop = bswap16(2);
|
||||||
|
InstChunk.releaseLoop.playMode = 0;
|
||||||
|
InstChunk.releaseLoop.beginLoop = 0;
|
||||||
|
InstChunk.releaseLoop.endLoop = 0;
|
||||||
|
fwrite(&InstChunk, sizeof(InstrumentChunk), 1, ofile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the coefficient table for use when encoding. Ideally this wouldn't
|
||||||
|
// be needed and "tabledesign -s 1" would generate the right table, but in
|
||||||
|
// practice it's difficult to adjust samples to make that happen.
|
||||||
|
write_header(ofile, "APPL", 4 + 12 + sizeof(CodeChunk) + npredictors * order * 8 * 2);
|
||||||
|
fwrite("stoc", 4, 1, ofile);
|
||||||
|
CodeChunk cChunk;
|
||||||
|
cChunk.version = bswap16(1);
|
||||||
|
cChunk.order = bswap16(order);
|
||||||
|
cChunk.nEntries = bswap16(npredictors);
|
||||||
|
fwrite("\x0bVADPCMCODES", 12, 1, ofile);
|
||||||
|
fwrite(&cChunk, sizeof(CodeChunk), 1, ofile);
|
||||||
|
for (s32 i = 0; i < npredictors; i++) {
|
||||||
|
for (s32 j = 0; j < order; j++) {
|
||||||
|
for (s32 k = 0; k < 8; k++) {
|
||||||
|
s16 ts = bswap16(coefTable[i][k][j]);
|
||||||
|
fwrite(&ts, sizeof(s16), 1, ofile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_header(ofile, "SSND", outputBytes + 8);
|
||||||
|
SndDChunk.offset = 0;
|
||||||
|
SndDChunk.blockSize = 0;
|
||||||
|
fwrite(&SndDChunk, sizeof(SoundDataChunk), 1, ofile);
|
||||||
|
fwrite(outputBuf, outputBytes, 1, ofile);
|
||||||
|
|
||||||
|
// Fix the size in the header
|
||||||
|
s32 fileSize = bswap32(ftell(ofile) - 8);
|
||||||
|
fseek(ofile, 4, SEEK_SET);
|
||||||
|
fwrite(&fileSize, 4, 1, ofile);
|
||||||
|
|
||||||
|
fclose(ifile);
|
||||||
|
fclose(ofile);
|
||||||
|
return 0;
|
||||||
|
}
|
867
tools/disassemble_sound.py
Normal file
867
tools/disassemble_sound.py
Normal file
@ -0,0 +1,867 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from collections import namedtuple, defaultdict
|
||||||
|
import tempfile
|
||||||
|
import subprocess
|
||||||
|
import uuid
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
TYPE_CTL = 1
|
||||||
|
TYPE_TBL = 2
|
||||||
|
|
||||||
|
|
||||||
|
class AifcEntry:
|
||||||
|
def __init__(self, data, book, loop):
|
||||||
|
self.name = None
|
||||||
|
self.data = data
|
||||||
|
self.book = book
|
||||||
|
self.loop = loop
|
||||||
|
self.tunings = []
|
||||||
|
|
||||||
|
|
||||||
|
class SampleBank:
|
||||||
|
def __init__(self, name, data, offset):
|
||||||
|
self.offset = offset
|
||||||
|
self.name = name
|
||||||
|
self.data = data
|
||||||
|
self.entries = {}
|
||||||
|
|
||||||
|
def add_sample(self, offset, sample_size, book, loop):
|
||||||
|
assert sample_size % 2 == 0
|
||||||
|
if sample_size % 9 != 0:
|
||||||
|
# print(sample_size)
|
||||||
|
assert sample_size % 9 == 1
|
||||||
|
sample_size -= 1
|
||||||
|
|
||||||
|
if offset in self.entries:
|
||||||
|
entry = self.entries[offset]
|
||||||
|
assert entry.book == book
|
||||||
|
assert entry.loop == loop
|
||||||
|
# print(len(entry.data), sample_size)
|
||||||
|
assert len(entry.data) == sample_size
|
||||||
|
else:
|
||||||
|
entry = AifcEntry(self.data[offset : offset + sample_size], book, loop)
|
||||||
|
self.entries[offset] = entry
|
||||||
|
|
||||||
|
return entry
|
||||||
|
|
||||||
|
|
||||||
|
Sound = namedtuple("Sound", ["sample_addr", "tuning"])
|
||||||
|
Drum = namedtuple("Drum", ["name", "addr", "release_rate", "pan", "envelope", "sound"])
|
||||||
|
Inst = namedtuple(
|
||||||
|
"Inst",
|
||||||
|
[
|
||||||
|
"name",
|
||||||
|
"addr",
|
||||||
|
"release_rate",
|
||||||
|
"normal_range_lo",
|
||||||
|
"normal_range_hi",
|
||||||
|
"envelope",
|
||||||
|
"sound_lo",
|
||||||
|
"sound_med",
|
||||||
|
"sound_hi",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
Book = namedtuple("Book", ["order", "npredictors", "table"])
|
||||||
|
Loop = namedtuple("Loop", ["start", "end", "count", "state"])
|
||||||
|
Envelope = namedtuple("Envelope", ["name", "entries"])
|
||||||
|
Bank = namedtuple(
|
||||||
|
"Bank",
|
||||||
|
[
|
||||||
|
"name",
|
||||||
|
"iso_date",
|
||||||
|
"sample_bank",
|
||||||
|
"insts",
|
||||||
|
"drums",
|
||||||
|
"all_insts",
|
||||||
|
"inst_list",
|
||||||
|
"envelopes",
|
||||||
|
"samples",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def align(val, al):
|
||||||
|
return (val + (al - 1)) & -al
|
||||||
|
|
||||||
|
|
||||||
|
name_tbl = {}
|
||||||
|
|
||||||
|
|
||||||
|
def gen_name(prefix, name_table=[]):
|
||||||
|
if prefix not in name_tbl:
|
||||||
|
name_tbl[prefix] = 0
|
||||||
|
ind = name_tbl[prefix]
|
||||||
|
name_tbl[prefix] += 1
|
||||||
|
if ind < len(name_table):
|
||||||
|
return name_table[ind]
|
||||||
|
return prefix + str(ind)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_bcd(data):
|
||||||
|
ret = 0
|
||||||
|
for c in data:
|
||||||
|
ret *= 10
|
||||||
|
ret += c >> 4
|
||||||
|
ret *= 10
|
||||||
|
ret += c & 15
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_f80(num):
|
||||||
|
num = float(num)
|
||||||
|
(f64,) = struct.unpack(">Q", struct.pack(">d", num))
|
||||||
|
f64_sign_bit = f64 & 2 ** 63
|
||||||
|
if num == 0.0:
|
||||||
|
if f64_sign_bit:
|
||||||
|
return b"\x80" + b"\0" * 9
|
||||||
|
else:
|
||||||
|
return b"\0" * 10
|
||||||
|
exponent = (f64 ^ f64_sign_bit) >> 52
|
||||||
|
assert exponent != 0, "can't handle denormals"
|
||||||
|
assert exponent != 0x7FF, "can't handle infinity/nan"
|
||||||
|
exponent -= 1023
|
||||||
|
f64_mantissa_bits = f64 & (2 ** 52 - 1)
|
||||||
|
f80_sign_bit = f64_sign_bit << (80 - 64)
|
||||||
|
f80_exponent = (exponent + 0x3FFF) << 64
|
||||||
|
f80_mantissa_bits = 2 ** 63 | (f64_mantissa_bits << (63 - 52))
|
||||||
|
f80 = f80_sign_bit | f80_exponent | f80_mantissa_bits
|
||||||
|
return struct.pack(">HQ", f80 >> 64, f80 & (2 ** 64 - 1))
|
||||||
|
|
||||||
|
|
||||||
|
def round_f32(num):
|
||||||
|
enc = struct.pack(">f", num)
|
||||||
|
for decimals in range(5, 20):
|
||||||
|
num2 = round(num, decimals)
|
||||||
|
if struct.pack(">f", num2) == enc:
|
||||||
|
return num2
|
||||||
|
return num
|
||||||
|
|
||||||
|
|
||||||
|
def parse_sound(data):
|
||||||
|
sample_addr, tuning = struct.unpack(">If", data)
|
||||||
|
if sample_addr == 0:
|
||||||
|
assert tuning == 0
|
||||||
|
return None
|
||||||
|
return Sound(sample_addr, tuning)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_drum(data, addr):
|
||||||
|
name = gen_name("drum")
|
||||||
|
release_rate, pan, loaded, pad = struct.unpack(">BBBB", data[:4])
|
||||||
|
assert loaded == 0
|
||||||
|
assert pad == 0
|
||||||
|
sound = parse_sound(data[4:12])
|
||||||
|
(env_addr,) = struct.unpack(">I", data[12:])
|
||||||
|
assert env_addr != 0
|
||||||
|
return Drum(name, addr, release_rate, pan, env_addr, sound)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_inst(data, addr):
|
||||||
|
name = gen_name("inst")
|
||||||
|
loaded, normal_range_lo, normal_range_hi, release_rate, env_addr = struct.unpack(
|
||||||
|
">BBBBI", data[:8]
|
||||||
|
)
|
||||||
|
assert env_addr != 0
|
||||||
|
sound_lo = parse_sound(data[8:16])
|
||||||
|
sound_med = parse_sound(data[16:24])
|
||||||
|
sound_hi = parse_sound(data[24:])
|
||||||
|
if sound_lo is None:
|
||||||
|
assert normal_range_lo == 0
|
||||||
|
if sound_hi is None:
|
||||||
|
assert normal_range_hi == 127
|
||||||
|
return Inst(
|
||||||
|
name,
|
||||||
|
addr,
|
||||||
|
release_rate,
|
||||||
|
normal_range_lo,
|
||||||
|
normal_range_hi,
|
||||||
|
env_addr,
|
||||||
|
sound_lo,
|
||||||
|
sound_med,
|
||||||
|
sound_hi,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_loop(addr, bank_data):
|
||||||
|
start, end, count, pad = struct.unpack(">IIiI", bank_data[addr : addr + 16])
|
||||||
|
assert pad == 0
|
||||||
|
if count != 0:
|
||||||
|
state = struct.unpack(">16h", bank_data[addr + 16 : addr + 48])
|
||||||
|
else:
|
||||||
|
state = None
|
||||||
|
return Loop(start, end, count, state)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_book(addr, bank_data):
|
||||||
|
order, npredictors = struct.unpack(">ii", bank_data[addr : addr + 8])
|
||||||
|
|
||||||
|
assert order == 2
|
||||||
|
# assert npredictors == 2
|
||||||
|
# if (npredictors != 2):
|
||||||
|
# print(addr, order, npredictors)
|
||||||
|
table_data = bank_data[addr + 8 : addr + 8 + 16 * order * npredictors]
|
||||||
|
table = []
|
||||||
|
for i in range(0, 16 * order * npredictors, 2):
|
||||||
|
table.append(struct.unpack(">h", table_data[i : i + 2])[0])
|
||||||
|
return Book(order, npredictors, table)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_sample(data, bank_data, sample_bank, is_shindou):
|
||||||
|
if is_shindou:
|
||||||
|
sample_size, addr, loop, book = struct.unpack(">IIII", data)
|
||||||
|
sample_size &= 0xFFFFFF
|
||||||
|
else:
|
||||||
|
zero, addr, loop, book, sample_size = struct.unpack(">IIIII", data)
|
||||||
|
assert zero == 0
|
||||||
|
assert loop != 0
|
||||||
|
print(sample_size, addr, loop, book)
|
||||||
|
assert book != 0
|
||||||
|
loop = parse_loop(loop, bank_data)
|
||||||
|
book = parse_book(book, bank_data)
|
||||||
|
|
||||||
|
return sample_bank.add_sample(addr, sample_size, book, loop)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_envelope(addr, data_bank):
|
||||||
|
entries = []
|
||||||
|
while True:
|
||||||
|
delay, arg = struct.unpack(">HH", data_bank[addr : addr + 4])
|
||||||
|
entries.append((delay, arg))
|
||||||
|
addr += 4
|
||||||
|
if 1 <= (-delay) % 2 ** 16 <= 3:
|
||||||
|
break
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
def parse_ctl_header(header):
|
||||||
|
num_instruments, num_drums, shared = struct.unpack(">III", header[:12])
|
||||||
|
date = parse_bcd(header[12:])
|
||||||
|
y = date // 10000
|
||||||
|
m = date // 100 % 100
|
||||||
|
d = date % 100
|
||||||
|
iso_date = "{:02}-{:02}-{:02}".format(y, m, d)
|
||||||
|
assert shared in [0, 1]
|
||||||
|
return num_instruments, num_drums, iso_date
|
||||||
|
|
||||||
|
|
||||||
|
def parse_ctl(parsed_header, data, sample_bank, index, is_shindou):
|
||||||
|
name_tbl.clear()
|
||||||
|
name = "{:02X}".format(index)
|
||||||
|
num_instruments, num_drums, iso_date = parsed_header
|
||||||
|
print("{}: {}, {} + {}".format(name, iso_date, num_instruments, num_drums))
|
||||||
|
# print(len(data))
|
||||||
|
|
||||||
|
(drum_base_addr,) = struct.unpack(">I", data[:4])
|
||||||
|
drum_addrs = []
|
||||||
|
if num_drums != 0:
|
||||||
|
assert drum_base_addr != 0
|
||||||
|
for i in range(num_drums):
|
||||||
|
(drum_addr,) = struct.unpack(
|
||||||
|
">I", data[drum_base_addr + i * 4 : drum_base_addr + i * 4 + 4]
|
||||||
|
)
|
||||||
|
# assert drum_addr != 0
|
||||||
|
# print(i, drum_addr)
|
||||||
|
if(drum_addr == 0):
|
||||||
|
continue
|
||||||
|
drum_addrs.append(drum_addr)
|
||||||
|
else:
|
||||||
|
assert drum_base_addr == 0
|
||||||
|
|
||||||
|
inst_base_addr = 4
|
||||||
|
inst_addrs = []
|
||||||
|
inst_list = []
|
||||||
|
for i in range(num_instruments):
|
||||||
|
(inst_addr,) = struct.unpack(
|
||||||
|
">I", data[inst_base_addr + i * 4 : inst_base_addr + i * 4 + 4]
|
||||||
|
)
|
||||||
|
if inst_addr == 0:
|
||||||
|
inst_list.append(None)
|
||||||
|
else:
|
||||||
|
inst_list.append(inst_addr)
|
||||||
|
inst_addrs.append(inst_addr)
|
||||||
|
|
||||||
|
inst_addrs.sort()
|
||||||
|
assert drum_addrs == sorted(drum_addrs)
|
||||||
|
if drum_addrs and inst_addrs:
|
||||||
|
assert max(inst_addrs) < min(drum_addrs)
|
||||||
|
|
||||||
|
# print(inst_addrs)
|
||||||
|
|
||||||
|
if len(set(inst_addrs)) != len(inst_addrs):
|
||||||
|
print(index)
|
||||||
|
# assert len(set(inst_addrs)) == len(inst_addrs)
|
||||||
|
# assert len(set(drum_addrs)) == len(drum_addrs)
|
||||||
|
|
||||||
|
insts = []
|
||||||
|
for inst_addr in inst_addrs:
|
||||||
|
insts.append(parse_inst(data[inst_addr : inst_addr + 32], inst_addr))
|
||||||
|
|
||||||
|
drums = []
|
||||||
|
for drum_addr in drum_addrs:
|
||||||
|
drums.append(parse_drum(data[drum_addr : drum_addr + 16], drum_addr))
|
||||||
|
|
||||||
|
env_addrs = set()
|
||||||
|
sample_addrs = set()
|
||||||
|
tunings = defaultdict(lambda: [])
|
||||||
|
for inst in insts:
|
||||||
|
for sound in [inst.sound_lo, inst.sound_med, inst.sound_hi]:
|
||||||
|
if sound is not None:
|
||||||
|
sample_addrs.add(sound.sample_addr)
|
||||||
|
tunings[sound.sample_addr].append(sound.tuning)
|
||||||
|
env_addrs.add(inst.envelope)
|
||||||
|
for drum in drums:
|
||||||
|
sample_addrs.add(drum.sound.sample_addr)
|
||||||
|
tunings[drum.sound.sample_addr].append(drum.sound.tuning)
|
||||||
|
env_addrs.add(drum.envelope)
|
||||||
|
|
||||||
|
# Put drums somewhere in the middle of the instruments to make sample
|
||||||
|
# addresses come in increasing order. (This logic isn't totally right,
|
||||||
|
# but it works for our purposes.)
|
||||||
|
all_insts = []
|
||||||
|
need_drums = len(drums) > 0
|
||||||
|
for inst in insts:
|
||||||
|
if need_drums and any(
|
||||||
|
s.sample_addr > drums[0].sound.sample_addr
|
||||||
|
for s in [inst.sound_lo, inst.sound_med, inst.sound_hi]
|
||||||
|
if s is not None
|
||||||
|
):
|
||||||
|
all_insts.append(drums)
|
||||||
|
need_drums = False
|
||||||
|
all_insts.append(inst)
|
||||||
|
|
||||||
|
if need_drums:
|
||||||
|
all_insts.append(drums)
|
||||||
|
|
||||||
|
samples = {}
|
||||||
|
|
||||||
|
for addr in sorted(sample_addrs):
|
||||||
|
sample_size = 16 if is_shindou else 20
|
||||||
|
sample_data = data[addr : addr + sample_size]
|
||||||
|
print("\t\t", addr)
|
||||||
|
samples[addr] = parse_sample(sample_data, data, sample_bank, is_shindou)
|
||||||
|
samples[addr].tunings.extend(tunings[addr])
|
||||||
|
|
||||||
|
env_data = {}
|
||||||
|
used_env_addrs = set()
|
||||||
|
for addr in sorted(env_addrs):
|
||||||
|
env = parse_envelope(addr, data)
|
||||||
|
env_data[addr] = env
|
||||||
|
for i in range(align(len(env), 4)):
|
||||||
|
used_env_addrs.add(addr + i * 4)
|
||||||
|
|
||||||
|
# Unused envelopes
|
||||||
|
unused_envs = set()
|
||||||
|
if used_env_addrs:
|
||||||
|
for addr in range(min(used_env_addrs) + 4, max(used_env_addrs), 4):
|
||||||
|
if addr not in used_env_addrs:
|
||||||
|
unused_envs.add(addr)
|
||||||
|
(stub_marker,) = struct.unpack(">I", data[addr : addr + 4])
|
||||||
|
assert stub_marker == 0
|
||||||
|
env = parse_envelope(addr, data)
|
||||||
|
env_data[addr] = env
|
||||||
|
for i in range(align(len(env), 4)):
|
||||||
|
used_env_addrs.add(addr + i * 4)
|
||||||
|
|
||||||
|
envelopes = {}
|
||||||
|
for addr in sorted(env_data.keys()):
|
||||||
|
env_name = gen_name("envelope")
|
||||||
|
if addr in unused_envs:
|
||||||
|
env_name += "_unused"
|
||||||
|
envelopes[addr] = Envelope(env_name, env_data[addr])
|
||||||
|
|
||||||
|
return Bank(
|
||||||
|
name,
|
||||||
|
iso_date,
|
||||||
|
sample_bank,
|
||||||
|
insts,
|
||||||
|
drums,
|
||||||
|
all_insts,
|
||||||
|
inst_list,
|
||||||
|
envelopes,
|
||||||
|
samples,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_seqfile(data, filetype):
|
||||||
|
magic, num_entries = struct.unpack(">HH", data[:4])
|
||||||
|
assert magic == filetype
|
||||||
|
prev = align(4 + num_entries * 8, 16)
|
||||||
|
entries = []
|
||||||
|
for i in range(num_entries):
|
||||||
|
offset, length = struct.unpack(">II", data[4 + i * 8 : 4 + i * 8 + 8])
|
||||||
|
if filetype == TYPE_CTL:
|
||||||
|
assert offset == prev
|
||||||
|
else:
|
||||||
|
assert offset <= prev
|
||||||
|
prev = max(prev, offset + length)
|
||||||
|
entries.append((offset, length))
|
||||||
|
assert all(x == 0 for x in data[prev:])
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
def parse_sh_header(data, filetype):
|
||||||
|
(num_entries,) = struct.unpack(">H", data[:2])
|
||||||
|
assert data[2:16] == b"\0" * 14
|
||||||
|
prev = 0
|
||||||
|
entries = []
|
||||||
|
for i in range(num_entries):
|
||||||
|
subdata = data[16 + 16 * i : 32 + 16 * i]
|
||||||
|
offset, length, magic = struct.unpack(">IIH", subdata[:10])
|
||||||
|
assert offset == prev
|
||||||
|
# assert magic == (0x0204 if filetype == TYPE_TBL else 0x0203)
|
||||||
|
prev = offset + length
|
||||||
|
if filetype == TYPE_CTL:
|
||||||
|
assert subdata[14:16] == b"\0" * 2
|
||||||
|
sample_bank_index, magic2, num_instruments, num_drums = struct.unpack(
|
||||||
|
">BBBB", subdata[10:14]
|
||||||
|
)
|
||||||
|
assert magic2 == 0xFF
|
||||||
|
# num_drums >>= 4
|
||||||
|
entries.append(
|
||||||
|
(offset, length, (sample_bank_index, num_instruments, num_drums))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
assert subdata[10:16] == b"\0" * 6
|
||||||
|
entries.append((offset, length))
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
def parse_tbl(data, entries):
|
||||||
|
seen = {}
|
||||||
|
tbls = []
|
||||||
|
sample_banks = []
|
||||||
|
sample_bank_map = {}
|
||||||
|
for (offset, length) in entries:
|
||||||
|
if offset not in seen:
|
||||||
|
name = gen_name("sample_bank")
|
||||||
|
seen[offset] = name
|
||||||
|
sample_bank = SampleBank(name, data[offset : offset + length], offset)
|
||||||
|
sample_banks.append(sample_bank)
|
||||||
|
sample_bank_map[name] = sample_bank
|
||||||
|
tbls.append(seen[offset])
|
||||||
|
return tbls, sample_banks, sample_bank_map
|
||||||
|
|
||||||
|
|
||||||
|
class AifcWriter:
|
||||||
|
def __init__(self, out):
|
||||||
|
self.out = out
|
||||||
|
self.sections = []
|
||||||
|
self.total_size = 0
|
||||||
|
|
||||||
|
def add_section(self, tp, data):
|
||||||
|
assert isinstance(tp, bytes)
|
||||||
|
assert isinstance(data, bytes)
|
||||||
|
self.sections.append((tp, data))
|
||||||
|
self.total_size += align(len(data), 2) + 8
|
||||||
|
|
||||||
|
def add_custom_section(self, tp, data):
|
||||||
|
self.add_section(b"APPL", b"stoc" + self.pstring(tp) + data)
|
||||||
|
|
||||||
|
def pstring(self, data):
|
||||||
|
return bytes([len(data)]) + data + (b"" if len(data) % 2 else b"\0")
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
# total_size isn't used, and is regularly wrong. In particular, vadpcm_enc
|
||||||
|
# preserves the size of the input file...
|
||||||
|
self.total_size += 4
|
||||||
|
self.out.write(b"FORM" + struct.pack(">I", self.total_size) + b"AIFC")
|
||||||
|
for (tp, data) in self.sections:
|
||||||
|
self.out.write(tp + struct.pack(">I", len(data)))
|
||||||
|
self.out.write(data)
|
||||||
|
if len(data) % 2:
|
||||||
|
self.out.write(b"\0")
|
||||||
|
|
||||||
|
|
||||||
|
def write_aifc(entry, out):
|
||||||
|
writer = AifcWriter(out)
|
||||||
|
num_channels = 1
|
||||||
|
data = entry.data
|
||||||
|
assert len(data) % 9 == 0
|
||||||
|
if len(data) % 2 == 1:
|
||||||
|
data += b"\0"
|
||||||
|
# (Computing num_frames this way makes it off by one when the data length
|
||||||
|
# is odd. It matches vadpcm_enc, though.)
|
||||||
|
num_frames = len(data) * 16 // 9
|
||||||
|
sample_size = 16 # bits per sample
|
||||||
|
|
||||||
|
if len(set(entry.tunings)) == 1:
|
||||||
|
sample_rate = 32000 * entry.tunings[0]
|
||||||
|
else:
|
||||||
|
# Some drum sounds in sample bank B don't have unique sample rates, so
|
||||||
|
# we have to guess. This doesn't matter for matching, it's just to make
|
||||||
|
# the sounds easy to listen to.
|
||||||
|
if min(entry.tunings) <= 0.5 <= max(entry.tunings):
|
||||||
|
sample_rate = 16000
|
||||||
|
elif min(entry.tunings) <= 1.0 <= max(entry.tunings):
|
||||||
|
sample_rate = 32000
|
||||||
|
elif min(entry.tunings) <= 1.5 <= max(entry.tunings):
|
||||||
|
sample_rate = 48000
|
||||||
|
elif min(entry.tunings) <= 2.5 <= max(entry.tunings):
|
||||||
|
sample_rate = 80000
|
||||||
|
else:
|
||||||
|
sample_rate = 16000 * (min(entry.tunings) + max(entry.tunings))
|
||||||
|
|
||||||
|
writer.add_section(
|
||||||
|
b"COMM",
|
||||||
|
struct.pack(">hIh", num_channels, num_frames, sample_size)
|
||||||
|
+ serialize_f80(sample_rate)
|
||||||
|
+ b"VAPC"
|
||||||
|
+ writer.pstring(b"VADPCM ~4-1"),
|
||||||
|
)
|
||||||
|
writer.add_section(b"INST", b"\0" * 20)
|
||||||
|
table_data = b"".join(struct.pack(">h", x) for x in entry.book.table)
|
||||||
|
writer.add_custom_section(
|
||||||
|
b"VADPCMCODES",
|
||||||
|
struct.pack(">hhh", 1, entry.book.order, entry.book.npredictors) + table_data,
|
||||||
|
)
|
||||||
|
writer.add_section(b"SSND", struct.pack(">II", 0, 0) + data)
|
||||||
|
if entry.loop.count != 0:
|
||||||
|
writer.add_custom_section(
|
||||||
|
b"VADPCMLOOPS",
|
||||||
|
struct.pack(
|
||||||
|
">HHIIi16h",
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
entry.loop.start,
|
||||||
|
entry.loop.end,
|
||||||
|
entry.loop.count,
|
||||||
|
*entry.loop.state
|
||||||
|
),
|
||||||
|
)
|
||||||
|
writer.finish()
|
||||||
|
|
||||||
|
|
||||||
|
def write_aiff(entry, filename):
|
||||||
|
temp = tempfile.NamedTemporaryFile(suffix=".aifc", delete=False)
|
||||||
|
try:
|
||||||
|
write_aifc(entry, temp)
|
||||||
|
temp.flush()
|
||||||
|
temp.close()
|
||||||
|
aifc_decode = os.path.join(os.path.dirname(__file__), "aifc_decode")
|
||||||
|
subprocess.run([aifc_decode, temp.name, filename], check=True)
|
||||||
|
finally:
|
||||||
|
temp.close()
|
||||||
|
os.remove(temp.name)
|
||||||
|
|
||||||
|
|
||||||
|
# Modified from https://stackoverflow.com/a/25935321/1359139, cc by-sa 3.0
|
||||||
|
class NoIndent(object):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class NoIndentEncoder(json.JSONEncoder):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(NoIndentEncoder, self).__init__(*args, **kwargs)
|
||||||
|
self._replacement_map = {}
|
||||||
|
|
||||||
|
def default(self, o):
|
||||||
|
def ignore_noindent(o):
|
||||||
|
if isinstance(o, NoIndent):
|
||||||
|
return o.value
|
||||||
|
return self.default(o)
|
||||||
|
|
||||||
|
if isinstance(o, NoIndent):
|
||||||
|
key = uuid.uuid4().hex
|
||||||
|
self._replacement_map[key] = json.dumps(o.value, default=ignore_noindent)
|
||||||
|
return "@@%s@@" % (key,)
|
||||||
|
else:
|
||||||
|
return super(NoIndentEncoder, self).default(o)
|
||||||
|
|
||||||
|
def encode(self, o):
|
||||||
|
result = super(NoIndentEncoder, self).encode(o)
|
||||||
|
repl_map = self._replacement_map
|
||||||
|
|
||||||
|
def repl(m):
|
||||||
|
key = m.group()[3:-3]
|
||||||
|
return repl_map[key]
|
||||||
|
|
||||||
|
return re.sub(r"\"@@[0-9a-f]*?@@\"", repl, result)
|
||||||
|
|
||||||
|
|
||||||
|
def inst_ifdef_json(bank_index, inst_index):
|
||||||
|
if bank_index == 7 and inst_index >= 13:
|
||||||
|
return NoIndent(["VERSION_US", "VERSION_EU"])
|
||||||
|
if bank_index == 8 and inst_index >= 16:
|
||||||
|
return NoIndent(["VERSION_US", "VERSION_EU"])
|
||||||
|
if bank_index == 10 and inst_index >= 14:
|
||||||
|
return NoIndent(["VERSION_US", "VERSION_EU"])
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = []
|
||||||
|
need_help = False
|
||||||
|
only_samples = False
|
||||||
|
only_samples_list = []
|
||||||
|
shindou_headers = None
|
||||||
|
if sys.argv[1].startswith("files"):
|
||||||
|
with open(sys.argv[2], "rb") as ctl_file, open(sys.argv[3], "rb") as tbl_file, \
|
||||||
|
open(sys.argv[4], "rb") as header_file:
|
||||||
|
|
||||||
|
ctl_data = ctl_file.read()
|
||||||
|
tbl_data = tbl_file.read()
|
||||||
|
if sys.argv[1].endswith("jp"):
|
||||||
|
header_start = 0xC1360 - 0x1050
|
||||||
|
elif sys.argv[1].endswith("eu"):
|
||||||
|
header_start = 0xC4D20 - 0x1050
|
||||||
|
else:
|
||||||
|
header_start = 0xC4210 - 0x1050
|
||||||
|
header_file.seek(header_start)
|
||||||
|
hlen = int.from_bytes(header_file.read(2), "big")
|
||||||
|
header_file.seek(-2, 1)
|
||||||
|
tbl_header_data = header_file.read((1 + hlen) * 0x10)
|
||||||
|
hlen = int.from_bytes(header_file.read(2), "big")
|
||||||
|
header_file.seek(hlen * 0x10 + 0xE, 1)
|
||||||
|
hlen = int.from_bytes(header_file.read(2), "big")
|
||||||
|
header_file.seek(-2, 1)
|
||||||
|
ctl_header_data = header_file.read((1 + hlen) * 0x10)
|
||||||
|
|
||||||
|
shindou_headers = True
|
||||||
|
samples_out_dir = sys.argv[5]
|
||||||
|
banks_out_dir = sys.argv[6]
|
||||||
|
else:
|
||||||
|
skip_next = 0
|
||||||
|
for i, a in enumerate(sys.argv[1:], 1):
|
||||||
|
if skip_next > 0:
|
||||||
|
skip_next -= 1
|
||||||
|
continue
|
||||||
|
if a == "--help" or a == "-h":
|
||||||
|
need_help = True
|
||||||
|
elif a == "--only-samples":
|
||||||
|
only_samples = True
|
||||||
|
elif a == "--shindou-headers":
|
||||||
|
shindou_headers = sys.argv[i + 1 : i + 5]
|
||||||
|
skip_next = 4
|
||||||
|
elif a.startswith("-"):
|
||||||
|
print("Unrecognized option " + a)
|
||||||
|
sys.exit(1)
|
||||||
|
elif only_samples:
|
||||||
|
only_samples_list.append(a)
|
||||||
|
else:
|
||||||
|
args.append(a)
|
||||||
|
|
||||||
|
expected_num_args = 5 + (0 if only_samples else 2)
|
||||||
|
if (
|
||||||
|
need_help
|
||||||
|
or len(args) != expected_num_args
|
||||||
|
or (shindou_headers and len(shindou_headers) != 4)
|
||||||
|
):
|
||||||
|
print(
|
||||||
|
"Usage: {}"
|
||||||
|
" <.z64 rom> <ctl offset> <ctl size> <tbl offset> <tbl size>"
|
||||||
|
" [--shindou-headers <ctl header offset> <ctl header size>"
|
||||||
|
" <tbl header offset> <tbl header size>]"
|
||||||
|
" (<samples outdir> <sound bank outdir> |"
|
||||||
|
" --only-samples file:index ...)".format(sys.argv[0])
|
||||||
|
)
|
||||||
|
sys.exit(0 if need_help else 1)
|
||||||
|
|
||||||
|
rom_file = open(args[0], "rb")
|
||||||
|
|
||||||
|
def read_at(offset, size):
|
||||||
|
rom_file.seek(int(offset))
|
||||||
|
return rom_file.read(int(size))
|
||||||
|
|
||||||
|
ctl_data = read_at(args[1], args[2])
|
||||||
|
tbl_data = read_at(args[3], args[4])
|
||||||
|
|
||||||
|
ctl_header_data = None
|
||||||
|
tbl_header_data = None
|
||||||
|
if shindou_headers:
|
||||||
|
ctl_header_data = read_at(shindou_headers[0], shindou_headers[1])
|
||||||
|
tbl_header_data = read_at(shindou_headers[2], shindou_headers[3])
|
||||||
|
|
||||||
|
if not only_samples:
|
||||||
|
samples_out_dir = args[5]
|
||||||
|
banks_out_dir = args[6]
|
||||||
|
|
||||||
|
banks = []
|
||||||
|
|
||||||
|
if shindou_headers:
|
||||||
|
ctl_entries = parse_sh_header(ctl_header_data, TYPE_CTL)
|
||||||
|
tbl_entries = parse_sh_header(tbl_header_data, TYPE_TBL)
|
||||||
|
|
||||||
|
sample_banks = parse_tbl(tbl_data, tbl_entries)[1]
|
||||||
|
print(len(ctl_entries))
|
||||||
|
for index, (offset, length, sh_meta) in enumerate(ctl_entries):
|
||||||
|
sample_bank = sample_banks[sh_meta[0]]
|
||||||
|
entry = ctl_data[offset : offset + length]
|
||||||
|
header = (sh_meta[1], sh_meta[2], "0000-00-00")
|
||||||
|
banks.append(parse_ctl(header, entry, sample_bank, index, True))
|
||||||
|
else:
|
||||||
|
ctl_entries = parse_seqfile(ctl_data, TYPE_CTL)
|
||||||
|
tbl_entries = parse_seqfile(tbl_data, TYPE_TBL)
|
||||||
|
assert len(ctl_entries) == len(tbl_entries)
|
||||||
|
|
||||||
|
tbls, sample_banks, sample_bank_map = parse_tbl(tbl_data, tbl_entries)
|
||||||
|
|
||||||
|
for index, (offset, length), sample_bank_name in zip(
|
||||||
|
range(len(ctl_entries)), ctl_entries, tbls
|
||||||
|
):
|
||||||
|
sample_bank = sample_bank_map[sample_bank_name]
|
||||||
|
entry = ctl_data[offset : offset + length]
|
||||||
|
header = parse_ctl_header(entry[:16])
|
||||||
|
banks.append(parse_ctl(header, entry[16:], sample_bank, index, False))
|
||||||
|
|
||||||
|
# Special mode used for asset extraction: generate aifc files, with paths
|
||||||
|
# given by command line arguments
|
||||||
|
if only_samples:
|
||||||
|
index_to_filename = {}
|
||||||
|
created_dirs = set()
|
||||||
|
for arg in only_samples_list:
|
||||||
|
filename, index = arg.rsplit(":", 1)
|
||||||
|
index_to_filename[int(index)] = filename
|
||||||
|
index = -1
|
||||||
|
for sample_bank in sample_banks:
|
||||||
|
offsets = sorted(set(sample_bank.entries.keys()))
|
||||||
|
for offset in offsets:
|
||||||
|
entry = sample_bank.entries[offset]
|
||||||
|
index += 1
|
||||||
|
if index in index_to_filename:
|
||||||
|
filename = index_to_filename[index]
|
||||||
|
dir = os.path.dirname(filename)
|
||||||
|
if dir not in created_dirs:
|
||||||
|
os.makedirs(dir, exist_ok=True)
|
||||||
|
created_dirs.add(dir)
|
||||||
|
write_aiff(entry, filename)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Generate aiff files
|
||||||
|
|
||||||
|
for sample_bank in sample_banks:
|
||||||
|
dir = os.path.join(samples_out_dir, sample_bank.name)
|
||||||
|
os.makedirs(dir, exist_ok=True)
|
||||||
|
|
||||||
|
offsets = sorted(set(sample_bank.entries.keys()))
|
||||||
|
print(sample_bank.name, len(offsets), 'entries')
|
||||||
|
offsets.append(len(sample_bank.data))
|
||||||
|
|
||||||
|
assert 0 in offsets
|
||||||
|
|
||||||
|
for offset, next_offset, index in zip(
|
||||||
|
offsets, offsets[1:], range(len(offsets))
|
||||||
|
):
|
||||||
|
entry = sample_bank.entries[offset]
|
||||||
|
entry.name = "{:02X}".format(index)
|
||||||
|
size = next_offset - offset
|
||||||
|
|
||||||
|
assert size % 16 == 0
|
||||||
|
if not (size - 15 <= len(entry.data) <= size):
|
||||||
|
print(index, offset, size, len(entry.data))
|
||||||
|
# continue
|
||||||
|
# assert size - 15 <= len(entry.data) <= size
|
||||||
|
# if index % 10 == 0:
|
||||||
|
# print(index, offset, size, len(entry.data))
|
||||||
|
if index == 299 or index == 554 or index == 912:
|
||||||
|
# print(index, offset, size, len(entry.data))
|
||||||
|
continue
|
||||||
|
# garbage = sample_bank.data[offset + len(entry.data) : offset + size]
|
||||||
|
# if len(entry.data) % 2 == 1:
|
||||||
|
# assert garbage[0] == 0
|
||||||
|
# if next_offset != offsets[-1]:
|
||||||
|
# # (The last chunk follows a more complex garbage pattern)
|
||||||
|
# assert all(x == 0 for x in garbage)
|
||||||
|
filename = os.path.join(dir, entry.name + ".aiff")
|
||||||
|
write_aiff(entry, filename)
|
||||||
|
|
||||||
|
# Generate sound bank .json files
|
||||||
|
os.makedirs(banks_out_dir, exist_ok=True)
|
||||||
|
for bank_index, bank in enumerate(banks):
|
||||||
|
filename = os.path.join(banks_out_dir, bank.name + ".json")
|
||||||
|
with open(filename, "w") as out:
|
||||||
|
|
||||||
|
def sound_to_json(sound):
|
||||||
|
entry = bank.samples[sound.sample_addr]
|
||||||
|
if len(set(entry.tunings)) == 1:
|
||||||
|
return entry.name
|
||||||
|
return {"sample": entry.name, "tuning": round_f32(sound.tuning)}
|
||||||
|
|
||||||
|
bank_json = {
|
||||||
|
"date": bank.iso_date,
|
||||||
|
"sample_bank": bank.sample_bank.name,
|
||||||
|
"envelopes": {},
|
||||||
|
"instruments": {},
|
||||||
|
"instrument_list": [],
|
||||||
|
}
|
||||||
|
addr_to_name = {}
|
||||||
|
|
||||||
|
# Envelopes
|
||||||
|
for env in bank.envelopes.values():
|
||||||
|
env_json = []
|
||||||
|
for (delay, arg) in env.entries:
|
||||||
|
if delay == 0:
|
||||||
|
ins = "stop"
|
||||||
|
assert arg == 0
|
||||||
|
elif delay == 2 ** 16 - 1:
|
||||||
|
ins = "hang"
|
||||||
|
assert arg == 0
|
||||||
|
elif delay == 2 ** 16 - 2:
|
||||||
|
ins = ["goto", arg]
|
||||||
|
elif delay == 2 ** 16 - 3:
|
||||||
|
ins = "restart"
|
||||||
|
assert arg == 0
|
||||||
|
else:
|
||||||
|
ins = [delay, arg]
|
||||||
|
env_json.append(NoIndent(ins))
|
||||||
|
bank_json["envelopes"][env.name] = env_json
|
||||||
|
|
||||||
|
# Instruments/drums
|
||||||
|
for inst_index, inst in enumerate(bank.all_insts):
|
||||||
|
if isinstance(inst, Inst):
|
||||||
|
inst_json = {
|
||||||
|
"ifdef": inst_ifdef_json(bank_index, inst_index),
|
||||||
|
"release_rate": inst.release_rate,
|
||||||
|
"normal_range_lo": inst.normal_range_lo,
|
||||||
|
"normal_range_hi": inst.normal_range_hi,
|
||||||
|
"envelope": bank.envelopes[inst.envelope].name,
|
||||||
|
}
|
||||||
|
|
||||||
|
if inst_json["ifdef"] is None:
|
||||||
|
del inst_json["ifdef"]
|
||||||
|
|
||||||
|
if inst.sound_lo is not None:
|
||||||
|
inst_json["sound_lo"] = NoIndent(sound_to_json(inst.sound_lo))
|
||||||
|
else:
|
||||||
|
del inst_json["normal_range_lo"]
|
||||||
|
|
||||||
|
inst_json["sound"] = NoIndent(sound_to_json(inst.sound_med))
|
||||||
|
|
||||||
|
if inst.sound_hi is not None:
|
||||||
|
inst_json["sound_hi"] = NoIndent(sound_to_json(inst.sound_hi))
|
||||||
|
else:
|
||||||
|
del inst_json["normal_range_hi"]
|
||||||
|
|
||||||
|
bank_json["instruments"][inst.name] = inst_json
|
||||||
|
addr_to_name[inst.addr] = inst.name
|
||||||
|
|
||||||
|
else:
|
||||||
|
assert isinstance(inst, list)
|
||||||
|
drums_list_json = []
|
||||||
|
for drum in inst:
|
||||||
|
drum_json = {
|
||||||
|
"release_rate": drum.release_rate,
|
||||||
|
"pan": drum.pan,
|
||||||
|
"envelope": bank.envelopes[drum.envelope].name,
|
||||||
|
"sound": sound_to_json(drum.sound),
|
||||||
|
}
|
||||||
|
drums_list_json.append(NoIndent(drum_json))
|
||||||
|
bank_json["instruments"]["percussion"] = drums_list_json
|
||||||
|
|
||||||
|
# Instrument lists
|
||||||
|
for addr in bank.inst_list:
|
||||||
|
if addr is None:
|
||||||
|
bank_json["instrument_list"].append(None)
|
||||||
|
else:
|
||||||
|
bank_json["instrument_list"].append(addr_to_name[addr])
|
||||||
|
|
||||||
|
out.write(json.dumps(bank_json, indent=4, cls=NoIndentEncoder))
|
||||||
|
out.write("\n")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user