add test audio input fetch function

This commit is contained in:
MihailRis 2025-10-15 22:13:16 +03:00
parent cc8e763f97
commit 7dca9255df
6 changed files with 107 additions and 25 deletions

View File

@ -55,6 +55,8 @@ local function update_hand()
skeleton.set_model("hand", bone, item.model_name(itemid)) skeleton.set_model("hand", bone, item.model_name(itemid))
end end
local stream
function on_hud_open() function on_hud_open()
input.add_callback("player.pick", function () input.add_callback("player.pick", function ()
if hud.is_paused() or hud.is_inventory_open() then if hud.is_paused() or hud.is_inventory_open() then
@ -117,16 +119,16 @@ function on_hud_open()
hud.default_hand_controller = update_hand hud.default_hand_controller = update_hand
local stream = PCMStream(44100, 1, 8) stream = PCMStream(44100, 1, 16)
stream:share("test-stream") stream:share("test-stream")
local bytes = Bytearray(44100 * 16) local bytes = Bytearray(44100 / 8)
for i=1,#bytes do for i=1,#bytes do
local x = math.sin(i * 0.08) * 127 + 128 local x = math.sin(i * 0.08) * 1 + 0
bytes[i] = x bytes[i] = x
end end
stream:feed(bytes) stream:feed(bytes)
audio.play_stream_2d("test-stream", 0.05, 1.0) audio.play_stream_2d("test-stream", 2.0, 1.0, "ui")
end end
function on_hud_render() function on_hud_render()
@ -135,4 +137,7 @@ function on_hud_render()
else else
update_hand() update_hand()
end end
local bytes = audio.fetch_input()
stream:feed(bytes)
end end

View File

@ -5,11 +5,40 @@
#include "debug/Logger.hpp" #include "debug/Logger.hpp"
#include "alutil.hpp" #include "alutil.hpp"
#include "../MemoryPCMStream.hpp"
static debug::Logger logger("al-audio"); static debug::Logger logger("al-audio");
using namespace audio; using namespace audio;
const char* alc_error_to_string(ALCenum error) {
switch (error) {
case ALC_NO_ERROR:
return "no error";
case ALC_INVALID_DEVICE:
return "invalid device handle";
case ALC_INVALID_CONTEXT:
return "invalid context handle";
case ALC_INVALID_ENUM:
return "invalid enum parameter passed to an ALC call";
case ALC_INVALID_VALUE:
return "invalid value parameter passed to an ALC call";
case ALC_OUT_OF_MEMORY:
return "out of memory";
default:
return "unknown ALC error";
}
}
static void check_alc_errors(ALCdevice* device, const char* context) {
ALCenum error = alcGetError(device);
if (error == ALC_NO_ERROR) {
return;
}
logger.error() << context << ": " << alc_error_to_string(error) << "("
<< error << ")";
}
ALSound::ALSound( ALSound::ALSound(
ALAudio* al, uint buffer, const std::shared_ptr<PCM>& pcm, bool keepPCM ALAudio* al, uint buffer, const std::shared_ptr<PCM>& pcm, bool keepPCM
) )
@ -45,14 +74,17 @@ ALInputDevice::ALInputDevice(
ALInputDevice::~ALInputDevice() { ALInputDevice::~ALInputDevice() {
alcCaptureCloseDevice(device); alcCaptureCloseDevice(device);
check_alc_errors(device, "alcCaptureCloseDevice");
} }
void ALInputDevice::startCapture() { void ALInputDevice::startCapture() {
AL_CHECK(alcCaptureStart(device)); alcCaptureStart(device);
check_alc_errors(device, "alcCaptureStart");
} }
void ALInputDevice::stopCapture() { void ALInputDevice::stopCapture() {
AL_CHECK(alcCaptureStop(device)); alcCaptureStop(device);
check_alc_errors(device, "alcCaptureStop");
} }
uint ALInputDevice::getChannels() const { uint ALInputDevice::getChannels() const {
@ -60,13 +92,15 @@ uint ALInputDevice::getChannels() const {
} }
size_t ALInputDevice::read(char* buffer, size_t bufferSize) { size_t ALInputDevice::read(char* buffer, size_t bufferSize) {
ALCint samplesCount; ALCint samplesCount = 0;
AL_CHECK(alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &samplesCount)); alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, sizeof(samplesCount), &samplesCount);
check_alc_errors(device, "alcGetIntegerv(ALC_CAPTURE_SAMPLES)");
size_t samplesRead = std::min<ALCsizei>( size_t samplesRead = std::min<ALCsizei>(
samplesCount, bufferSize / channels / (bitsPerSample >> 3) samplesCount, bufferSize / channels / (bitsPerSample >> 3)
); );
AL_CHECK(alcCaptureSamples(device, buffer, samplesRead)); alcCaptureSamples(device, buffer, samplesRead);
return samplesRead; check_alc_errors(device, "alcCaptureSamples");
return samplesRead * channels * (bitsPerSample >> 3);
} }
ALStream::ALStream( ALStream::ALStream(
@ -195,7 +229,7 @@ void ALStream::update(double delta) {
// alspeaker->stopped is assigned to false at ALSpeaker::play(...) // alspeaker->stopped is assigned to false at ALSpeaker::play(...)
if (p_speaker->isStopped() && !alspeaker->stopped) { //TODO: -V560 false-positive? if (p_speaker->isStopped() && !alspeaker->stopped) { //TODO: -V560 false-positive?
if (preloaded) { if (preloaded || dynamic_cast<MemoryPCMStream*>(source.get())) {
p_speaker->play(); p_speaker->play();
} else { } else {
p_speaker->stop(); p_speaker->stop();
@ -417,8 +451,10 @@ ALAudio::~ALAudio() {
AL_CHECK(alDeleteBuffers(1, &buffer)); AL_CHECK(alDeleteBuffers(1, &buffer));
} }
AL_CHECK(alcMakeContextCurrent(context)); alcMakeContextCurrent(nullptr);
check_alc_errors(device, "alcMakeContextCurrent");
alcDestroyContext(context); alcDestroyContext(context);
check_alc_errors(device, "alcDestroyContext");
if (!alcCloseDevice(device)) { if (!alcCloseDevice(device)) {
logger.error() << "device not closed!"; logger.error() << "device not closed!";
} }
@ -447,15 +483,16 @@ std::unique_ptr<InputDevice> ALAudio::openInputDevice(
uint sampleRate, uint channels, uint bitsPerSample uint sampleRate, uint channels, uint bitsPerSample
) { ) {
uint bps = bitsPerSample >> 3; uint bps = bitsPerSample >> 3;
AL_CHECK(
ALCdevice* device = alcCaptureOpenDevice( ALCdevice* device = alcCaptureOpenDevice(
nullptr, nullptr,
sampleRate, sampleRate,
AL::to_al_format(channels, bps), AL::to_al_format(channels, bitsPerSample),
sampleRate * channels * bps sampleRate * channels * bps / 8
) );
check_alc_errors(device, "alcCaptureOpenDevice");
return std::make_unique<ALInputDevice>(
this, device, channels, bitsPerSample
); );
return std::make_unique<ALInputDevice>(this, device, channels, bps);
} }
std::unique_ptr<ALAudio> ALAudio::create() { std::unique_ptr<ALAudio> ALAudio::create() {

View File

@ -151,6 +151,8 @@ public:
} }
}; };
static std::unique_ptr<InputDevice> input_device = nullptr;
void audio::initialize(bool enabled, AudioSettings& settings) { void audio::initialize(bool enabled, AudioSettings& settings) {
enabled = enabled && settings.enabled.get(); enabled = enabled && settings.enabled.get();
if (enabled) { if (enabled) {
@ -180,6 +182,13 @@ void audio::initialize(bool enabled, AudioSettings& settings) {
audio::get_channel(channel.name)->setVolume(value * value); audio::get_channel(channel.name)->setVolume(value * value);
}, true)); }, true));
} }
input_device = backend->openInputDevice(44100, 1, 16);
input_device->startCapture();
}
InputDevice* audio::get_input_device() {
return input_device.get();
} }
std::unique_ptr<PCM> audio::load_PCM(const io::path& file, bool headerOnly) { std::unique_ptr<PCM> audio::load_PCM(const io::path& file, bool headerOnly) {
@ -458,6 +467,7 @@ void audio::reset_channel(int index) {
} }
void audio::close() { void audio::close() {
input_device->stopCapture();
speakers.clear(); speakers.clear();
delete backend; delete backend;
backend = nullptr; backend = nullptr;

View File

@ -24,6 +24,8 @@ namespace audio {
/// @brief streams and important sounds /// @brief streams and important sounds
constexpr inline int PRIORITY_HIGH = 10; constexpr inline int PRIORITY_HIGH = 10;
constexpr inline size_t MAX_INPUT_SAMPLES = 22050;
class Speaker; class Speaker;
/// @brief Audio speaker states /// @brief Audio speaker states
@ -423,6 +425,15 @@ namespace audio {
std::shared_ptr<PCMStream> stream, bool keepSource std::shared_ptr<PCMStream> stream, bool keepSource
); );
/// @brief Open audio input device
/// @param sampleRate sample rate
/// @param channels channels count (1 - mono, 2 - stereo)
/// @param bitsPerSample number of bits per sample (8 or 16)
/// @return new InputDevice instance or nullptr
std::unique_ptr<InputDevice> open_input_device(
uint sampleRate, uint channels, uint bitsPerSample
);
/// @brief Configure 3D listener /// @brief Configure 3D listener
/// @param position listener position /// @param position listener position
/// @param velocity listener velocity (used for Doppler effect) /// @param velocity listener velocity (used for Doppler effect)
@ -536,6 +547,8 @@ namespace audio {
/// @brief Stop all playing audio in channel, reset channel state /// @brief Stop all playing audio in channel, reset channel state
void reset_channel(int channel); void reset_channel(int channel);
InputDevice* get_input_device();
/// @brief Finalize audio system /// @brief Finalize audio system
void close(); void close();
}; };

View File

@ -379,16 +379,35 @@ static int l_audio_get_velocity(lua::State* L) {
return 0; return 0;
} }
// @brief audio.count_speakers() -> integer /// @brief audio.count_speakers() -> integer
static int l_audio_count_speakers(lua::State* L) { static int l_audio_count_speakers(lua::State* L) {
return lua::pushinteger(L, audio::count_speakers()); return lua::pushinteger(L, audio::count_speakers());
} }
// @brief audio.count_streams() -> integer /// @brief audio.count_streams() -> integer
static int l_audio_count_streams(lua::State* L) { static int l_audio_count_streams(lua::State* L) {
return lua::pushinteger(L, audio::count_streams()); return lua::pushinteger(L, audio::count_streams());
} }
/// @brief audio.fetch_input(size) -> Bytearray
static int l_audio_fetch_input(lua::State* L) {
auto device = audio::get_input_device();
if (device == nullptr) {
return 0;
}
size_t size = lua::touinteger(L, 1);
const size_t MAX_BUFFER_SIZE = audio::MAX_INPUT_SAMPLES * 4;
if (size == 0) {
size = MAX_BUFFER_SIZE;
}
size = std::min<size_t>(size, MAX_BUFFER_SIZE);
ubyte buffer[MAX_BUFFER_SIZE];
size = device->read(reinterpret_cast<char*>(buffer), size);
std::vector<ubyte> bytes(buffer, buffer + size);
return lua::create_bytearray(L, std::move(bytes));
}
const luaL_Reg audiolib[] = { const luaL_Reg audiolib[] = {
{"play_sound", lua::wrap<l_audio_play_sound>}, {"play_sound", lua::wrap<l_audio_play_sound>},
{"play_sound_2d", lua::wrap<l_audio_play_sound_2d>}, {"play_sound_2d", lua::wrap<l_audio_play_sound_2d>},
@ -414,5 +433,6 @@ const luaL_Reg audiolib[] = {
{"get_velocity", lua::wrap<l_audio_get_velocity>}, {"get_velocity", lua::wrap<l_audio_get_velocity>},
{"count_speakers", lua::wrap<l_audio_count_speakers>}, {"count_speakers", lua::wrap<l_audio_count_speakers>},
{"count_streams", lua::wrap<l_audio_count_streams>}, {"count_streams", lua::wrap<l_audio_count_streams>},
{"fetch_input", lua::wrap<l_audio_fetch_input>},
{nullptr, nullptr} {nullptr, nullptr}
}; };

View File

@ -18,10 +18,7 @@ const std::shared_ptr<audio::MemoryPCMStream>& LuaPCMStream::getStream() const {
return stream; return stream;
} }
#include <iostream>
static int l_feed(lua::State* L) { static int l_feed(lua::State* L) {
std::cout << "feed" << std::endl;
auto stream = touserdata<LuaPCMStream>(L, 1); auto stream = touserdata<LuaPCMStream>(L, 1);
if (stream == nullptr) { if (stream == nullptr) {
return 0; return 0;