Procházet zdrojové kódy

audio: allow to load a sample from raw data.

legacy
Sam Hocevar před 5 roky
rodič
revize
6f0155a50e
5 změnil soubory, kde provedl 75 přidání a 41 odebrání
  1. +38
    -28
      doc/tutorial/09_sound.cpp
  2. +15
    -6
      src/audio/audio.cpp
  3. +17
    -2
      src/audio/sample.cpp
  4. +3
    -3
      src/lol/audio/sample.h
  5. +2
    -2
      src/ui/sdl-input.cpp

+ 38
- 28
doc/tutorial/09_sound.cpp Zobrazit soubor

@@ -17,6 +17,7 @@
#include <lol/engine.h>

#include <functional>
#include <array>

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<int16_t, 20000> m_instrument;
sample* m_sample;
Text *m_text;
};



+ 15
- 6
src/audio/audio.cpp Zobrazit soubor

@@ -12,6 +12,7 @@

#include <lol/engine-internal.h>

#include <array>
#include <unordered_set>
#include <functional>

@@ -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<void(void *, int)> m_callback;
std::array<uint16_t, LOL_AUDIO_CHANNELS * LOL_AUDIO_SAMPLE_FRAMES> m_empty; // SDL needs a reference to this
#if defined LOL_USE_SDL_MIXER
std::vector<uint8_t> m_empty; // SDL keeps a reference to this
Mix_Chunk *m_chunk;
#endif
};
@@ -47,7 +55,7 @@ std::unordered_set<std::shared_ptr<audio_streamer>> 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<void(void *, int)> const &f)
s->m_callback(stream, bytes);
};

std::shared_ptr<audio_streamer> s = std::make_shared<audio_streamer>();
auto s = std::make_shared<audio_streamer>();
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());


+ 17
- 2
src/audio/sample.cpp Zobrazit soubor

@@ -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<sample_data>())
{
data->m_name = std::string("<sample> ") + path;

@@ -84,13 +89,23 @@ sample::sample(std::string const &path)
#endif
}

sample::sample(void const *samples, size_t len)
: data(std::make_unique<sample_data>())
{
data->m_name = std::string("<sample>");

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


+ 3
- 3
src/lol/audio/sample.h Zobrazit soubor

@@ -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<class sample_data> data;
};

} /* namespace lol */


+ 2
- 2
src/ui/sdl-input.cpp Zobrazit soubor

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


Načítá se…
Zrušit
Uložit