Commit dc58ce6b authored by Matěj Toul's avatar Matěj Toul
Browse files

osi - audio: separated SDL audio logic into an osi submodule

parent 7652a2d2
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -7,7 +7,6 @@
#include <vector>
#include <cstdint>
#include <string>
#include <SDL2/SDL_audio.h>

namespace lfs { struct ResourceHandle; }

@@ -53,7 +52,6 @@ private:
    lfs::ResourceHandle* m_resource_handle;
    std::vector<float> m_audio_data;
    AudioDecoder* m_decoder;
    SDL_AudioSpec m_source_spec;
    std::uint32_t m_sample_rate;
    std::uint32_t m_channels;
    std::uint32_t m_playback_position;
+3 −5
Original line number Diff line number Diff line
@@ -2,8 +2,8 @@
#   define AUDIO_AUDIO_SYSTEM_HPP_INCLUDED

#include <com/library.hpp>
#include <osi/audio.hpp>
#include <cstdint>
#include <SDL2/SDL_audio.h>

namespace audio {

@@ -38,7 +38,6 @@ struct AudioSystem final : public com::Library

    std::uint32_t get_sample_rate() const { return m_sample_rate; }
    std::uint32_t get_channels() const { return m_channels; }
    SDL_AudioSpec const& get_audio_spec() const { return m_audio_spec; }

protected:
    void initialize() override;
@@ -50,15 +49,14 @@ private:
    AudioMixer* m_master_mixer;
    AudioProcessor* m_audio_processor;

    SDL_AudioDeviceID m_audio_device;
    SDL_AudioSpec m_audio_spec;
    osi::AudioDevice m_audio_device;
    
    std::uint32_t m_sample_rate;
    std::uint32_t m_channels;
    float m_master_volume;
    bool m_is_playing;

    // SDL callback wrapper
    // Callback wrapper to satisfy void* userdata format for audio
    friend void audio_callback(void* userdata, std::uint8_t* stream, int len);
    // concrete audio callback implementation
    void audio_callback_impl(std::uint8_t* stream, int len);
+5 −5
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#   define AUDIO_MP3_DECODER_HPP_INCLUDED

#include "audio_decoder.hpp"
#include <SDL2/SDL_audio.h>
#include <osi/audio.hpp>
#include <vector>
#include <cstdint>

@@ -18,7 +18,7 @@ namespace audio
    public:
        MP3Decoder(std::vector<std::uint8_t> const& mp3_data, 
                   std::uint32_t target_sample_rate, 
                   std::uint32_t target_channels);
                   std::uint8_t target_channels);
        
        ~MP3Decoder() override;

@@ -30,10 +30,10 @@ namespace audio
        std::vector<std::uint8_t> const& m_mp3_data;
        mp3dec_ex_t* m_dec;
        std::uint32_t m_target_sample_rate;
        std::uint32_t m_target_channels;
        std::uint8_t m_target_channels;
        std::uint32_t m_source_sample_rate;
        std::uint32_t m_source_channels;
        SDL_AudioStream* m_audio_stream;
        std::uint8_t m_source_channels;
        osi::AudioConverter m_converter;
        std::vector<float> m_decode_buffer;
        bool m_valid;
    };
+1 −1
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ namespace audio
            {
                if (!m_ring_buffer.push(sample))
                {
                    std::cerr << "Audio: audio buffer overrun, dropping samples" << std::endl;
					LOG(logging_severity_level::LSL_WARNING, "Audio: audio buffer overrun, dropping samples");
                    return; // Stop if we can't push anymore
                }
            }
+15 −108
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#include <audio/audio_system.hpp>
#include <audio/mp3_decoder.hpp>
#include <lfs/index.hpp>
#include <SDL2/SDL_audio.h>
#include <osi/audio.hpp>
#include <algorithm>
#include <cstring>
#include <iostream>
@@ -22,7 +22,6 @@ AudioSource::AudioSource(std::string const& name)
    , m_is_streaming(false)
    , m_volume(1.0f)
{
    SDL_zero(m_source_spec);
}

AudioSource::~AudioSource()
@@ -229,134 +228,42 @@ void AudioSource::decode_audio_data()
    }
    else
    {
        std::cerr << "Audio: Unknown audio file format" << std::endl;
		LOG(logging_severity_level::LSL_ERROR, "Audio: Unknown audio file format for file: " << m_resource_handle->name());
    }
}

bool AudioSource::load_wav_file(std::vector<std::uint8_t> const& file_data)
{
    SDL_RWops* rw = SDL_RWFromConstMem(file_data.data(), static_cast<int>(file_data.size()));
    if (rw == nullptr)
        return false;
    
    std::uint8_t* wav_buffer = nullptr;
    std::uint32_t wav_length = 0;
    
    if (SDL_LoadWAV_RW(rw, 1, &m_source_spec, &wav_buffer, &wav_length) == nullptr)
    {
        return false;
    }

    // TODO: unify this with audio system
    SDL_AudioSpec target_spec;
    SDL_zero(target_spec);
    target_spec.freq = 44100;
    target_spec.format = AUDIO_F32SYS;
    target_spec.channels = 2;
    
    SDL_AudioStream* stream = SDL_NewAudioStream(
        m_source_spec.format, m_source_spec.channels, m_source_spec.freq,
        target_spec.format, target_spec.channels, target_spec.freq
    );
    
    if (stream == nullptr)
    {
        SDL_FreeWAV(wav_buffer);
        return false;
    }
    
    // Convert audio data
    if (SDL_AudioStreamPut(stream, wav_buffer, wav_length) < 0)
    {
        SDL_FreeAudioStream(stream);
        SDL_FreeWAV(wav_buffer);
        return false;
    }
    
    SDL_AudioStreamFlush(stream);
    
    int available = SDL_AudioStreamAvailable(stream);
    if (available <= 0)
    {
        SDL_FreeAudioStream(stream);
        SDL_FreeWAV(wav_buffer);
        return false;
    }

    m_audio_data.resize(available / sizeof(float));
    SDL_AudioStreamGet(stream, m_audio_data.data(), available);
    // Use OSI audio loader to load and convert WAV file
    osi::WavData wav_data = osi::AudioLoader::load_wav(
        file_data, 44100, 2, osi::AudioFormat::Float32);
    
    m_sample_rate = target_spec.freq;
    m_channels = target_spec.channels;
    m_audio_data = std::move(wav_data.samples);
    m_sample_rate = wav_data.sample_rate;
    m_channels = wav_data.channels;
    m_total_samples = static_cast<std::uint32_t>(m_audio_data.size());
    
    SDL_FreeAudioStream(stream);
    SDL_FreeWAV(wav_buffer);
    
    return true;
}

bool AudioSource::load_mp3_file(std::vector<std::uint8_t> const& file_data)
{
    // Size threshold: files under 1MB are fully decoded, larger files are streamed
    constexpr std::uint32_t DECODE_THRESHOLD_BYTES = 1024 * 1024;
    bool should_stream = file_data.size() > DECODE_THRESHOLD_BYTES;

    MP3Decoder* mp3_decoder = new MP3Decoder(m_resource_handle->data(), 44100, 2);

    if (!mp3_decoder->is_valid())
    {
        delete mp3_decoder;
        std::cerr << "Audio: Failed to create MP3 decoder" << std::endl;
        LOG(logging_severity_level::LSL_ERROR, "Audio: Failed to create MP3 decoder for file: " << m_resource_handle->name());
        return false;
    }

    if (should_stream)
    {
    m_decoder = mp3_decoder;
    m_sample_rate = 44100;
    m_channels = 2;
    m_total_samples = 0;
    m_is_streaming = true;

        std::cout << "Audio: Loaded MP3 file for streaming (" << file_data.size() / 1024 << " KB)" << std::endl;
    return true;
}
    else
    {
        // Decode entire file to memory using the decoder
        // Estimate size: assume ~10:1 compression ratio for MP3
        std::size_t estimated_samples = file_data.size() * 10 / sizeof(float);
        m_audio_data.reserve(estimated_samples);
        
        constexpr std::uint32_t CHUNK_FRAMES = 4096;
        std::vector<float> decode_buffer(CHUNK_FRAMES * 2);
        
        std::uint32_t frames_decoded;
        do
        {
            frames_decoded = mp3_decoder->decode(decode_buffer.data(), CHUNK_FRAMES);
            if (frames_decoded > 0)
            {
                std::uint32_t samples_decoded = frames_decoded * 2;
                m_audio_data.insert(m_audio_data.end(), 
                                   decode_buffer.begin(), 
                                   decode_buffer.begin() + samples_decoded);
            }
        } while (frames_decoded == CHUNK_FRAMES);

        delete mp3_decoder;
        m_resource_handle->set_discardable(true);

        m_sample_rate = 44100;
        m_channels = 2;
        m_total_samples = static_cast<std::uint32_t>(m_audio_data.size());
        m_is_streaming = false;

        std::cout << "Audio: Loaded MP3 file fully decoded (" << file_data.size() / 1024 
                  << " KB -> " << m_audio_data.size() * sizeof(float) / 1024 << " KB PCM)" << std::endl;
        return true;
    }
}

}
Loading