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))
end
local stream
function on_hud_open()
input.add_callback("player.pick", function ()
if hud.is_paused() or hud.is_inventory_open() then
@ -117,16 +119,16 @@ function on_hud_open()
hud.default_hand_controller = update_hand
local stream = PCMStream(44100, 1, 8)
stream = PCMStream(44100, 1, 16)
stream:share("test-stream")
local bytes = Bytearray(44100 * 16)
local bytes = Bytearray(44100 / 8)
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
end
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
function on_hud_render()
@ -135,4 +137,7 @@ function on_hud_render()
else
update_hand()
end
local bytes = audio.fetch_input()
stream:feed(bytes)
end

View File

@ -5,11 +5,40 @@
#include "debug/Logger.hpp"
#include "alutil.hpp"
#include "../MemoryPCMStream.hpp"
static debug::Logger logger("al-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(
ALAudio* al, uint buffer, const std::shared_ptr<PCM>& pcm, bool keepPCM
)
@ -45,14 +74,17 @@ ALInputDevice::ALInputDevice(
ALInputDevice::~ALInputDevice() {
alcCaptureCloseDevice(device);
check_alc_errors(device, "alcCaptureCloseDevice");
}
void ALInputDevice::startCapture() {
AL_CHECK(alcCaptureStart(device));
alcCaptureStart(device);
check_alc_errors(device, "alcCaptureStart");
}
void ALInputDevice::stopCapture() {
AL_CHECK(alcCaptureStop(device));
alcCaptureStop(device);
check_alc_errors(device, "alcCaptureStop");
}
uint ALInputDevice::getChannels() const {
@ -60,13 +92,15 @@ uint ALInputDevice::getChannels() const {
}
size_t ALInputDevice::read(char* buffer, size_t bufferSize) {
ALCint samplesCount;
AL_CHECK(alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &samplesCount));
ALCint samplesCount = 0;
alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, sizeof(samplesCount), &samplesCount);
check_alc_errors(device, "alcGetIntegerv(ALC_CAPTURE_SAMPLES)");
size_t samplesRead = std::min<ALCsizei>(
samplesCount, bufferSize / channels / (bitsPerSample >> 3)
);
AL_CHECK(alcCaptureSamples(device, buffer, samplesRead));
return samplesRead;
alcCaptureSamples(device, buffer, samplesRead);
check_alc_errors(device, "alcCaptureSamples");
return samplesRead * channels * (bitsPerSample >> 3);
}
ALStream::ALStream(
@ -195,7 +229,7 @@ void ALStream::update(double delta) {
// alspeaker->stopped is assigned to false at ALSpeaker::play(...)
if (p_speaker->isStopped() && !alspeaker->stopped) { //TODO: -V560 false-positive?
if (preloaded) {
if (preloaded || dynamic_cast<MemoryPCMStream*>(source.get())) {
p_speaker->play();
} else {
p_speaker->stop();
@ -417,8 +451,10 @@ ALAudio::~ALAudio() {
AL_CHECK(alDeleteBuffers(1, &buffer));
}
AL_CHECK(alcMakeContextCurrent(context));
alcMakeContextCurrent(nullptr);
check_alc_errors(device, "alcMakeContextCurrent");
alcDestroyContext(context);
check_alc_errors(device, "alcDestroyContext");
if (!alcCloseDevice(device)) {
logger.error() << "device not closed!";
}
@ -447,15 +483,16 @@ std::unique_ptr<InputDevice> ALAudio::openInputDevice(
uint sampleRate, uint channels, uint bitsPerSample
) {
uint bps = bitsPerSample >> 3;
AL_CHECK(
ALCdevice* device = alcCaptureOpenDevice(
nullptr,
sampleRate,
AL::to_al_format(channels, bps),
sampleRate * channels * bps
)
ALCdevice* device = alcCaptureOpenDevice(
nullptr,
sampleRate,
AL::to_al_format(channels, bitsPerSample),
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() {

View File

@ -151,6 +151,8 @@ public:
}
};
static std::unique_ptr<InputDevice> input_device = nullptr;
void audio::initialize(bool enabled, AudioSettings& settings) {
enabled = enabled && settings.enabled.get();
if (enabled) {
@ -180,6 +182,13 @@ void audio::initialize(bool enabled, AudioSettings& settings) {
audio::get_channel(channel.name)->setVolume(value * value);
}, 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) {
@ -458,6 +467,7 @@ void audio::reset_channel(int index) {
}
void audio::close() {
input_device->stopCapture();
speakers.clear();
delete backend;
backend = nullptr;

View File

@ -24,6 +24,8 @@ namespace audio {
/// @brief streams and important sounds
constexpr inline int PRIORITY_HIGH = 10;
constexpr inline size_t MAX_INPUT_SAMPLES = 22050;
class Speaker;
/// @brief Audio speaker states
@ -423,6 +425,15 @@ namespace audio {
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
/// @param position listener position
/// @param velocity listener velocity (used for Doppler effect)
@ -536,6 +547,8 @@ namespace audio {
/// @brief Stop all playing audio in channel, reset channel state
void reset_channel(int channel);
InputDevice* get_input_device();
/// @brief Finalize audio system
void close();
};

View File

@ -379,16 +379,35 @@ static int l_audio_get_velocity(lua::State* L) {
return 0;
}
// @brief audio.count_speakers() -> integer
/// @brief audio.count_speakers() -> integer
static int l_audio_count_speakers(lua::State* L) {
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) {
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[] = {
{"play_sound", lua::wrap<l_audio_play_sound>},
{"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>},
{"count_speakers", lua::wrap<l_audio_count_speakers>},
{"count_streams", lua::wrap<l_audio_count_streams>},
{"fetch_input", lua::wrap<l_audio_fetch_input>},
{nullptr, nullptr}
};

View File

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