Kaynağa Gözat

audio: start migrating to the new streaming API

main
Sam Hocevar 2 yıl önce
ebeveyn
işleme
b632fa370b
3 değiştirilmiş dosya ile 48 ekleme ve 80 silme
  1. +1
    -1
      lol
  2. +33
    -59
      src/audio/audio.cpp
  3. +14
    -20
      src/include/lol/engine/private/audio/audio.h

+ 1
- 1
lol

@@ -1 +1 @@
Subproject commit b5f006511e853340e49c3757b71f752df591579e
Subproject commit 4db95f5728ed4505e73ec35bbe9a7e97684aa915

+ 33
- 59
src/audio/audio.cpp Dosyayı Görüntüle

@@ -1,7 +1,7 @@
//
// Lol Engine
//
// Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net>
// Copyright © 2010–2024 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
@@ -16,11 +16,11 @@
#include <lol/msg>
#include <memory>
#include <unordered_map>
#include <unordered_set>

#if LOL_USE_KINC
# include <kinc/audio2/audio.h>
#elif LOL_USE_SDL_MIXER
# include <unordered_set>
# if HAVE_SDL2_SDL_H
# include <SDL2/SDL.h>
# include <SDL2/SDL_mixer.h>
@@ -35,56 +35,33 @@
namespace lol::audio
{

struct streamer
{
std::function<void(void *, size_t)> callback;
format format;
int frequency;
int channels;
};

std::unordered_map<int, std::shared_ptr<streamer>> g_streamers;
std::shared_ptr<mixer<float>> g_mixer;

static void play_audio(kinc_a2_buffer_t *buffer, size_t samples)
{
size_t const out_rate = buffer->format.samples_per_second;
size_t const out_channels = buffer->format.channels;
size_t const out_frames = samples / out_channels;
size_t const in_rate = 22050;
size_t const in_frames = out_frames * in_rate / out_rate + 1;

// Mix all channels into a float buffer
std::vector<float> z8_buffer(in_frames + 1);
std::vector<int16_t> tmp(in_frames);
for (auto &s : g_streamers)
{
s.second->callback(tmp.data(), in_frames);
for (size_t i = 0; i < in_frames; ++i)
z8_buffer[i] += tmp[i] / 32767.f;
}

for (size_t i = 0; i < out_frames; ++i)
{
auto frame = (float *)(buffer->data + buffer->write_location);
// Linear interpolation
float s0 = z8_buffer[i * in_rate / out_rate];
float s1 = z8_buffer[i * in_rate / out_rate + 1];
float s = s0 + (s1 - s0) * float(i * in_rate % out_rate) / out_rate;
// clip so that we never go outside -1..1 range
s = std::max(-1.0f, std::min(1.0f, s));
// Output frame samples
for (size_t ch = 0; ch < out_channels; ++ch)
frame[ch] = s;
buffer->write_location = (buffer->write_location + out_channels * sizeof(*frame)) % buffer->data_size;
}
}
// FIXME: this could be removed by inserting this in g_mixer
std::unordered_map<int, std::shared_ptr<stream<float>>> g_streams;

void init()
{
g_mixer = std::make_shared<mixer<float>>(2, 48000);

kinc_a2_init();
kinc_a2_set_callback([](kinc_a2_buffer_t *buffer, int samples, void *userdata)
{
play_audio(buffer, size_t(samples));
size_t const frame_size = 2 * sizeof(float);
size_t todo = size_t(samples) / 2;
size_t remaining = (buffer->data_size - buffer->write_location) / frame_size;

if (todo >= remaining)
{
todo -= g_mixer->get(reinterpret_cast<float *>(buffer->data + buffer->write_location), remaining);
buffer->write_location = 0;
}

if (todo > 0)
{
g_mixer->get(reinterpret_cast<float *>(buffer->data + buffer->write_location), todo);
buffer->write_location += int(todo * frame_size);
}
}, nullptr);
}

@@ -93,23 +70,20 @@ void shutdown()
kinc_a2_set_callback(nullptr, nullptr);
}

int start(std::function<void(void *, size_t)> f,
format format, int frequency, int channels)
template<>
int start_stream(std::shared_ptr<stream<float>> s)
{
auto s = std::make_shared<streamer>();
s->callback = f;
s->format = format;
s->frequency = frequency;
s->channels = channels;

static int idx = 0;
g_streamers[idx] = s;
g_streams[idx] = s;
g_mixer->add(s);
return idx++;
}

void stop(int stream)
void stop_stream(int id)
{
g_streamers.erase(stream);
auto s = g_streams[id];
g_streams.erase(id);
g_mixer->remove(s);
}

} // namespace lol::audio
@@ -308,12 +282,12 @@ int audio::start_streaming(std::function<void(void *, int)> const &f,

void audio::stop_streaming(int track)
{
for (auto streamer : g_streamers)
for (auto s : g_streamers)
{
if (streamer->m_track == track)
if (s->m_track == track)
{
Mix_HaltChannel(track);
g_streamers.erase(streamer);
g_streamers.erase(s);
break;
}
}


+ 14
- 20
src/include/lol/engine/private/audio/audio.h Dosyayı Görüntüle

@@ -14,36 +14,30 @@

//
// The audio interface
// -------------------
// ———————————————————
// Helper functions to set up the audio device.
//

#include <functional>
#include <lol/audio/stream>
#include <unordered_map>

namespace lol::audio
{

enum class format : uint8_t
{
unknown = 0,
// 8-bit, unsigned or signed
uint8, sint8,
// 16-bit, unsigned or signed, little endian or big endian
uint16le, uint16be,
sint16le, sint16be,
// 24-bit signed, little endian
sint24le,
// 32-bit signed, little endian or big endian
sint32le, sint32be,
// 32-bit floats, little endian or big endian
float32le, float32be,
};

void init();
void shutdown();

int start(std::function<void(void *, size_t)> f,
format format, int frequency, int channels);
void stop(int stream);
template<typename S, typename T = S::sample_type>
inline int start_stream(std::shared_ptr<S> s0)
{
std::shared_ptr<stream<float>> s = make_adapter<float>(s0, 2, 48000);
return start_stream(s);
}

template<>
int start_stream(std::shared_ptr<stream<float>> stream);

void stop_stream(int id);

} // namespace lol

Yükleniyor…
İptal
Kaydet