diff --git a/doc/tutorial/09_sound.cpp b/doc/tutorial/09_sound.cpp index ac113115..602f5d93 100644 --- a/doc/tutorial/09_sound.cpp +++ b/doc/tutorial/09_sound.cpp @@ -17,6 +17,7 @@ #include #include +#include using namespace lol; @@ -25,8 +26,17 @@ class sound_demo : public WorldEntity public: sound_demo() { - for (auto &val : m_streams) - val = -1; + for (int i = 0; i < 2; ++i) + { + auto f = std::bind(&sound_demo::synth, this, i, + std::placeholders::_1, + std::placeholders::_2); + m_streams[i] = audio::start_streaming(f); + } + + for (size_t i = 0; i < m_instrument.size(); ++i) + m_instrument[i] = (int16_t)(i % 80 * (10000 - lol::abs(i - 10000)) * 40 / 10000); + m_sample = sample::create(m_instrument.data(), 40000); m_text = new Text("SPACE for sine wave, Left Click for white noise", "data/font/ascii.png"); @@ -39,18 +49,25 @@ public: Ticker::Unref(m_text); } - void synth(int mode, void *buf, int bytes) + void synth(int channel, void *buf, int bytes) { + int mode = (1 << channel) & m_mask; + int16_t *stream = (int16_t *)buf; - for (int i = 0; i < bytes / 2; ++i) + for (int i = 0; i < bytes / 2; i += 2) { switch (mode) { - case 0: // sine wave - stream[i] = lol::sin(4 * i * F_TAU / bytes) > 0 ? 800 : -800; + case 2: // square / triangle signals + stream[i] = 800 * (i % 128 > 64 ? -1 : 1); + stream[i + 1] = (i % 128 - 64) * 15; break; case 1: // white noise - stream[i] = lol::rand(-200, 200); + stream[i] = lol::rand(-2000, 2000); + stream[i + 1] = lol::rand(-1000, 1000); + break; + case 0: // inactive + stream[i] = stream[i + 1] = 0; break; } } @@ -63,35 +80,28 @@ public: auto mouse = input::mouse(); auto keyboard = input::keyboard(); - for (int i = 0; i < 2; ++i) - { - if (i == 0 && !keyboard->key_pressed(input::key::SC_Space)) - continue; - if (i == 1 && !mouse->button_pressed(input::button::BTN_Left)) - continue; + if (keyboard->key_pressed(input::key::SC_Return)) + m_sample->play(); - if (m_streams[i] < 0) - { - auto f = std::bind(&sound_demo::synth, this, i, - std::placeholders::_1, - std::placeholders::_2); - m_streams[i] = audio::start_streaming(f); - } - else - { - audio::stop_streaming(m_streams[i]); - m_streams[i] = -1; - } - } + if (keyboard->key_pressed(input::key::SC_Space)) + m_mask ^= 2; + + if (mouse->button_pressed(input::button::BTN_Left)) + m_mask ^= 1; } - virtual void tick_draw(float seconds, Scene &scene) override + virtual bool release_game() override { - WorldEntity::tick_draw(seconds, scene); + for (int i = 0; i < 2; ++i) + audio::stop_streaming(m_streams[i]); + return true; } private: int m_streams[2]; + int m_mask = 0; + std::array m_instrument; + sample* m_sample; Text *m_text; }; diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index fa28f935..cbadecbc 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -12,6 +12,7 @@ #include +#include #include #include @@ -25,6 +26,13 @@ # endif #endif +// Buffer size, in samples (https://wiki.libsdl.org/SDL_AudioSpec) +// “[…] refers to the size of the audio buffer in sample frames. A sample frame +// is a chunk of audio data of the size specified in format multiplied by the +// number of channels.” +#define LOL_AUDIO_SAMPLE_FRAMES 1024 +#define LOL_AUDIO_CHANNELS 2 + namespace lol { @@ -32,8 +40,8 @@ struct audio_streamer { int m_channel; std::function m_callback; + std::array m_empty; // SDL needs a reference to this #if defined LOL_USE_SDL_MIXER - std::vector m_empty; // SDL keeps a reference to this Mix_Chunk *m_chunk; #endif }; @@ -47,7 +55,7 @@ std::unordered_set> audio::m_streamers; #if defined LOL_USE_SDL_MIXER void audio::init() { - Mix_OpenAudio(22050, AUDIO_S16, 2, 1024); + Mix_OpenAudio(22050, AUDIO_S16, LOL_AUDIO_CHANNELS, LOL_AUDIO_SAMPLE_FRAMES); set_channels(8); } @@ -79,12 +87,13 @@ int audio::start_streaming(std::function const &f) s->m_callback(stream, bytes); }; - std::shared_ptr s = std::make_shared(); + auto s = std::make_shared(); m_streamers.insert(s); - s->m_empty.resize(1024); - s->m_chunk = Mix_QuickLoad_RAW(s->m_empty.data(), - (Uint32)(s->m_empty.size() * sizeof(uint8_t))); + Uint8* audio_data = (Uint8*)s->m_empty.data(); + Uint32 audio_size = (Uint32)(s->m_empty.size() * sizeof(s->m_empty[0])); + memset(audio_data, 17, audio_size); + s->m_chunk = Mix_QuickLoad_RAW(audio_data, audio_size); s->m_channel = Mix_PlayChannel(-1, s->m_chunk, -1); s->m_callback = f; Mix_RegisterEffect(s->m_channel, trampoline, nullptr, s.get()); diff --git a/src/audio/sample.cpp b/src/audio/sample.cpp index ca2f1e5c..df5e411d 100644 --- a/src/audio/sample.cpp +++ b/src/audio/sample.cpp @@ -58,6 +58,11 @@ sample *sample::create(std::string const &path) return ret ? ret : sample_cache.set(path, new sample(path)); } +sample *sample::create(void const *samples, size_t len) +{ + return new sample(samples, len); +} + void sample::destroy(sample *s) { // FIXME: decrement! @@ -65,7 +70,7 @@ void sample::destroy(sample *s) } sample::sample(std::string const &path) - : data(new sample_data()) + : data(std::make_unique()) { data->m_name = std::string(" ") + path; @@ -84,13 +89,23 @@ sample::sample(std::string const &path) #endif } +sample::sample(void const *samples, size_t len) + : data(std::make_unique()) +{ + data->m_name = std::string(""); + +#if defined LOL_USE_SDL_MIXER + data->m_chunk = Mix_QuickLoad_RAW((Uint8 *)samples, (Uint32)len); + data->m_channel = -1; +#endif +} + sample::~sample() { #if defined LOL_USE_SDL_MIXER if (data->m_chunk) Mix_FreeChunk(data->m_chunk); #endif - delete data; } void sample::tick_game(float seconds) diff --git a/src/lol/audio/sample.h b/src/lol/audio/sample.h index 7415d924..77e3b95e 100644 --- a/src/lol/audio/sample.h +++ b/src/lol/audio/sample.h @@ -25,16 +25,16 @@ namespace lol { -class sample_data; - class sample : public entity { public: static sample *create(std::string const &path); + static sample* create(void const* samples, size_t len); static void destroy(sample *s); protected: sample(std::string const &path); + sample(void const *samples, size_t len); virtual ~sample(); /* Inherited from entity */ @@ -48,7 +48,7 @@ public: void stop(); private: - sample_data *data; + std::unique_ptr data; }; } /* namespace lol */ diff --git a/src/ui/sdl-input.cpp b/src/ui/sdl-input.cpp index 13c31216..8fca57fd 100644 --- a/src/ui/sdl-input.cpp +++ b/src/ui/sdl-input.cpp @@ -197,8 +197,8 @@ void SdlInput::tick(float seconds) //case SDL_TEXTEDITING: //TODO: handle that? case SDL_TEXTINPUT: - keyboard->internal_add_text(event.text.text); - break; + keyboard->internal_add_text(event.text.text); + break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: