Browse Source

Support MP3 playback

pull/4373/head
Gleb Mazovetskiy 4 years ago committed by Anders Jenbo
parent
commit
5645456537
  1. 2
      3rdParty/SDL_audiolib/CMakeLists.txt
  2. 51
      Source/sound.cpp
  3. 37
      Source/utils/soundsample.cpp
  4. 12
      Source/utils/soundsample.h

2
3rdParty/SDL_audiolib/CMakeLists.txt vendored

@ -27,7 +27,7 @@ set(USE_DEC_FLUIDSYNTH OFF)
set(USE_DEC_BASSMIDI OFF)
set(USE_DEC_WILDMIDI OFF)
set(USE_DEC_ADLMIDI OFF)
set(USE_DEC_DRMP3 OFF)
set(USE_DEC_DRMP3 ON)
include(FetchContent)
FetchContent_Declare(SDL_audiolib

51
Source/sound.cpp

@ -10,6 +10,7 @@
#include <memory>
#include <mutex>
#include <Aulib/DecoderDrmp3.h>
#include <Aulib/DecoderDrwav.h>
#include <Aulib/ResamplerSpeex.h>
#include <Aulib/Stream.h>
@ -45,7 +46,22 @@ std::optional<Aulib::Stream> music;
std::unique_ptr<char[]> musicBuffer;
#endif
void LoadMusic(SDL_RWops *handle)
std::unique_ptr<Aulib::Decoder> CreateDecoder(bool isMp3)
{
if (isMp3)
return std::make_unique<Aulib::DecoderDrmp3>();
return std::make_unique<Aulib::DecoderDrwav>();
}
std::string GetMp3Path(const char *path)
{
std::string mp3Path = path;
const std::string::size_type dot = mp3Path.find_last_of('.');
mp3Path.replace(dot + 1, mp3Path.size() - (dot + 1), "mp3");
return mp3Path;
}
void LoadMusic(SDL_RWops *handle, bool isMp3)
{
#ifdef DISABLE_STREAMING_MUSIC
size_t bytestoread = SDL_RWsize(handle);
@ -55,7 +71,7 @@ void LoadMusic(SDL_RWops *handle)
handle = SDL_RWFromConstMem(musicBuffer.get(), bytestoread);
#endif
music.emplace(handle, std::make_unique<Aulib::DecoderDrwav>(),
music.emplace(handle, CreateDecoder(isMp3),
std::make_unique<Aulib::ResamplerSpeex>(*sgOptions.Audio.resamplingQuality), /*closeRw=*/true);
}
@ -151,28 +167,36 @@ void snd_play_snd(TSnd *pSnd, int lVolume, int lPan)
std::unique_ptr<TSnd> sound_file_load(const char *path, bool stream)
{
auto snd = std::make_unique<TSnd>();
snd->start_tc = SDL_GetTicks() - 80 - 1;
#ifndef STREAM_ALL_AUDIO
if (stream) {
#endif
if (snd->DSB.SetChunkStream(path) != 0) {
ErrSdl();
if (snd->DSB.SetChunkStream(GetMp3Path(path), /*isMp3=*/true, /*logErrors=*/false) != 0) {
SDL_ClearError();
if (snd->DSB.SetChunkStream(path, /*isMp3=*/false, /*logErrors=*/true) != 0) {
ErrSdl();
}
}
#ifndef STREAM_ALL_AUDIO
} else {
SDL_RWops *file = OpenAsset(path);
bool isMp3 = true;
SDL_RWops *file = OpenAsset(GetMp3Path(path).c_str());
if (file == nullptr) {
ErrDlg("OpenAsset failed", path, __FILE__, __LINE__);
SDL_ClearError();
isMp3 = false;
file = OpenAsset(path);
if (file == nullptr) {
ErrDlg("OpenAsset failed", path, __FILE__, __LINE__);
}
}
size_t dwBytes = SDL_RWsize(file);
auto waveFile = MakeArraySharedPtr<std::uint8_t>(dwBytes);
if (SDL_RWread(file, waveFile.get(), dwBytes, 1) == 0) {
ErrDlg("Failed to read file", fmt::format("{}: {}", path, SDL_GetError()), __FILE__, __LINE__);
}
int error = snd->DSB.SetChunk(waveFile, dwBytes);
int error = snd->DSB.SetChunk(waveFile, dwBytes, isMp3);
SDL_RWclose(file);
if (error != 0) {
ErrSdl();
@ -245,9 +269,16 @@ void music_start(uint8_t nTrack)
#else
const bool threadsafe = true;
#endif
SDL_RWops *handle = OpenAsset(trackPath, threadsafe);
bool isMp3 = true;
SDL_RWops *handle = OpenAsset(GetMp3Path(trackPath).c_str());
if (handle == nullptr) {
SDL_ClearError();
handle = OpenAsset(trackPath, threadsafe);
isMp3 = false;
}
if (handle != nullptr) {
LoadMusic(handle);
LoadMusic(handle, isMp3);
if (!music->open()) {
LogError(LogCategory::Audio, "Aulib::Stream::open (from music_start): {}", SDL_GetError());
CleanupMusic();

37
Source/utils/soundsample.cpp

@ -4,6 +4,7 @@
#include <cmath>
#include <utility>
#include <Aulib/DecoderDrmp3.h>
#include <Aulib/DecoderDrwav.h>
#include <Aulib/ResamplerSpeex.h>
#include <SDL.h>
@ -56,6 +57,19 @@ float PanLogToLinear(int logPan)
return copysign(1.F - factor, static_cast<float>(logPan));
}
std::unique_ptr<Aulib::Decoder> CreateDecoder(bool isMp3)
{
if (isMp3)
return std::make_unique<Aulib::DecoderDrmp3>();
return std::make_unique<Aulib::DecoderDrwav>();
}
std::unique_ptr<Aulib::Stream> CreateStream(SDL_RWops *handle, bool isMp3)
{
return std::make_unique<Aulib::Stream>(handle, CreateDecoder(isMp3),
std::make_unique<Aulib::ResamplerSpeex>(*sgOptions.Audio.resamplingQuality), /*closeRw=*/true);
}
} // namespace
float VolumeLogToLinear(int logVolume, int logMin, int logMax)
@ -113,28 +127,30 @@ void SoundSample::Stop()
stream_->stop();
}
int SoundSample::SetChunkStream(std::string filePath)
int SoundSample::SetChunkStream(std::string filePath, bool isMp3, bool logErrors)
{
file_path_ = std::move(filePath);
SDL_RWops *handle = OpenAsset(file_path_.c_str(), /*threadsafe=*/true);
SDL_RWops *handle = OpenAsset(filePath.c_str(), /*threadsafe=*/true);
if (handle == nullptr) {
LogError(LogCategory::Audio, "OpenAsset failed (from SoundSample::SetChunkStream): {}", SDL_GetError());
if (logErrors)
LogError(LogCategory::Audio, "OpenAsset failed (from SoundSample::SetChunkStream): {}", SDL_GetError());
return -1;
}
stream_ = std::make_unique<Aulib::Stream>(handle, std::make_unique<Aulib::DecoderDrwav>(),
std::make_unique<Aulib::ResamplerSpeex>(*sgOptions.Audio.resamplingQuality), /*closeRw=*/true);
file_path_ = std::move(filePath);
isMp3_ = isMp3;
stream_ = CreateStream(handle, isMp3_);
if (!stream_->open()) {
stream_ = nullptr;
LogError(LogCategory::Audio, "Aulib::Stream::open (from SoundSample::SetChunkStream): {}", SDL_GetError());
if (logErrors)
LogError(LogCategory::Audio, "Aulib::Stream::open (from SoundSample::SetChunkStream): {}", SDL_GetError());
return -1;
}
return 0;
}
#ifndef STREAM_ALL_AUDIO
int SoundSample::SetChunk(ArraySharedPtr<std::uint8_t> fileData, std::size_t dwBytes)
int SoundSample::SetChunk(ArraySharedPtr<std::uint8_t> fileData, std::size_t dwBytes, bool isMp3)
{
isMp3_ = isMp3;
file_data_ = std::move(fileData);
file_data_size_ = dwBytes;
SDL_RWops *buf = SDL_RWFromConstMem(file_data_.get(), dwBytes);
@ -142,8 +158,7 @@ int SoundSample::SetChunk(ArraySharedPtr<std::uint8_t> fileData, std::size_t dwB
return -1;
}
stream_ = std::make_unique<Aulib::Stream>(buf, std::make_unique<Aulib::DecoderDrwav>(),
std::make_unique<Aulib::ResamplerSpeex>(*sgOptions.Audio.resamplingQuality), /*closeRw=*/true);
stream_ = CreateStream(buf, isMp3_);
if (!stream_->open()) {
stream_ = nullptr;
file_data_ = nullptr;

12
Source/utils/soundsample.h

@ -29,7 +29,9 @@ public:
bool IsPlaying();
void Play(int logSoundVolume, int logUserVolume, int logPan);
void Stop();
int SetChunkStream(std::string filePath);
// Returns 0 on success.
int SetChunkStream(std::string filePath, bool isMp3, bool logErrors = true);
void SetFinishCallback(Aulib::Stream::Callback &&callback)
{
@ -43,7 +45,7 @@ public:
* @param dwBytes Length of buffer
* @return 0 on success, -1 otherwise
*/
int SetChunk(ArraySharedPtr<std::uint8_t> fileData, std::size_t dwBytes);
int SetChunk(ArraySharedPtr<std::uint8_t> fileData, std::size_t dwBytes, bool isMp3);
#endif
#ifndef STREAM_ALL_AUDIO
@ -59,8 +61,8 @@ public:
return SetChunkStream(other.file_path_);
#else
if (other.IsStreaming())
return SetChunkStream(other.file_path_);
return SetChunk(other.file_data_, other.file_data_size_);
return SetChunkStream(other.file_path_, isMp3_);
return SetChunk(other.file_data_, other.file_data_size_, isMp3_);
#endif
}
@ -76,6 +78,8 @@ private:
// Set for streaming audio to allow for duplicating it:
std::string file_path_;
bool isMp3_;
std::unique_ptr<Aulib::Stream> stream_;
};

Loading…
Cancel
Save