mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-21 01:19:18 +02:00
audio subsystem replacement: openal audio renderer and buffer class, removed deprecated files
This commit is contained in:
181
audio.cpp
Normal file
181
audio.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "audio.h"
|
||||
#include "globals.h"
|
||||
#include "mczapkie/mctools.h"
|
||||
|
||||
#define DR_WAV_IMPLEMENTATION
|
||||
#include "dr_wav.h"
|
||||
#define DR_FLAC_IMPLEMENTATION
|
||||
#include "dr_flac.h"
|
||||
|
||||
namespace audio {
|
||||
|
||||
openal_buffer::openal_buffer( std::string const &Filename ) :
|
||||
name( Filename ) {
|
||||
|
||||
::alGenBuffers( 1, &id );
|
||||
// fetch audio data
|
||||
if( Filename.substr( Filename.rfind( '.' ) ) == ".wav" ) {
|
||||
// .wav file
|
||||
auto *file { drwav_open_file( Filename.c_str() ) };
|
||||
rate = file->sampleRate;
|
||||
auto const samplecount { static_cast<std::size_t>( file->totalSampleCount ) };
|
||||
data.resize( samplecount );
|
||||
drwav_read_s16(
|
||||
file,
|
||||
samplecount,
|
||||
&data[ 0 ] );
|
||||
if( file->channels > 1 ) {
|
||||
narrow_to_mono( file->channels );
|
||||
data.resize( samplecount / file->channels );
|
||||
}
|
||||
// we're done with the disk data
|
||||
drwav_close( file );
|
||||
}
|
||||
else {
|
||||
// .flac or .ogg file
|
||||
auto *file { drflac_open_file( Filename.c_str() ) };
|
||||
rate = file->sampleRate;
|
||||
auto const samplecount{ static_cast<std::size_t>( file->totalSampleCount ) };
|
||||
data.resize( samplecount );
|
||||
drflac_read_s16(
|
||||
file,
|
||||
samplecount,
|
||||
&data[ 0 ] );
|
||||
if( file->channels > 1 ) {
|
||||
narrow_to_mono( file->channels );
|
||||
data.resize( samplecount / file->channels );
|
||||
}
|
||||
// we're done with the disk data
|
||||
drflac_close( file );
|
||||
}
|
||||
// send the data to openal side
|
||||
::alBufferData( id, AL_FORMAT_MONO16, data.data(), data.size() * sizeof( std::int16_t ), rate );
|
||||
// and get rid of the source, we shouldn't need it anymore
|
||||
// TBD, TODO: delay data fetching and transfers until the buffer is actually used?
|
||||
std::vector<std::int16_t>().swap( data );
|
||||
}
|
||||
|
||||
// mix specified number of interleaved multi-channel data, down to mono
|
||||
void
|
||||
openal_buffer::narrow_to_mono( std::uint16_t const Channelcount ) {
|
||||
|
||||
std::size_t monodataindex { 0 };
|
||||
std::int32_t accumulator { 0 };
|
||||
auto channelcount { Channelcount };
|
||||
|
||||
for( auto const channeldata : data ) {
|
||||
|
||||
accumulator += channeldata;
|
||||
if( --channelcount == 0 ) {
|
||||
|
||||
data[ monodataindex++ ] = accumulator / Channelcount;
|
||||
accumulator = 0;
|
||||
channelcount = Channelcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
buffer_manager::~buffer_manager() {
|
||||
|
||||
for( auto &buffer : m_buffers ) {
|
||||
if( buffer.id != null_resource ) {
|
||||
::alDeleteBuffers( 1, &( buffer.id ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// creates buffer object out of data stored in specified file. returns: handle to the buffer or null_handle if creation failed
|
||||
buffer_handle
|
||||
buffer_manager::create( std::string const &Filename ) {
|
||||
|
||||
auto filename { ToLower( Filename ) };
|
||||
|
||||
auto const dotpos { filename.rfind( '.' ) };
|
||||
if( ( dotpos != std::string::npos )
|
||||
&& ( dotpos != filename.rfind( ".." ) + 1 ) ) {
|
||||
// trim extension if there's one, but don't mistake folder traverse for extension
|
||||
filename.erase( dotpos );
|
||||
}
|
||||
// convert slashes
|
||||
std::replace(
|
||||
std::begin( filename ), std::end( filename ),
|
||||
'\\', '/' );
|
||||
|
||||
// try dynamic-specific sounds first
|
||||
auto lookup { find_buffer( Global::asCurrentDynamicPath + filename ) };
|
||||
if( lookup != null_handle ) {
|
||||
return lookup;
|
||||
}
|
||||
std::string filelookup { find_file( Global::asCurrentDynamicPath + filename ) };
|
||||
if( false == filelookup.empty() ) {
|
||||
return emplace( filelookup );
|
||||
}
|
||||
// if dynamic-specific lookup finds nothing, try the default sound folder
|
||||
lookup = find_buffer( szSoundPath + filename );
|
||||
if( lookup != null_handle ) {
|
||||
return lookup;
|
||||
}
|
||||
filelookup = find_file( szSoundPath + filename );
|
||||
if( false == filelookup.empty() ) {
|
||||
return emplace( filelookup );
|
||||
}
|
||||
// if we still didn't find anything, give up
|
||||
return null_handle;
|
||||
}
|
||||
|
||||
// places in the bank a buffer containing data stored in specified file. returns: handle to the buffer
|
||||
buffer_handle
|
||||
buffer_manager::emplace( std::string Filename ) {
|
||||
|
||||
buffer_handle const handle { m_buffers.size() };
|
||||
m_buffers.emplace_back( Filename );
|
||||
|
||||
// NOTE: we store mapping without file type extension, to simplify lookups
|
||||
m_buffermappings.emplace(
|
||||
Filename.erase( Filename.rfind( '.' ) ),
|
||||
handle );
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
buffer_handle
|
||||
buffer_manager::find_buffer( std::string const &Buffername ) const {
|
||||
|
||||
auto lookup = m_buffermappings.find( Buffername );
|
||||
if( lookup != m_buffermappings.end() )
|
||||
return lookup->second;
|
||||
else
|
||||
return null_handle;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
buffer_manager::find_file( std::string const &Filename ) const {
|
||||
|
||||
std::vector<std::string> const extensions { ".wav", ".flac", ".ogg" };
|
||||
|
||||
for( auto const &extension : extensions ) {
|
||||
if( FileExists( Filename + extension ) ) {
|
||||
// valid name on success
|
||||
return Filename + extension;
|
||||
}
|
||||
}
|
||||
return {}; // empty string on failure
|
||||
}
|
||||
|
||||
} // audio
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user