mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-07 21:56:37 +02:00
#9 support Web Audio API, defines for ADPCM, MP3 & OGG decoders, play bubble sound when Lara is under water
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +371,7 @@ struct Controller {
|
||||
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_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]);
|
||||
}
|
||||
|
@@ -15,9 +15,11 @@ namespace Game {
|
||||
Stream stream("LEVEL2_DEMO.PHD");
|
||||
level = new Level(stream);
|
||||
|
||||
#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() {
|
||||
|
48
src/sound.h
48
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT(decoder != NULL);
|
||||
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) {
|
||||
|
@@ -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
|
@@ -41,9 +41,31 @@
|
||||
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");
|
||||
|
||||
Module.setStatus('Downloading...');
|
||||
@@ -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>
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user