Skip to content

Commit

Permalink
#9 support Web Audio API, defines for ADPCM, MP3 & OGG decoders, play…
Browse files Browse the repository at this point in the history
… bubble sound when Lara is under water
  • Loading branch information
XProger committed Oct 4, 2016
1 parent 6591726 commit 831e076
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 23 deletions.
Binary file modified bin/OpenLara.exe
Binary file not shown.
7 changes: 2 additions & 5 deletions src/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,7 @@ struct Controller {
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
uint32 c = level->soundOffsets[b.offset + rand() % ((b.flags & 0xFF) >> 2)];
void *p = &level->soundData[c];
#ifdef WIN32
Sound::play(new Stream(p, 1024 * 1024), b.volume / 255.0f, 0.0f, Sound::Flags::PAN);
// PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
#endif
}
}

Expand Down Expand Up @@ -373,8 +370,8 @@ struct Controller {
case TR::ANIM_CMD_SPECIAL : // special commands
if (frameIndex != animPrevFrame && frameIndex + anim->frameStart == ptr[0]) {
switch (ptr[1]) {
case TR::ANIM_CMD_SPECIAL_FLIP : angle.y = angle.y + PI; break;
case TR::ANIM_CMD_SPECIAL_BUBBLE : /* playSound(TR::SND_BUBBLE); */ break;
case TR::ANIM_CMD_SPECIAL_FLIP : angle.y = angle.y + PI; break;
case TR::ANIM_CMD_SPECIAL_BUBBLE : playSound(TR::SND_BUBBLE); break;
case TR::ANIM_CMD_SPECIAL_CTRL : LOG("water out ?\n"); break;
default : LOG("unknown special cmd %d\n", (int)ptr[1]);
}
Expand Down
10 changes: 6 additions & 4 deletions src/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ namespace Game {
Core::init();
Stream stream("LEVEL2_DEMO.PHD");
level = new Level(stream);

//Sound::play(Sound::openWAD("05_Lara's_Themes.wav"), 1, 1, 0);
Sound::play(new Stream("05.ogg"), 1, 1, 0);
//Sound::play(new Stream("03.mp3"), 1, 1, 0);

#ifndef __EMSCRIPTEN__
//Sound::play(Sound::openWAD("05_Lara's_Themes.wav"), 1, 1, 0);
Sound::play(new Stream("05.ogg"), 1, 1, 0);
//Sound::play(new Stream("03.mp3"), 1, 1, 0);
#endif
}

void free() {
Expand Down
52 changes: 42 additions & 10 deletions src/sound.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
#ifndef H_SOUND
#define H_SOUND

//#define DECODE_ADPCM
//#define DECODE_MP3
#define DECODE_OGG

#ifdef __EMSCRIPTEN__ // TODO: http streaming
#undef DECODE_MP3
#undef DECODE_OGG
#endif

#include "utils.h"
#include "libs/minimp3/minimp3.h"
#define STB_VORBIS_HEADER_ONLY
#include "libs/stb_vorbis/stb_vorbis.c"
#ifdef DECODE_MP3
#include "libs/minimp3/minimp3.h"
#endif
#ifdef DECODE_OGG
#define STB_VORBIS_HEADER_ONLY
#include "libs/stb_vorbis/stb_vorbis.c"
#endif

#define SND_CHANNELS_MAX 32
#define BUFFER_SIZE_MP3 8192

namespace Sound {

Expand Down Expand Up @@ -56,6 +68,7 @@ namespace Sound {
}
};

#ifdef DECODE_ADPCM
struct ADPCM : Decoder { // https://wiki.multimedia.cx/?title=Microsoft_ADPCM
int size, block;

Expand Down Expand Up @@ -127,7 +140,9 @@ namespace Sound {
}
}
};

#endif

#ifdef DECODE_MP3
struct MP3 : Decoder {
mp3_decoder_t mp3;
char *buffer;
Expand Down Expand Up @@ -160,7 +175,9 @@ namespace Sound {
return i;
}
};
#endif

#ifdef DECODE_OGG
struct OGG : Decoder {
stb_vorbis *ogg;
stb_vorbis_alloc alloc;
Expand Down Expand Up @@ -195,6 +212,7 @@ namespace Sound {
return i;
}
};
#endif

struct Listener {
mat4 matrix;
Expand All @@ -216,7 +234,7 @@ namespace Sound {
int flags;
bool isPlaying;

Sample(Stream *stream, float volume, float pitch, int flags) : decoder(NULL), volume(volume), pitch(pitch), flags(flags), isPlaying(true) {
Sample(Stream *stream, float volume, float pitch, int flags) : decoder(NULL), volume(volume), pitch(pitch), flags(flags) {
uint32 fourcc;
stream->read(fourcc);
if (fourcc == FOURCC("RIFF")) { // wav
Expand All @@ -240,26 +258,36 @@ namespace Sound {
stream->seek(size - sizeof(waveFmt));
} else if (type == FOURCC("data")) {
if (waveFmt.format == 1) decoder = new PCM(stream, waveFmt.channels, waveFmt.samplesPerSec, size, waveFmt.sampleBits);
#ifdef DECODE_ADPCM
if (waveFmt.format == 2) decoder = new ADPCM(stream, waveFmt.channels, size, waveFmt.block);
#endif
break;
} else
stream->seek(size);
}
} else if (fourcc == FOURCC("OggS")) { // ogg
}
#ifdef DECODE_OGG
else if (fourcc == FOURCC("OggS")) { // ogg
stream->seek(-4);
decoder = new OGG(stream, 2);
} else if (fourcc == FOURCC("ID3\3")) { // mp3
}
#endif
#ifdef DECODE_MP3
else if (fourcc == FOURCC("ID3\3")) { // mp3
decoder = new MP3(stream, 2);
}

ASSERT(decoder != NULL);
#endif

isPlaying = decoder != NULL;
ASSERT(isPlaying);
}

~Sample() {
delete decoder;
}

bool render(Frame *frames, int count) {
if (!isPlaying) return 0;
int i = 0;
while (i < count) {
int res = decoder->decode(&frames[i], count - i);
Expand All @@ -277,13 +305,17 @@ namespace Sound {

void init() {
channelsCount = 0;
#ifdef DECODE_MP3
mp3_decode_init();
#endif
}

void free() {
for (int i = 0; i < channelsCount; i++)
delete channels[i];
#ifdef DECODE_MP3
mp3_decode_free();
#endif
}

void fill(Frame *frames, int count) {
Expand Down
4 changes: 2 additions & 2 deletions src/web/build.bat
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
set SRC=main.cpp ../libs/minimp3/minimp3.cpp ../libs/stb_vorbis/stb_vorbis.c
call em++ %SRC% -O2 -s ASSERTIONS=1 -Wno-deprecated-register --llvm-opts 2 --closure 2 -std=c++11 -o OpenLara.js --preload-file ./LEVEL2_DEMO.PHD -I..\
set SRC=main.cpp
call em++ %SRC% -O2 -s ASSERTIONS=1 -Wno-deprecated-register --llvm-opts 2 --closure 1 -std=c++11 -o OpenLara.js --preload-file ./LEVEL2_DEMO.PHD -I..\
gzip.exe -9 -f OpenLara.data OpenLara.js OpenLara.js.mem
26 changes: 25 additions & 1 deletion src/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,30 @@
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
},
};

function snd_init() {
var AudioContext = window.AudioContext || window.webkitAudioContext;
if (!AudioContext) return;
var ctx = new (window.AudioContext || window.webkitAudioContext)();
var count = 2048;
var frames = Module._malloc(count * 4); // interleaved short L, R
var proc = ctx.createScriptProcessor(count, 2, 2);

proc.onaudioprocess = function(e) {
var L = e.outputBuffer.getChannelData(0),
R = e.outputBuffer.getChannelData(1);
Module.ccall('snd_fill', 'null', ['number', 'number'], [frames, count]);
var index = frames;
for (var i = 0; i < count; i++) {
L[i] = Module.getValue(index , 'i16') / 0x8000;
R[i] = Module.getValue(index + 2, 'i16') / 0x8000;
index += 4;
}
}
proc.connect(ctx.destination);
}

var gl = canvasElement.getContext("webgl") || canvasElement.getContext("experimental-webgl");

Expand Down Expand Up @@ -74,5 +96,7 @@
script.src = "OpenLara.js";
document.body.appendChild(script);
</script>

<audio autoplay loop><source src="05.ogg" type="audio/ogg"></audio>
</body>
</html>
10 changes: 9 additions & 1 deletion src/web/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ int getTime() {
return (int)emscripten_get_now();
}

extern "C" {
void EMSCRIPTEN_KEEPALIVE snd_fill(Sound::Frame *frames, int count) {
Sound::fill(frames, count);
}
}

void main_loop() {
int time = getTime();

Expand Down Expand Up @@ -168,7 +174,7 @@ EM_BOOL mouseCallback(int eventType, const EmscriptenMouseEvent *e, void *userDa
int main() {
initGL();

emscripten_set_canvas_size(Core::width = 1280, Core::height = 720);
emscripten_set_canvas_size(Core::width = 854, Core::height = 480);

emscripten_set_keydown_callback(0, 0, 1, keyCallback);
emscripten_set_keyup_callback(0, 0, 1, keyCallback);
Expand All @@ -185,6 +191,8 @@ int main() {

Game::init();

emscripten_run_script("snd_init()");

lastTime = getTime();
fpsTime = lastTime + 1000;
fps = 0;
Expand Down

0 comments on commit 831e076

Please sign in to comment.