diff --git a/src/fixed/common.h b/src/fixed/common.h index 594e5ee5..90a3842e 100644 --- a/src/fixed/common.h +++ b/src/fixed/common.h @@ -19,7 +19,6 @@ #define MODE4 #define USE_DIV_TABLE #define ROM_READ - //#define USE_9BIT_SOUND #include #elif defined(__TNS__) @@ -41,8 +40,13 @@ #define USE_DIV_TABLE // TODO_3DO remove #define CPU_BIG_ENDIAN - #define MAX_RAM (800 * 1024) - #define MAX_VRAM (640 * 1024) + #define MAX_RAM_LVL (800 * 1024) + #define MAX_RAM_TEX (640 * 1024) + #define MAX_RAM_CEL (MAX_FACES * sizeof(CCB)) + + extern void* RAM_LVL; + extern void* RAM_TEX; + extern void* RAM_CEL; #include #include @@ -126,6 +130,8 @@ #define NAV_STEPS 1 // the maximum of active enemies #define MAX_ENEMIES 3 +// set the maximum number of simultaneously played channels + #define SND_CHANNELS 4 #endif #ifndef NAV_STEPS @@ -222,7 +228,7 @@ X_INLINE int32 abs(int32 x) { extern int32 osGetSystemTimeMS(); extern void osJoyVibrate(int32 index, int32 L, int32 R); extern void osSetPalette(const uint16* palette); -extern void osLoadLevel(const char* name); +extern void* osLoadLevel(const char* name); #ifdef PROFILING #define PROFILE_FRAME\ @@ -343,7 +349,11 @@ extern int32 fps; #define FIXED_SHIFT 14 #define SND_MAX_DIST (8 * 1024) -#define SND_CHANNELS 6 + +#ifndef SND_CHANNELS + #define SND_CHANNELS 6 +#endif + #define SND_FIXED_SHIFT 8 #define SND_VOL_SHIFT 6 #define SND_PITCH_SHIFT 7 @@ -362,14 +372,8 @@ extern int32 fps; #define SND_SAMPLE_FREQ 22050 #define SND_ENCODE(x) (x) #define SND_DECODE(x) ((x) - 128) - - #ifdef USE_9BIT_SOUND - #define SND_MIN -255 - #define SND_MAX 254 - #else - #define SND_MIN -128 - #define SND_MAX 127 - #endif + #define SND_MIN -128 + #define SND_MAX 127 #elif defined(__DOS__) #define SND_SAMPLES 1024 #define SND_OUTPUT_FREQ 11025 @@ -580,10 +584,12 @@ struct Matrix }; struct Quad { +#ifdef __3DO__ + Index indices[4]; + uint32 flags; +#else Index indices[4]; uint16 flags; -#ifdef __3DO__ - uint16 _unused; #endif }; @@ -1689,6 +1695,12 @@ enum EffectType FX_TR1_FLICKER = 16 }; +enum SoundMode { + UNIQUE, + REPLAY, + LOOP +}; + enum SoundID { SND_NO = 2, @@ -1866,6 +1878,8 @@ struct Level uint16 itemsCount; uint16 camerasCount; uint16 cameraFramesCount; + uint16 soundOffsetsCount; + uint16 _reserved; const uint16* palette; const uint8* lightmap; @@ -1991,10 +2005,6 @@ extern ItemObj items[MAX_ITEMS]; extern bool enableClipping; extern bool enableMaxSort; -#ifdef __3DO__ -extern uint8* VRAM_TEX; -#endif - template X_INLINE void swap(T &a, T &b) { T tmp = a; @@ -2162,10 +2172,17 @@ bool useSwitch(ItemObj* item, int32 timer); bool useKey(ItemObj* item, ItemObj* lara); bool usePickup(ItemObj* item); -void musicPlay(int32 track); -void musicStop(); int32 doTutorial(ItemObj* lara, int32 track); +void sndInit(); +void sndInitSamples(); +void sndFill(uint8* buffer, int32 count); +void* sndPlaySample(int32 index, int32 volume, int32 pitch, int32 mode); +void sndPlayTrack(int32 track); +void sndStopTrack(); +void sndStopSample(int32 index); +void sndStop(); + X_INLINE void dmaFill(void *dst, uint8 value, uint32 count) { ASSERT((count & 3) == 0); diff --git a/src/fixed/draw.h b/src/fixed/draw.h index 826204be..944fb44d 100644 --- a/src/fixed/draw.h +++ b/src/fixed/draw.h @@ -135,7 +135,7 @@ int32 getTextWidth(const char* text) int32 w = 0; char c; - while (c = *text++) + while ((c = *text++)) { if (c == ' ') { w += 6; diff --git a/src/fixed/game.h b/src/fixed/game.h index e99b625c..3e2ea779 100644 --- a/src/fixed/game.h +++ b/src/fixed/game.h @@ -2,7 +2,6 @@ #define H_GAME #include "common.h" -#include "sound.h" #include "room.h" #include "camera.h" #include "item.h" @@ -31,9 +30,8 @@ struct Game animTexFrame = 0; dynSectorsCount = 0; - osLoadLevel(name); - - loadLevel(levelData); + void* data = osLoadLevel(name); + loadLevel(data); } void loadLevel(const void* data) diff --git a/src/fixed/item.h b/src/fixed/item.h index d079cf3f..55ac6a86 100644 --- a/src/fixed/item.h +++ b/src/fixed/item.h @@ -2,7 +2,6 @@ #define H_ITEM #include "common.h" -#include "sound.h" #include "camera.h" #include "room.h" @@ -28,11 +27,8 @@ int32 alignOffset(int32 a, int32 b) return -(a + 1); } -Mixer::Sample* soundPlay(int16 id, const vec3i &pos) +void* soundPlay(int16 id, const vec3i &pos) { -#ifdef __3DO__ - return NULL; -#endif // TODO gym // 0 -> 200 // 4 -> 204 @@ -76,13 +72,7 @@ Mixer::Sample* soundPlay(int16 id, const vec3i &pos) index += (rand_draw() * b->flags.count) >> 15; } - const uint8 *data = level.soundData + level.soundOffsets[index]; - - int32 size; - memcpy(&size, data + 40, 4); // TODO preprocess and remove wave header - data += 44; - - return mixer.playSample(data, size, volume, pitch, b->flags.mode); + return sndPlaySample(index, volume, pitch, b->flags.mode); } void soundStop(int16 id) @@ -96,46 +86,8 @@ void soundStop(int16 id) for (int32 i = 0; i < b->flags.count; i++) { - int32 index = b->index + i; - - const uint8 *data = level.soundData + level.soundOffsets[index]; - - int32 size; - memcpy(&size, data + 40, 4); // TODO preprocess and remove wave header - data += 44; - - mixer.stopSample(data); - } -} - -void musicPlay(int32 track) -{ -#ifdef __3DO__ - return; -#endif - if (track == 13) { - gCurTrack = 0; + sndStopSample(b->index + i); } - - if (track == gCurTrack) - return; - - gCurTrack = track; - - struct TrackInfo { - int32 offset; - int32 size; - } *info = (TrackInfo*)((uint8*)TRACKS_IMA + track * 8); - - if (!info->size) - return; - - mixer.playMusic((uint8*)TRACKS_IMA + info->offset, info->size); -} - -void musicStop() -{ - mixer.stopMusic(); } int32 ItemObj::getFrames(const AnimFrame* &frameA, const AnimFrame* &frameB, int32 &animFrameRate) const diff --git a/src/fixed/level.h b/src/fixed/level.h index 585bc6d9..0822f190 100644 --- a/src/fixed/level.h +++ b/src/fixed/level.h @@ -67,6 +67,7 @@ void readLevel_GBA(const uint8* data) for (int32 i = 0; i < level.modelsCount; i++) { const Model* model = level.models + i; + ASSERT(model->type < MAX_MODELS); models[model->type] = *model; } level.models = models; @@ -120,9 +121,10 @@ void readLevel_GBA(const uint8* data) for (int32 i = 0; i < level.texturesCount; i++) { Texture* tex = level.textures + i; - tex->data += intptr_t(VRAM_TEX); - tex->plut += intptr_t(VRAM_TEX); + tex->data += intptr_t(RAM_TEX); + tex->plut += intptr_t(RAM_TEX); } + sndInitSamples(); #endif } diff --git a/src/fixed/room.h b/src/fixed/room.h index 92328702..2276044f 100644 --- a/src/fixed/room.h +++ b/src/fixed/room.h @@ -1279,9 +1279,9 @@ void checkTrigger(const FloorData* fd, ItemObj* lara) if (flags.mask == ITEM_FLAGS_MASK_ALL) { flags.once |= FD_ONCE(data); - musicPlay(track); + sndPlayTrack(track); } else { - musicStop(); + sndStopTrack(); } break; } @@ -1295,7 +1295,7 @@ void checkTrigger(const FloorData* fd, ItemObj* lara) if (gSaveGame.secrets & (1 << FD_ARGS(triggerCmd))) break; gSaveGame.secrets |= (1 << FD_ARGS(triggerCmd)); - musicPlay(13); + sndPlayTrack(13); break; } diff --git a/src/fixed/sound.h b/src/fixed/sound.h deleted file mode 100644 index 324a7cc5..00000000 --- a/src/fixed/sound.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef H_SOUND -#define H_SOUND - -#include "common.h" - -void decodeIMA(IMA_STATE &state, const uint8* data, int32* buffer, int32 size); - -struct Mixer -{ - enum SoundMode { - UNIQUE, - REPLAY, - LOOP, - }; - - struct Music - { - const uint8* data; - int32 size; - int32 pos; - IMA_STATE state; - - void fill(int32* buffer, int32 count) - { - int32 len = X_MIN(size - pos, count >> 1); - - decodeIMA(state, data + pos, buffer, len); - - pos += len; - - if (pos >= size) - { - data = NULL; - memset(buffer, 0, (count - (len << 1)) * sizeof(buffer[0])); - } - } - }; - - struct Sample - { - const uint8* data; - int32 size; - int32 pos; - int32 inc; - int32 volume; - - void fill(int32* buffer, int32 count) - { - for (int32 i = 0; i < count; i++) - { - buffer[i] += SND_DECODE(data[pos >> SND_FIXED_SHIFT]) * volume; - - pos += inc; - if (pos >= size) - { - // TODO LOOP - data = NULL; - return; - } - } - } - }; - - Music music; - Sample channels[SND_CHANNELS]; - int32 channelsCount; - - #define CALC_INC (((SND_SAMPLE_FREQ << SND_FIXED_SHIFT) / SND_OUTPUT_FREQ) * pitch >> SND_PITCH_SHIFT) - - Sample* playSample(const uint8* data, int32 size, int32 volume, int32 pitch, int32 mode) - { - if (mode == UNIQUE || mode == REPLAY) - { - for (int32 i = 0; i < channelsCount; i++) - { - Sample* sample = channels + i; - - if (sample->data != data) - continue; - - sample->inc = CALC_INC; - sample->volume = volume; - - if (mode == REPLAY) - { - sample->pos = 0; - } - - return sample; - } - } - - if (channelsCount >= SND_CHANNELS) - return NULL; - - #ifdef USE_9BIT_SOUND - // expand 8 to 9-bit - volume <<= 1; - #endif - - Sample* sample = channels + channelsCount++; - sample->data = data; - sample->size = size << SND_FIXED_SHIFT; - sample->pos = 0; - sample->inc = CALC_INC; - sample->volume = volume; - - return sample; - } - - void stopSample(const uint8* data) - { - int32 i = channelsCount; - - while (--i >= 0) - { - if (channels[i].data == data) - { - channels[i] = channels[--channelsCount]; - } - } - } - - void stopSamples() - { - channelsCount = 0; - } - - void playMusic(const void* data, int32 size) - { - music.data = (uint8*)data; - music.size = size; - music.pos = 0; - //music.volume = (1 << SND_VOL_SHIFT); - music.state.smp = 0; - music.state.idx = 0; - } - - void stopMusic() - { - music.data = NULL; - } - - void init() - { - channelsCount = 0; - music.data = NULL; - } - - void fill(uint8* bufferA, uint8* bufferB, int32 count) - { - #ifdef PROFILE_SOUNDTIME - PROFILE_CLEAR(); - PROFILE(CNT_SOUND); - #endif - - if ((channelsCount == 0) && !music.data) - { - dmaFill(bufferA, SND_ENCODE(0), count); - #ifdef USE_9BIT_SOUND - dmaFill(bufferB, SND_ENCODE(0), count); - #endif - return; - } - - int32 tmp[SND_SAMPLES]; - - if (music.data) { - music.fill(tmp, count); - } else { - dmaFill(tmp, 0, sizeof(tmp)); - } - - int32 ch = channelsCount; - while (ch--) - { - Sample* sample = channels + ch; - - sample->fill(tmp, count); - - if (!sample->data) { - channels[ch] = channels[--channelsCount]; - } - } - - for (int32 i = 0; i < count; i++) - { - #ifdef USE_9BIT_SOUND - int32 samp = tmp[i] >> (SND_VOL_SHIFT - 1); - //samp += (rand_draw() & 1) - 1; - samp = X_CLAMP(samp, SND_MIN, SND_MAX); - - bufferA[i] = SND_ENCODE((samp >> 1)); - bufferB[i] = SND_ENCODE((samp >> 1) + (samp & 1)); - #else - int32 samp = X_CLAMP(tmp[i] >> SND_VOL_SHIFT, SND_MIN, SND_MAX); - - bufferA[i] = SND_ENCODE(samp); - #endif - } - } -}; - -Mixer mixer; - -#endif diff --git a/src/platform/gba/OpenLara.vcxproj b/src/platform/gba/OpenLara.vcxproj index 9fc04ee6..5464acce 100644 --- a/src/platform/gba/OpenLara.vcxproj +++ b/src/platform/gba/OpenLara.vcxproj @@ -22,6 +22,7 @@ + @@ -36,7 +37,6 @@ - diff --git a/src/platform/gba/main.cpp b/src/platform/gba/main.cpp index ebf567a3..229919c4 100644 --- a/src/platform/gba/main.cpp +++ b/src/platform/gba/main.cpp @@ -3,8 +3,8 @@ const void* levelData; #elif defined(__GBA__) #include "TRACKS_IMA.h" - #include "LEVEL2_PKD.h" - const void* levelData = LEVEL2_PKD; + #include "LEVEL1_PKD.h" + const void* levelData = LEVEL1_PKD; #elif defined(__TNS__) const void* levelData; #endif @@ -299,10 +299,7 @@ int32 fpsCounter = 0; void osJoyVibrate(int32 index, int32 L, int32 R) {} #endif -EWRAM_DATA ALIGN16 uint8 soundBufferA[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt -#ifdef USE_9BIT_SOUND -EWRAM_DATA ALIGN16 uint8 soundBufferB[2 * SND_SAMPLES + 32]; // for 9-bit mixer support via Direct Mixer B channel -#endif +EWRAM_DATA ALIGN16 uint8 soundBuffer[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt uint32 curSoundBuffer = 0; @@ -311,8 +308,9 @@ HWAVEOUT waveOut; WAVEFORMATEX waveFmt = { WAVE_FORMAT_PCM, 1, SND_OUTPUT_FREQ, SND_OUTPUT_FREQ, 1, 8, sizeof(waveFmt) }; WAVEHDR waveBuf[2]; -void soundInit() { - mixer.init(); +void soundInit() +{ + sndInit(); if (waveOutOpen(&waveOut, WAVE_MAPPER, &waveFmt, (INT_PTR)hWnd, 0, CALLBACK_WINDOW) != MMSYSERR_NOERROR) { return; @@ -322,16 +320,17 @@ void soundInit() { for (int i = 0; i < 2; i++) { WAVEHDR *waveHdr = waveBuf + i; waveHdr->dwBufferLength = SND_SAMPLES; - waveHdr->lpData = (LPSTR)(soundBufferA + i * SND_SAMPLES); + waveHdr->lpData = (LPSTR)(soundBuffer + i * SND_SAMPLES); waveOutPrepareHeader(waveOut, waveHdr, sizeof(WAVEHDR)); waveOutWrite(waveOut, waveHdr, sizeof(WAVEHDR)); } } -void soundFill() { +void soundFill() +{ WAVEHDR *waveHdr = waveBuf + curSoundBuffer; waveOutUnprepareHeader(waveOut, waveHdr, sizeof(WAVEHDR)); - mixer.fill((uint8*)waveHdr->lpData, NULL, SND_SAMPLES); + sndFill((uint8*)waveHdr->lpData, SND_SAMPLES); waveOutPrepareHeader(waveOut, waveHdr, sizeof(WAVEHDR)); waveOutWrite(waveOut, waveHdr, sizeof(WAVEHDR)); curSoundBuffer ^= 1; @@ -339,43 +338,24 @@ void soundFill() { #elif defined(__GBA__) void soundInit() { - mixer.init(); + sndInit(); REG_SOUNDCNT_X = SSTAT_ENABLE; -#ifdef USE_9BIT_SOUND - REG_SOUNDCNT_H = SDS_ATMR0 | SDS_AL | SDS_AR | SDS_ARESET | SDS_A50 | - SDS_BTMR0 | SDS_BL | SDS_BR | SDS_BRESET | SDS_B50; -#else REG_SOUNDCNT_H = SDS_ATMR0 | SDS_AL | SDS_AR | SDS_ARESET | SDS_A100; -#endif REG_TM0D = 65536 - (16777216 / SND_OUTPUT_FREQ); REG_TM0CNT = TM_ENABLE; REG_DMA1DAD = (u32)®_FIFO_A; -#ifdef USE_9BIT_SOUND - REG_DMA2DAD = (u32)®_FIFO_B; -#endif } void soundFill() { if (curSoundBuffer == 1) { REG_DMA1CNT = 0; - REG_DMA1SAD = (u32)soundBufferA; + REG_DMA1SAD = (u32)soundBuffer; REG_DMA1CNT = DMA_DST_FIXED | DMA_REPEAT | DMA_16 | DMA_AT_FIFO | DMA_ENABLE; - #ifdef USE_9BIT_SOUND - REG_DMA2CNT = 0; - REG_DMA2SAD = (u32)soundBufferB; - REG_DMA2CNT = DMA_DST_FIXED | DMA_REPEAT | DMA_16 | DMA_AT_FIFO | DMA_ENABLE; - #endif - } - - mixer.fill(soundBufferA + curSoundBuffer * SND_SAMPLES, - #ifdef USE_9BIT_SOUND - soundBufferB + curSoundBuffer * SND_SAMPLES, - #else - NULL, - #endif - SND_SAMPLES); + } + + sndFill(soundBuffer + curSoundBuffer * SND_SAMPLES, SND_SAMPLES); curSoundBuffer ^= 1; } #endif @@ -453,7 +433,7 @@ void vblank() { #endif -int32 gLevelID = 2; +int32 gLevelID = 1; static const char* gLevelNames[] = { "GYM", @@ -474,10 +454,9 @@ static const char* gLevelNames[] = { // "LEVEL10C" }; -void osLoadLevel(const char* name) +void* osLoadLevel(const char* name) { - mixer.stopMusic(); - mixer.stopSamples(); + sndStop(); #if defined(_WIN32) || defined(__TNS__) || defined(__DOS__) { @@ -497,7 +476,7 @@ void osLoadLevel(const char* name) FILE *f = fopen(buf, "rb"); if (!f) - return; + return NULL; { fseek(f, 0, SEEK_END); @@ -516,7 +495,7 @@ void osLoadLevel(const char* name) { FILE *f = fopen("data/TRACKS.IMA", "rb"); if (!f) - return; + return NULL; fseek(f, 0, SEEK_END); int32 size = ftell(f); @@ -530,6 +509,7 @@ void osLoadLevel(const char* name) #endif } #endif + return (void*)levelData; } int main(void) { @@ -605,7 +585,7 @@ int main(void) { fastAccessReg = 0x0E000020; // fast EWRAM - vu32* fastAccessMem = (vu32*)soundBufferA; // check EWRAM access + vu32* fastAccessMem = (vu32*)soundBuffer; // check EWRAM access // write for (int32 i = 0; i < 16; i++) { diff --git a/src/platform/gba/packer/main.cpp b/src/platform/gba/packer/main.cpp index a618dd6a..0569e181 100644 --- a/src/platform/gba/packer/main.cpp +++ b/src/platform/gba/packer/main.cpp @@ -34,6 +34,34 @@ inline void swap(T &a, T &b) { b = tmp; } +void launchApp(const char* cmdline) +{ + STARTUPINFOA si; + PROCESS_INFORMATION pi; + + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + si.cb = sizeof(si); + + CreateProcess( + NULL, + (char*)cmdline, + NULL, + NULL, + FALSE, + 0, + NULL, + NULL, + &si, + &pi + ); + + WaitForSingleObject(pi.hProcess, INFINITE); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} + #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) @@ -312,6 +340,19 @@ struct FileStream return aligned; } + uint32 align16() + { + uint32 pos = getPos(); + uint32 aligned = (pos + 15) & ~15; + + if (aligned != pos) { + static const uint32 zero = 0; + fwrite(&zero, 1, aligned - pos, f); + } + + return aligned; + } + template void read(T &result) { @@ -600,8 +641,7 @@ struct LevelPC struct Quad3DO { uint16 indices[4]; - uint16 flags; - uint16 _unused; + uint32 flags; void write(FileStream &f) const { @@ -610,7 +650,6 @@ struct LevelPC f.write(indices[2]); f.write(indices[3]); f.write(flags); - f.write(_unused); } }; @@ -636,7 +675,6 @@ struct LevelPC comp.indices[2] = indices[2]; comp.indices[3] = indices[3]; comp.flags = flags; - comp._unused = 0; comp.write(f); } }; @@ -1373,14 +1411,16 @@ struct LevelPC uint16 index; uint16 volume; uint16 chance; - uint16 flags; + uint8 flagsA; + uint8 flagsB; void write(FileStream &f) const { f.write(index); f.write(volume); f.write(chance); - f.write(flags); + f.write(flagsA); + f.write(flagsB); } }; @@ -1653,6 +1693,8 @@ struct LevelPC uint16 itemsCount; uint16 camerasCount; uint16 cameraFramesCount; + uint16 soundOffsetsCount; + uint16 _reserved; uint32 palette; uint32 lightmap; @@ -1700,6 +1742,9 @@ struct LevelPC f.write(itemsCount); f.write(camerasCount); f.write(cameraFramesCount); + f.write(soundOffsetsCount); + f.write(_reserved); + f.write(palette); f.write(lightmap); f.write(tiles); @@ -1744,13 +1789,13 @@ struct LevelPC Room::VertexComp roomVertices[MAX_ROOM_VERTICES]; int32 roomVerticesCount; - int32 addRoomVertex(const Room::Vertex &v) + int32 addRoomVertex(const Room::Vertex &v, bool ignoreG = false) { Room::VertexComp comp; comp.x = v.pos.x / 1024; comp.y = v.pos.y / 256; comp.z = v.pos.z / 1024; - comp.g = v.lighting >> 5; + comp.g = ignoreG ? 0 : (v.lighting >> 5); for (int32 i = 0; i < roomVerticesCount; i++) { @@ -2134,6 +2179,8 @@ struct LevelPC header.itemsCount = itemsCount; header.camerasCount = camerasCount; header.cameraFramesCount = cameraFramesCount; + header.soundOffsetsCount = soundOffsetsCount; + header._reserved = 0; header.palette = f.align4(); @@ -3338,6 +3385,8 @@ struct LevelPC header.itemsCount = itemsCount; header.camerasCount = camerasCount; header.cameraFramesCount = cameraFramesCount; + header.soundOffsetsCount = soundOffsetsCount; + header._reserved = 0; header.palette = 0; header.lightmap = 0; @@ -3394,12 +3443,72 @@ struct LevelPC { Quad q = room->quads[i]; calcQuadFlip(q); - q.indices[0] = addRoomVertex(room->vertices[q.indices[0]]); - q.indices[1] = addRoomVertex(room->vertices[q.indices[1]]); - q.indices[2] = addRoomVertex(room->vertices[q.indices[2]]); - q.indices[3] = addRoomVertex(room->vertices[q.indices[3]]); - q.write3DO(f); + const Room::Vertex &v0 = room->vertices[q.indices[0]]; + const Room::Vertex &v1 = room->vertices[q.indices[1]]; + const Room::Vertex &v2 = room->vertices[q.indices[2]]; + const Room::Vertex &v3 = room->vertices[q.indices[3]]; + + + uint32 intensity = (v0.lighting + v1.lighting + v2.lighting + v3.lighting) >> (2 + 5); + ASSERT(intensity <= 255); + + q.indices[0] = addRoomVertex(v0, true); + q.indices[1] = addRoomVertex(v1, true); + q.indices[2] = addRoomVertex(v2, true); + q.indices[3] = addRoomVertex(v3, true); + + vec3i a, b, n; + a.x = v1.pos.x - v0.pos.x; + a.y = v1.pos.y - v0.pos.y; + a.z = v1.pos.z - v0.pos.z; + + b.x = v2.pos.x - v0.pos.x; + b.y = v2.pos.y - v0.pos.y; + b.z = v2.pos.z - v0.pos.z; + + n.x = b.y * a.z - b.z * a.y; + n.y = b.z * a.x - b.x * a.z; + n.z = b.x * a.y - b.y * a.x; + + if (n.x < 0) n.x = -1; + if (n.x > 0) n.x = +1; + if (n.y < 0) n.y = -1; + if (n.y > 0) n.y = +1; + if (n.z < 0) n.z = -1; + if (n.z > 0) n.z = +1; + + static const struct { + int32 x, y, z; + int32 mask; + } normals[9] = { + { -1, 0, 0, 2 << 0 }, + { 1, 0, 0, 1 << 0 }, + { 0, -1, 0, 2 << 2 }, + { 0, 1, 0, 1 << 2 }, + { 0, 0, -1, 2 << 4 }, + { 0, 0, 1, 1 << 4 } + }; + + uint32 normalMask = 255; + for (int32 i = 0; i < 9; i++) + { + if (n.x == normals[i].x && + n.y == normals[i].y && + n.z == normals[i].z) + { + normalMask = normals[i].mask; + break; + } + } + + Quad3DO comp; + comp.indices[0] = q.indices[0]; + comp.indices[1] = q.indices[1]; + comp.indices[2] = q.indices[2]; + comp.indices[3] = q.indices[3]; + comp.flags = q.flags | (normalMask << 16) | (intensity << 24); + comp.write(f); } info.triangles = f.align4(); @@ -3862,7 +3971,45 @@ struct LevelPC f.writeObj(soundInfo, soundInfoCount); header.soundData = f.align4(); - //f.write(soundData, soundDataSize); + + uint8* soundBuf = new uint8[2 * 1024 * 1024]; + + for (int32 i = 0; i < soundOffsetsCount; i++) + { + { // save wav to the temporary file + uint8* data = soundData + soundOffsets[i]; + int32 size = *(int32*)(data + 4) + 8; + + FILE* f = fopen("tmp.wav", "wb"); + fwrite(data, 1, size, f); + fclose(f); + } + + launchApp("C:\\Program Files\\ffmpeg\\ffmpeg.exe -y -i tmp.wav -ac 1 -ar 4000 -acodec pcm_s8 tmp.aiff"); + + int32 soundSize; + { // read converted aiff + FILE* f = fopen("tmp.aiff", "rb"); + fseek(f, 0, SEEK_END); + soundSize = ftell(f); + fseek(f, 0, SEEK_SET); + fread(soundBuf, 1, soundSize, f); + fclose(f); + } + + // update sound sample offset + soundOffsets[i] = f.align4() - header.soundData + 2; + + uint16 zero = 0; + f.write(zero); + + //ASSERT(soundOffsets[i] % 16 == 0); + + // write aiff sound data + f.write(soundBuf, soundSize); + } + + delete[] soundBuf; header.soundOffsets = f.align4(); f.write(soundOffsets, soundOffsetsCount); diff --git a/src/platform/gba/sound.cpp b/src/platform/gba/sound.cpp new file mode 100644 index 00000000..7e78d5bc --- /dev/null +++ b/src/platform/gba/sound.cpp @@ -0,0 +1,206 @@ +#include "common.h" + +void decodeIMA(IMA_STATE &state, const uint8* data, int32* buffer, int32 size); + +struct Music +{ + const uint8* data; + int32 size; + int32 pos; + IMA_STATE state; + + void fill(int32* buffer, int32 count) + { + int32 len = X_MIN(size - pos, count >> 1); + + decodeIMA(state, data + pos, buffer, len); + + pos += len; + + if (pos >= size) + { + data = NULL; + memset(buffer, 0, (count - (len << 1)) * sizeof(buffer[0])); + } + } +}; + +struct Sample +{ + const uint8* data; + int32 size; + int32 pos; + int32 inc; + int32 volume; + + void fill(int32* buffer, int32 count) + { + for (int32 i = 0; i < count; i++) + { + buffer[i] += SND_DECODE(data[pos >> SND_FIXED_SHIFT]) * volume; + + pos += inc; + if (pos >= size) + { + // TODO LOOP + data = NULL; + return; + } + } + } +}; + +Music music; +Sample channels[SND_CHANNELS]; +int32 channelsCount; + +#ifdef __GBA__ +extern const uint8_t TRACKS_IMA[]; +#else +extern const void* TRACKS_IMA; +#endif + +#define CALC_INC (((SND_SAMPLE_FREQ << SND_FIXED_SHIFT) / SND_OUTPUT_FREQ) * pitch >> SND_PITCH_SHIFT) + +void sndInit() +{ + // initialized in main.cpp +} + +void sndInitSamples() +{ + // nothing to do +} + +void* sndPlaySample(int32 index, int32 volume, int32 pitch, int32 mode) +{ + const uint8 *data = level.soundData + level.soundOffsets[index]; + + int32 size; + memcpy(&size, data + 40, 4); // TODO preprocess and remove wave header + data += 44; + + if (mode == UNIQUE || mode == REPLAY) + { + for (int32 i = 0; i < channelsCount; i++) + { + Sample* sample = channels + i; + + if (sample->data != data) + continue; + + sample->inc = CALC_INC; + sample->volume = volume; + + if (mode == REPLAY) + { + sample->pos = 0; + } + + return sample; + } + } + + if (channelsCount >= SND_CHANNELS) + return NULL; + + Sample* sample = channels + channelsCount++; + sample->data = data; + sample->size = size << SND_FIXED_SHIFT; + sample->pos = 0; + sample->inc = CALC_INC; + sample->volume = volume; + + return sample; +} + +void sndPlayTrack(int32 track) +{ + if (track == gCurTrack) + return; + + gCurTrack = track; + + struct TrackInfo { + int32 offset; + int32 size; + }; + + const TrackInfo* info = (const TrackInfo*)TRACKS_IMA + track; + + if (!info->size) + return; + + music.data = (uint8*)TRACKS_IMA + info->offset; + music.size = info->size; + music.pos = 0; + //music.volume = (1 << SND_VOL_SHIFT); + music.state.smp = 0; + music.state.idx = 0; +} + +void sndStopTrack() +{ + music.data = NULL; +} + +void sndStopSample(int32 index) +{ + const uint8 *data = level.soundData + level.soundOffsets[index] + 44; + + int32 i = channelsCount; + + while (--i >= 0) + { + if (channels[i].data == data) + { + channels[i] = channels[--channelsCount]; + } + } +} + +void sndStop() +{ + channelsCount = 0; + music.data = NULL; +} + +void sndFill(uint8* buffer, int32 count) +{ +#ifdef PROFILE_SOUNDTIME + PROFILE_CLEAR(); + PROFILE(CNT_SOUND); +#endif + + if ((channelsCount == 0) && !music.data) + { + dmaFill(buffer, SND_ENCODE(0), count); + return; + } + + int32 tmp[SND_SAMPLES]; + + if (music.data) { + music.fill(tmp, count); + } else { + dmaFill(tmp, 0, sizeof(tmp)); + } + + int32 ch = channelsCount; + while (ch--) + { + Sample* sample = channels + ch; + + sample->fill(tmp, count); + + if (!sample->data) { + channels[ch] = channels[--channelsCount]; + } + } + + for (int32 i = 0; i < count; i++) + { + int32 samp = X_CLAMP(tmp[i] >> SND_VOL_SHIFT, SND_MIN, SND_MAX); + buffer[i] = SND_ENCODE(samp); + } +}