// Copyright (C) 2012-2015 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of Nova libraries. // For conditions of distribution and use, see copying.txt file in root folder. #include "nv/sdl/sdl_audio.hh" #include "nv/stl/math.hh" #include "nv/lib/sdl_mixer.hh" #include "nv/core/logging.hh" using namespace nv; sdl::audio::audio() { nv::load_sdl_library(); nv::load_sdl_mixer_library(); if ( SDL_Init( SDL_INIT_AUDIO ) == -1 ) { NV_LOG_CRITICAL( "SDL_AUDIO failed to load -- ", SDL_GetError() ); return; } if( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, 1024 ) == -1 ) { NV_LOG_CRITICAL( "SDL_mixer failed to load -- ", Mix_GetError() ); return; } } nv::channel nv::sdl::audio::play_sound( sound a_sound, float volume, float pan /*= 0.0f */ ) { sound_info* info = m_sounds.get( a_sound ); if ( info ) { int channel = Mix_PlayChannel(-1, static_cast( info->sdl_sound ), 0); if ( channel == -1 ) { NV_LOG_WARNING( "SDL_mixer failed to play -- ", Mix_GetError() ); } else { Mix_Volume( channel, static_cast( volume * 128.0f ) ); if ( pan != 0.0f) { uint8 right = static_cast( (pan + 1.0f) * 127.0f ); Mix_SetPanning( channel, 254-right, right ); } else { Mix_SetPanning( channel, 255, 255 ); } } } return channel(); } nv::channel nv::sdl::audio::play_sound( sound a_sound, vec3 position ) { sound_info* info = m_sounds.get( a_sound ); if ( info ) { int channel = Mix_PlayChannel(-1, static_cast( info->sdl_sound ), 0); if ( channel == -1 ) { NV_LOG_WARNING( "SDL_mixer failed to play -- ", Mix_GetError() ); } else { vec3 relative = position - m_position; float angle = 0; float distance = 0; if ( relative != vec3() ) { angle = math::degrees( -glm::orientedAngle( m_forward, glm::normalize( relative ), m_up ) ); distance = glm::clamp( 20.0f * glm::length( relative ), 0.0f, 255.0f ); } if ( angle < 0.0f ) angle += 360.0f; Mix_SetPosition( channel, sint16(angle), uint8(distance) ); } } return channel(); } nv::sound nv::sdl::audio::load_sound( const string_view& a_path ) { // TODO: this is a really weird error - if we remove this check, all hell gets loose if ( Mix_LoadWAV_RW == nullptr || SDL_RWFromFile == nullptr ) { NV_LOG_ERROR( "SDL_mixer not loaded!" ); } Mix_Chunk *sample = Mix_LoadWAV_RW(SDL_RWFromFile(a_path.data(), "rb"), 1); if ( sample == nullptr ) { NV_LOG_ERROR( "SDL_mixer failed to load sample '", a_path, "' -- ", Mix_GetError() ); return sound(); } sound result = m_sounds.create(); sound_info* info = m_sounds.get( result ); info->sdl_sound = sample; return result; } void nv::sdl::audio::update( vec3 position ) { m_position = position; } nv::sdl::audio::~audio() { while ( m_sounds.size() > 0 ) release( m_sounds.get_handle(0) ); Mix_CloseAudio(); // TODO: should we do it here? SDL_Quit(); } void nv::sdl::audio::release( sound a_sound ) { sound_info* info = m_sounds.get( a_sound ); if ( info ) { Mix_FreeChunk( static_cast( info->sdl_sound ) ); m_sounds.destroy( a_sound ); } } void nv::sdl::audio::set_orientation( vec3 forward, vec3 up ) { m_forward = forward; m_up = up; }