diff --git a/bin/OpenLara.exe b/bin/OpenLara.exe index 84b909d..ae1da41 100644 Binary files a/bin/OpenLara.exe and b/bin/OpenLara.exe differ diff --git a/src/controller.h b/src/controller.h index e37eada..38c5959 100644 --- a/src/controller.h +++ b/src/controller.h @@ -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 } } @@ -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]); } diff --git a/src/game.h b/src/game.h index 09636f9..64bc0c1 100644 --- a/src/game.h +++ b/src/game.h @@ -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() { diff --git a/src/sound.h b/src/sound.h index 7b555b7..f0daf42 100644 --- a/src/sound.h +++ b/src/sound.h @@ -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 { @@ -56,6 +68,7 @@ namespace Sound { } }; +#ifdef DECODE_ADPCM struct ADPCM : Decoder { // https://wiki.multimedia.cx/?title=Microsoft_ADPCM int size, block; @@ -127,7 +140,9 @@ namespace Sound { } } }; - +#endif + +#ifdef DECODE_MP3 struct MP3 : Decoder { mp3_decoder_t mp3; char *buffer; @@ -160,7 +175,9 @@ namespace Sound { return i; } }; +#endif +#ifdef DECODE_OGG struct OGG : Decoder { stb_vorbis *ogg; stb_vorbis_alloc alloc; @@ -195,6 +212,7 @@ namespace Sound { return i; } }; +#endif struct Listener { mat4 matrix; @@ -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 @@ -240,19 +258,28 @@ 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() { @@ -260,6 +287,7 @@ namespace Sound { } bool render(Frame *frames, int count) { + if (!isPlaying) return 0; int i = 0; while (i < count) { int res = decoder->decode(&frames[i], count - i); @@ -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) { diff --git a/src/web/build.bat b/src/web/build.bat index 39b9900..55c1117 100644 --- a/src/web/build.bat +++ b/src/web/build.bat @@ -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 \ No newline at end of file diff --git a/src/web/index.html b/src/web/index.html index 0da390a..992a664 100644 --- a/src/web/index.html +++ b/src/web/index.html @@ -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"); @@ -74,5 +96,7 @@ script.src = "OpenLara.js"; document.body.appendChild(script); + + \ No newline at end of file diff --git a/src/web/main.cpp b/src/web/main.cpp index 1f60d1c..125fd56 100644 --- a/src/web/main.cpp +++ b/src/web/main.cpp @@ -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(); @@ -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); @@ -185,6 +191,8 @@ int main() { Game::init(); + emscripten_run_script("snd_init()"); + lastTime = getTime(); fpsTime = lastTime + 1000; fps = 0;