mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-21 04:11:53 +02:00
#368 GBA remove experimental 9-bit audio support, move sound.h to platform dependent sound.cpp
This commit is contained in:
@@ -19,7 +19,6 @@
|
||||
#define MODE4
|
||||
#define USE_DIV_TABLE
|
||||
#define ROM_READ
|
||||
//#define USE_9BIT_SOUND
|
||||
|
||||
#include <tonc.h>
|
||||
#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 <displayutils.h>
|
||||
#include <debug.h>
|
||||
@@ -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 <class T>
|
||||
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);
|
||||
|
@@ -135,7 +135,7 @@ int32 getTextWidth(const char* text)
|
||||
int32 w = 0;
|
||||
|
||||
char c;
|
||||
while (c = *text++)
|
||||
while ((c = *text++))
|
||||
{
|
||||
if (c == ' ') {
|
||||
w += 6;
|
||||
|
@@ -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)
|
||||
|
@@ -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,48 +86,10 @@ 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);
|
||||
sndStopSample(b->index + i);
|
||||
}
|
||||
}
|
||||
|
||||
void musicPlay(int32 track)
|
||||
{
|
||||
#ifdef __3DO__
|
||||
return;
|
||||
#endif
|
||||
if (track == 13) {
|
||||
gCurTrack = 0;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
const Anim* anim = level.anims + animIndex;
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
@@ -22,6 +22,7 @@
|
||||
<ClCompile Include="..\..\fixed\common.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="render.cpp" />
|
||||
<ClCompile Include="sound.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\fixed\camera.h" />
|
||||
@@ -36,7 +37,6 @@
|
||||
<ClInclude Include="..\..\fixed\nav.h" />
|
||||
<ClInclude Include="..\..\fixed\object.h" />
|
||||
<ClInclude Include="..\..\fixed\room.h" />
|
||||
<ClInclude Include="..\..\fixed\sound.h" />
|
||||
<ClInclude Include="rasterizer_mode13.h" />
|
||||
<ClInclude Include="rasterizer_mode4.h" />
|
||||
</ItemGroup>
|
||||
|
@@ -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++)
|
||||
{
|
||||
|
@@ -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 <typename T>
|
||||
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);
|
||||
|
206
src/platform/gba/sound.cpp
Normal file
206
src/platform/gba/sound.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user