1
0
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:
XProger
2021-11-01 08:00:15 +03:00
parent 3b368ac6a4
commit f961161ff6
11 changed files with 439 additions and 343 deletions

View File

@@ -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);

View File

@@ -135,7 +135,7 @@ int32 getTextWidth(const char* text)
int32 w = 0;
char c;
while (c = *text++)
while ((c = *text++))
{
if (c == ' ') {
w += 6;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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)&REG_FIFO_A;
#ifdef USE_9BIT_SOUND
REG_DMA2DAD = (u32)&REG_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++)
{

View File

@@ -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
View 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);
}
}