ソースを参照

audio: minimal streaming API

This will allow us to generate sounds on the fly on several dedicated
channels. Until now we could only play fully loaded samples.
legacy
Sam Hocevar 8年前
コミット
7619caef3e
5個のファイルの変更181行の追加7行の削除
  1. +1
    -0
      .gitignore
  2. +114
    -0
      doc/tutorial/09_sound.cpp
  3. +5
    -1
      doc/tutorial/Makefile.am
  4. +57
    -5
      src/audio/audio.cpp
  5. +4
    -1
      src/lol/audio/audio.h

+ 1
- 0
.gitignore ファイルの表示

@@ -95,6 +95,7 @@ doc/tutorial/05_easymesh
doc/tutorial/06_sprite
doc/tutorial/07_input
doc/tutorial/08_fbo
doc/tutorial/09_sound
doc/tutorial/11_fractal
doc/tutorial/12_voronoi
doc/tutorial/13_shader_builder


+ 114
- 0
doc/tutorial/09_sound.cpp ファイルの表示

@@ -0,0 +1,114 @@
//
// Lol Engine — Sound tutorial
//
// Copyright © 2011—2016 Sam Hocevar <sam@hocevar.net>
//
// Lol Engine is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
//

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <lol/engine.h>

#include <functional>

using namespace lol;

class sound_demo : public WorldEntity
{
public:
sound_demo()
{
for (auto &val : m_streams)
val = -1;

m_controller = new Controller("Default");
m_profile << InputProfile::Keyboard(0, "Space")
<< InputProfile::MouseKey(1, "Left");
m_controller->Init(m_profile);
m_mouse = InputDevice::GetMouse();

m_text = new Text("SPACE for sine wave, Left Click for white noise",
"data/font/ascii.png");
m_text->SetPos(vec3(5, 5, 1));
Ticker::Ref(m_text);
}

~sound_demo()
{
Ticker::Unref(m_text);
}

void synth(int mode, void *buf, int bytes)
{
uint16_t *stream = (uint16_t *)buf;
for (int i = 0; i < bytes / 2; ++i)
{
switch (mode)
{
case 0: // sine wave
stream[i] = 400 * lol::sin(12 * i * F_TAU / bytes);
break;
case 1: // white noise
stream[i] = lol::rand(-120, 120);
break;
}
}
}

virtual void TickGame(float seconds)
{
WorldEntity::TickGame(seconds);

for (int i = 0; i < 2; ++i)
{
if (!m_controller->WasKeyPressedThisFrame(i))
continue;

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;
}
}
}

virtual void TickDraw(float seconds, Scene &scene)
{
WorldEntity::TickDraw(seconds, scene);
}

private:
int m_streams[2];

InputDevice *m_mouse;
Controller *m_controller;
InputProfile m_profile;

Text *m_text;
};

int main(int argc, char **argv)
{
sys::init(argc, argv);

Application app("Tutorial 9: Sound", ivec2(640, 480), 60.0f);
new sound_demo();
app.Run();

return EXIT_SUCCESS;
}


+ 5
- 1
doc/tutorial/Makefile.am ファイルの表示

@@ -3,7 +3,7 @@ include $(top_srcdir)/build/autotools/common.am

if BUILD_TUTORIAL
noinst_PROGRAMS = 01_triangle 02_cube 03_noise 04_texture 05_easymesh \
06_sprite 07_input 08_fbo 11_fractal \
06_sprite 07_input 08_fbo 09_sound 11_fractal \
12_voronoi 13_shader_builder 14_lol_lua
endif

@@ -43,6 +43,10 @@ endif
08_fbo_CPPFLAGS = $(AM_CPPFLAGS)
08_fbo_DEPENDENCIES = @LOL_DEPS@

09_sound_SOURCES = 09_sound.cpp
09_sound_CPPFLAGS = $(AM_CPPFLAGS)
09_sound_DEPENDENCIES = @LOL_DEPS@

11_fractal_SOURCES = 11_fractal.cpp 11_fractal.lolfx
11_fractal_CPPFLAGS = $(AM_CPPFLAGS)
11_fractal_DEPENDENCIES = @LOL_DEPS@


+ 57
- 5
src/audio/audio.cpp ファイルの表示

@@ -28,14 +28,26 @@
namespace lol
{

/*
struct audio_streamer
{
int m_channel;
std::function<void(void *, int)> m_callback;
#if defined LOL_USE_SDL_MIXER
Mix_Chunk *m_chunk;
#endif
};

array<audio_streamer *> g_streamers;

/*
* Public audio class
*/

void audio::init()
{
#if defined LOL_USE_SDL_MIXER
Mix_OpenAudio(22050, AUDIO_S16, 8, 1024);
Mix_OpenAudio(22050, AUDIO_S16, 2, 1024);
set_channels(8);
#endif
}

@@ -61,8 +73,6 @@ void audio::mute_all()
{
#if defined LOL_USE_SDL_MIXER
Mix_Volume(-1,0);
#else
UNUSED(false);
#endif
}

@@ -70,8 +80,50 @@ void audio::unmute_all()
{
#if defined LOL_USE_SDL_MIXER
Mix_Volume(-1,MIX_MAX_VOLUME);
#endif
}

int audio::start_streaming(std::function<void(void *, int)> const &f)
{
#if defined LOL_USE_SDL_MIXER
static auto trampoline = [](int, void *stream, int bytes, void *udata)
{
auto s = (audio_streamer *)udata;
s->m_callback(stream, bytes);
};

audio_streamer *s = new audio_streamer();
g_streamers.push(s);

array<uint8_t> empty;
empty.resize(1024);
s->m_chunk = Mix_QuickLoad_RAW(empty.data(), empty.bytes());
s->m_channel = Mix_PlayChannel(-1, s->m_chunk, -1);
s->m_callback = f;
Mix_RegisterEffect(s->m_channel, trampoline, nullptr, s);

return s->m_channel;
#else
UNUSED(f);
return -1;
#endif
}

void audio::stop_streaming(int channel)
{
#if defined LOL_USE_SDL_MIXER
for (int i = 0; i < g_streamers.count(); ++i)
{
if (g_streamers[i]->m_channel == channel)
{
Mix_HaltChannel(channel);
delete g_streamers[i];
g_streamers.remove(i);
return;
}
}
#else
UNUSED(false);
UNUSED(channel);
#endif
}



+ 4
- 1
src/lol/audio/audio.h ファイルの表示

@@ -18,7 +18,7 @@
// Helper functions to set up the audio device.
//

#include <stdint.h>
#include <functional>

namespace lol
{
@@ -33,6 +33,9 @@ public:
static void mute_all();
static void unmute_all();

static int start_streaming(std::function<void(void *, int)> const &f);
static void stop_streaming(int channel);

private:
audio() {}
};


読み込み中…
キャンセル
保存