From f4c8bc686d877701241704809ecc1bbc8b4fdd77 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 19 Aug 2016 22:14:23 -0400 Subject: [PATCH 01/19] Add optional channel param for Sound::play() --- include/cpp3ds/Audio/Sound.hpp | 2 +- src/cpp3ds/Audio/Sound.cpp | 14 +++++++++----- src/emu3ds/Audio/Sound.cpp | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/cpp3ds/Audio/Sound.hpp b/include/cpp3ds/Audio/Sound.hpp index 02eeaec..5b898df 100644 --- a/include/cpp3ds/Audio/Sound.hpp +++ b/include/cpp3ds/Audio/Sound.hpp @@ -88,7 +88,7 @@ public : /// \see pause, stop /// //////////////////////////////////////////////////////////// - void play(); + void play(int channel = -1); //////////////////////////////////////////////////////////// /// \brief Pause the sound diff --git a/src/cpp3ds/Audio/Sound.cpp b/src/cpp3ds/Audio/Sound.cpp index caf40f4..259f216 100644 --- a/src/cpp3ds/Audio/Sound.cpp +++ b/src/cpp3ds/Audio/Sound.cpp @@ -76,7 +76,7 @@ Sound::~Sound() //////////////////////////////////////////////////////////// -void Sound::play() +void Sound::play(int channel) { if (!m_buffer || m_buffer->getSampleCount() == 0) return; @@ -87,11 +87,15 @@ void Sound::play() return; } - m_channel = 0; - while (m_channel < 24 && ndspChnIsPlaying(m_channel)) - m_channel++; + m_channel = channel; + if (channel == -1) + { + m_channel = 0; + while (m_channel < 24 && ndspChnIsPlaying(m_channel)) + m_channel++; + } - if (m_channel == 24) { + if (m_channel >= 24) { err() << "Sound::play() failed because all channels are in use." << std::endl; m_channel = -1; return; diff --git a/src/emu3ds/Audio/Sound.cpp b/src/emu3ds/Audio/Sound.cpp index 64ed0b0..3c30c0e 100644 --- a/src/emu3ds/Audio/Sound.cpp +++ b/src/emu3ds/Audio/Sound.cpp @@ -68,7 +68,7 @@ Sound::~Sound() //////////////////////////////////////////////////////////// -void Sound::play() +void Sound::play(int channel) { alCheck(alSourcePlay(m_source)); } From e034484dd55a54f69f7985b153229a8dd2c7e3b1 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 26 Aug 2016 22:55:39 -0400 Subject: [PATCH 02/19] Lazily force utf8 with String --- src/cpp3ds/System/I18n.cpp | 3 ++- src/cpp3ds/System/String.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/cpp3ds/System/I18n.cpp b/src/cpp3ds/System/I18n.cpp index cf77a37..037e5a9 100644 --- a/src/cpp3ds/System/I18n.cpp +++ b/src/cpp3ds/System/I18n.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #define TOKEN_COMMENT '#' @@ -108,7 +109,7 @@ void I18n::loadLanguageFile(const std::string& filename) bool I18n::loadFromFile(const std::string filename) { - std::ifstream file(filename); + std::ifstream file(FileSystem::getFilePath(filename)); if (file) { m_content.clear(); diff --git a/src/cpp3ds/System/String.cpp b/src/cpp3ds/System/String.cpp index d66529c..27e3dd9 100644 --- a/src/cpp3ds/System/String.cpp +++ b/src/cpp3ds/System/String.cpp @@ -73,7 +73,7 @@ String::String(const char* ansiString, const std::locale& locale) if (length > 0) { m_string.reserve(length + 1); - Utf32::fromAnsi(ansiString, ansiString + length, std::back_inserter(m_string), locale); + Utf8::toUtf32(ansiString, ansiString + length, std::back_inserter(m_string)); } } } @@ -83,7 +83,7 @@ String::String(const char* ansiString, const std::locale& locale) String::String(const std::string& ansiString, const std::locale& locale) { m_string.reserve(ansiString.length() + 1); - Utf32::fromAnsi(ansiString.begin(), ansiString.end(), std::back_inserter(m_string), locale); + Utf8::toUtf32(ansiString.begin(), ansiString.end(), std::back_inserter(m_string)); } @@ -154,7 +154,7 @@ std::string String::toAnsiString(const std::locale& locale) const output.reserve(m_string.length() + 1); // Convert - Utf32::toAnsi(m_string.begin(), m_string.end(), std::back_inserter(output), 0, locale); + Utf32::toUtf8(m_string.begin(), m_string.end(), std::back_inserter(output)); return output; } @@ -168,7 +168,7 @@ std::wstring String::toWideString() const output.reserve(m_string.length() + 1); // Convert - Utf32::toWide(m_string.begin(), m_string.end(), std::back_inserter(output), 0); + Utf32::toUtf8(m_string.begin(), m_string.end(), std::back_inserter(output)); return output; } From 8c964a653200750a20405e25966d1e5fcf42f0f0 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Mon, 29 Aug 2016 19:29:41 -0400 Subject: [PATCH 03/19] Remove unnecessary inline --- include/cpp3ds/System/I18n.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cpp3ds/System/I18n.hpp b/include/cpp3ds/System/I18n.hpp index 767bd55..dc40b59 100644 --- a/include/cpp3ds/System/I18n.hpp +++ b/include/cpp3ds/System/I18n.hpp @@ -52,7 +52,7 @@ class I18n { static void loadLanguage(Language language); - static inline void loadLanguageFile(const std::string& filename); + static void loadLanguageFile(const std::string& filename); static Language getLanguage(); From 350b7ccd3cb8400aa07cd58d94814598a491021c Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 2 Sep 2016 23:13:15 -0400 Subject: [PATCH 04/19] Add I18n::clearLoadedLanguage to return to default --- include/cpp3ds/System/I18n.hpp | 5 +++-- src/cpp3ds/System/I18n.cpp | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/cpp3ds/System/I18n.hpp b/include/cpp3ds/System/I18n.hpp index dc40b59..9486ba6 100644 --- a/include/cpp3ds/System/I18n.hpp +++ b/include/cpp3ds/System/I18n.hpp @@ -43,6 +43,8 @@ enum Language { Portuguese, Russian, ChineseTraditional, + + COUNT, }; class I18n { @@ -51,9 +53,8 @@ class I18n { static I18n& getInstance(); static void loadLanguage(Language language); - static void loadLanguageFile(const std::string& filename); - + static void clearLoadedLanguage(); static Language getLanguage(); template diff --git a/src/cpp3ds/System/I18n.cpp b/src/cpp3ds/System/I18n.cpp index 037e5a9..e94c6b3 100644 --- a/src/cpp3ds/System/I18n.cpp +++ b/src/cpp3ds/System/I18n.cpp @@ -51,14 +51,12 @@ I18n::I18n() #ifdef EMULATION langcode = 1; // TODO: get actual locale of PC #else - ret = CFGU_GetSystemLanguage(&langcode); - if (!ret) { + if (R_FAILED(ret = CFGU_GetSystemLanguage(&langcode))) // If the syscall fails, as it does with Citra-emu, default to English langcode = 1; - } + std::cout << (int)langcode << std::endl; #endif - m_language = static_cast(langcode); - loadFromLanguage(m_language); + loadFromLanguage(static_cast(langcode)); } @@ -90,12 +88,13 @@ void I18n::loadLanguage(Language language) Language I18n::getLanguage() { - return static_cast(getInstance().m_language); + return getInstance().m_language; } bool I18n::loadFromLanguage(const Language language) { + m_language = language; std::string filename = "lang/" + getLangString(language) + ".lang"; return loadFromFile(filename); } @@ -107,12 +106,18 @@ void I18n::loadLanguageFile(const std::string& filename) } +void I18n::clearLoadedLanguage() +{ + getInstance().m_content.clear(); +} + + bool I18n::loadFromFile(const std::string filename) { + m_content.clear(); std::ifstream file(FileSystem::getFilePath(filename)); if (file) { - m_content.clear(); std::string line; std::string content; const std::map replaceList = { From b73f82b11be28ee7dbcfb5656ddba6a44acf6614 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 9 Sep 2016 19:39:09 -0400 Subject: [PATCH 05/19] Skip drawing Text objects with empty strings --- src/cpp3ds/Graphics/Text.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cpp3ds/Graphics/Text.cpp b/src/cpp3ds/Graphics/Text.cpp index c829952..8417979 100644 --- a/src/cpp3ds/Graphics/Text.cpp +++ b/src/cpp3ds/Graphics/Text.cpp @@ -400,6 +400,9 @@ void Text::drawSystemFont(RenderTarget& target, RenderStates states) const //////////////////////////////////////////////////////////// void Text::draw(RenderTarget& target, RenderStates states) const { + if (m_string.isEmpty()) + return; + if (m_useSystemFont) { drawSystemFont(target, states); From 6baf956af661aa0e18a80ae3b3ed1451b499bd5d Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 23 Sep 2016 23:13:31 -0400 Subject: [PATCH 06/19] Disable OGG writer for transition to Tremor --- Dockerfile | 2 +- src/cpp3ds/Audio/SoundFileFactory.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index de74bb1..023ea90 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ RUN apt-get update && apt-get -y install \ RUN apt-get -y clean -RUN wget -q https://github.com/cpp3ds/3ds_portlibs/releases/download/r3/portlibs-3ds-r3.tar.xz -O portlibs.tar.xz && \ +RUN wget -q https://github.com/cpp3ds/3ds_portlibs/releases/download/r4/portlibs-3ds-r4.tar.xz -O portlibs.tar.xz && \ tar -xaf portlibs.tar.xz && \ rm portlibs.tar.xz && \ ln -s $(pwd)/portlibs $DEVKITPRO/portlibs && \ diff --git a/src/cpp3ds/Audio/SoundFileFactory.cpp b/src/cpp3ds/Audio/SoundFileFactory.cpp index 849b4ea..e87eb1c 100644 --- a/src/cpp3ds/Audio/SoundFileFactory.cpp +++ b/src/cpp3ds/Audio/SoundFileFactory.cpp @@ -32,7 +32,7 @@ #endif #ifdef CPP3DS_ENABLE_OGG #include -#include +//#include #endif #ifdef CPP3DS_ENABLE_MP3 #include @@ -57,7 +57,7 @@ namespace #endif #ifdef CPP3DS_ENABLE_OGG cpp3ds::SoundFileFactory::registerReader(); - cpp3ds::SoundFileFactory::registerWriter(); +// cpp3ds::SoundFileFactory::registerWriter(); #endif #ifdef CPP3DS_ENABLE_MP3 cpp3ds::SoundFileFactory::registerReader(); From 568e9b5363b94cdf51d7cd390a81e233dbc06387 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Sun, 25 Sep 2016 03:22:31 -0400 Subject: [PATCH 07/19] Add texture loadFromPreprocessedFile for 3dstex compatibility --- include/cpp3ds/Graphics/Texture.hpp | 1 + src/cpp3ds/Graphics/Texture.cpp | 75 +++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/include/cpp3ds/Graphics/Texture.hpp b/include/cpp3ds/Graphics/Texture.hpp index 4a1062e..9ce6a22 100644 --- a/include/cpp3ds/Graphics/Texture.hpp +++ b/include/cpp3ds/Graphics/Texture.hpp @@ -217,6 +217,7 @@ public : bool loadFromImage(const Image& image, const IntRect& area = IntRect()); #ifndef EMULATION + bool loadFromPreprocessedFile(const std::string& filename); bool loadFromPreprocessedFile(const std::string& filename, size_t width, size_t height, GPU_TEXCOLOR format); bool loadFromPreprocessedMemory(void *data, size_t size, size_t width, size_t height, GPU_TEXCOLOR format, bool copyData = true); diff --git a/src/cpp3ds/Graphics/Texture.cpp b/src/cpp3ds/Graphics/Texture.cpp index 103049f..5108ef4 100644 --- a/src/cpp3ds/Graphics/Texture.cpp +++ b/src/cpp3ds/Graphics/Texture.cpp @@ -47,6 +47,17 @@ GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | \ GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) +#ifdef _3DS +typedef struct +{ + u16 format; //< Format matching ctrulib enum GPU_TEXCOLOR + u16 width; //< Width (original width to next power of 2) + u16 height; //< Height (original height to next power of 2) + u16 widthOriginal; //< Width of original input + u16 heightOriginal; //< Height of original input +} Header; +#endif + namespace { cpp3ds::Mutex mutex; @@ -113,6 +124,34 @@ namespace } } } + + inline size_t fmtSize(GPU_TEXCOLOR fmt) + { + switch (fmt) + { + case GPU_RGBA8: + return 32; + case GPU_RGB8: + return 24; + case GPU_RGBA5551: + case GPU_RGB565: + case GPU_RGBA4: + case GPU_LA8: + case GPU_HILO8: + return 16; + case GPU_L8: + case GPU_A8: + case GPU_LA4: + case GPU_ETC1A4: + return 8; + case GPU_L4: + case GPU_A4: + case GPU_ETC1: + return 4; + default: + return 0; + } + } } @@ -299,6 +338,40 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area) } +//////////////////////////////////////////////////////////// +bool Texture::loadFromPreprocessedFile(const std::string& filename) +{ + if (filename.empty()) + return false; + + Header header; + FileInputStream file; + if (!file.open(filename)) + return false; + + file.read(&header, sizeof(Header)); + size_t size = file.getSize() - sizeof(Header); + + // Verify header + GPU_TEXCOLOR format = static_cast(header.format); + if (size != header.width * header.height * fmtSize(format) / 8) + { + err() << "Improper file header: " << filename << std::endl; + return false; + } + + void *data = malloc(size); + file.read(data, size); + + bool ret = loadFromPreprocessedMemory(data, size, header.width, header.height, format, true); + m_size.x = header.widthOriginal; + m_size.y = header.heightOriginal; + + free(data); + return ret; +} + + //////////////////////////////////////////////////////////// bool Texture::loadFromPreprocessedFile(const std::string& filename, size_t width, size_t height, GPU_TEXCOLOR format) { @@ -307,6 +380,8 @@ bool Texture::loadFromPreprocessedFile(const std::string& filename, size_t width FileInputStream file; file.open(filename); + if (!file.open(filename)) + return false; size_t size = file.getSize(); void *data = malloc(size); From ba11776fc62c58dd526854472479d4d3cdbfebde Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Sun, 25 Sep 2016 03:23:31 -0400 Subject: [PATCH 08/19] Fix Korean lang string --- src/cpp3ds/System/I18n.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpp3ds/System/I18n.cpp b/src/cpp3ds/System/I18n.cpp index e94c6b3..fb33aa1 100644 --- a/src/cpp3ds/System/I18n.cpp +++ b/src/cpp3ds/System/I18n.cpp @@ -70,7 +70,7 @@ const std::string I18n::getLangString(const Language langcode) const case Italian: return "it"; case Spanish: return "es"; case ChineseSimplified: return "zh"; - case Korean: return "ko"; + case Korean: return "kr"; case Dutch: return "nl"; case Portuguese: return "pt"; case Russian: return "ru"; From 4fad1a83341646077a11313474ac59371fc2ae1f Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Sun, 25 Sep 2016 15:01:23 -0400 Subject: [PATCH 09/19] Use FindTremor when building for 3ds --- cmake/FindTremor.cmake | 21 +++++++++++++++++++++ include/cpp3ds/Audio/SoundFileReaderOgg.hpp | 4 ++++ src/cpp3ds/Audio/CMakeLists.txt | 7 +++---- src/cpp3ds/Audio/SoundFileReaderOgg.cpp | 4 ++++ 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 cmake/FindTremor.cmake diff --git a/cmake/FindTremor.cmake b/cmake/FindTremor.cmake new file mode 100644 index 0000000..5234dfd --- /dev/null +++ b/cmake/FindTremor.cmake @@ -0,0 +1,21 @@ +# - Find Tremor +# +# TREMOR_INCLUDE_DIR - where to find Tremor headers. +# TREMOR_LIBRAY - List of libraries when using libTremor. +# TREMOR_FOUND - True if Tremor found. + +if(TREMOR_INCLUDE_DIR) + # Already in cache, be silent + set(TREMOR_FIND_QUIETLY TRUE) +endif(TREMOR_INCLUDE_DIR) + +find_path(TREMOR_INCLUDE_DIR tremor/ivorbisfile.h) +find_library(TREMOR_LIBRARY NAMES vorbisidec) + +# Handle the QUIETLY and REQUIRED arguments and set TREMOR_FOUND to TRUE if +# all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(TREMOR DEFAULT_MSG + TREMOR_INCLUDE_DIR TREMOR_LIBRARY) + +mark_as_advanced(TREMOR_INCLUDE_DIR TREMOR_LIBRARY) diff --git a/include/cpp3ds/Audio/SoundFileReaderOgg.hpp b/include/cpp3ds/Audio/SoundFileReaderOgg.hpp index 9b30e67..7ba5420 100644 --- a/include/cpp3ds/Audio/SoundFileReaderOgg.hpp +++ b/include/cpp3ds/Audio/SoundFileReaderOgg.hpp @@ -29,7 +29,11 @@ // Headers //////////////////////////////////////////////////////////// #include +#ifdef _3DS +#include +#else #include +#endif namespace cpp3ds diff --git a/src/cpp3ds/Audio/CMakeLists.txt b/src/cpp3ds/Audio/CMakeLists.txt index ede0564..5acdf63 100644 --- a/src/cpp3ds/Audio/CMakeLists.txt +++ b/src/cpp3ds/Audio/CMakeLists.txt @@ -17,11 +17,10 @@ set(SRC ) if(ENABLE_OGG) - find_package(Vorbis REQUIRED) - include_directories(${VORBIS_INCLUDE_DIRS}) + find_package(Tremor REQUIRED) + include_directories(${TREMOR_INCLUDE_DIRS}) list(APPEND SRC - ${SRCROOT}/SoundFileReaderOgg.cpp - ${SRCROOT}/SoundFileWriterOgg.cpp) + ${SRCROOT}/SoundFileReaderOgg.cpp) endif() if(ENABLE_MP3) find_package(mpg123 REQUIRED) diff --git a/src/cpp3ds/Audio/SoundFileReaderOgg.cpp b/src/cpp3ds/Audio/SoundFileReaderOgg.cpp index 9aba217..c8313ab 100644 --- a/src/cpp3ds/Audio/SoundFileReaderOgg.cpp +++ b/src/cpp3ds/Audio/SoundFileReaderOgg.cpp @@ -144,7 +144,11 @@ Uint64 SoundFileReaderOgg::read(Int16* samples, Uint64 maxCount) while (count < maxCount) { int bytesToRead = static_cast(maxCount - count) * sizeof(Int16); +#ifdef _3DS + long bytesRead = ov_read(&m_vorbis, reinterpret_cast(samples), bytesToRead, NULL); +#else long bytesRead = ov_read(&m_vorbis, reinterpret_cast(samples), bytesToRead, 0, 2, 1, NULL); +#endif if (bytesRead > 0) { long samplesRead = bytesRead / sizeof(Int16); From e410e8a071fea87fc51cba52190f0f505df33bed Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Sat, 1 Oct 2016 02:09:44 -0400 Subject: [PATCH 10/19] Change SoundStream to use more buffers at smaller sizes --- include/cpp3ds/Audio/SoundStream.hpp | 2 +- src/cpp3ds/Audio/Music.cpp | 2 +- src/cpp3ds/Audio/SoundStream.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/cpp3ds/Audio/SoundStream.hpp b/include/cpp3ds/Audio/SoundStream.hpp index ac9b317..6d9646c 100644 --- a/include/cpp3ds/Audio/SoundStream.hpp +++ b/include/cpp3ds/Audio/SoundStream.hpp @@ -284,7 +284,7 @@ class SoundStream : public SoundSource enum { - BufferCount = 3 ///< Number of audio buffers used by the streaming loop + BufferCount = 30 ///< Number of audio buffers used by the streaming loop }; //////////////////////////////////////////////////////////// diff --git a/src/cpp3ds/Audio/Music.cpp b/src/cpp3ds/Audio/Music.cpp index b497615..d874339 100644 --- a/src/cpp3ds/Audio/Music.cpp +++ b/src/cpp3ds/Audio/Music.cpp @@ -138,7 +138,7 @@ void Music::initialize() m_duration = m_file.getDuration(); // Resize the internal buffer so that it can contain 1 second of audio samples - m_samples.resize(m_file.getSampleRate() * m_file.getChannelCount()); + m_samples.resize(m_file.getSampleRate() * m_file.getChannelCount() / 16); // Initialize the stream SoundStream::initialize(m_file.getChannelCount(), m_file.getSampleRate()); diff --git a/src/cpp3ds/Audio/SoundStream.cpp b/src/cpp3ds/Audio/SoundStream.cpp index 46e38cf..06a2eb9 100644 --- a/src/cpp3ds/Audio/SoundStream.cpp +++ b/src/cpp3ds/Audio/SoundStream.cpp @@ -46,7 +46,7 @@ SoundStream::SoundStream() , m_loop (false) , m_samplesProcessed(0) { - m_thread.setPriority(0x19); + m_thread.setPriority(0x1A); } @@ -121,7 +121,7 @@ void SoundStream::play() } m_channel = 0; - while (m_channel < 24 && ndspChnIsPlaying(m_channel)) + while (m_channel < 24 && (ndspChnIsPlaying(m_channel) || ndspChnIsPaused(m_channel))) m_channel++; if (m_channel == 24) { @@ -437,7 +437,7 @@ bool SoundStream::fillQueue() { if (fillAndPushBuffer(i)) requestStop = true; - sleep(milliseconds(10)); + sleep(milliseconds(20)); } return requestStop; From 0aef59543706a77dc8e633c25fe7c5fa8af0dc9c Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Mon, 23 Jan 2017 15:20:47 -0500 Subject: [PATCH 11/19] Add locking for ndsp channels --- include/cpp3ds/Audio/AlResource.hpp | 7 +++++++ include/cpp3ds/Audio/Sound.hpp | 2 +- include/cpp3ds/Audio/SoundStream.hpp | 2 +- src/cpp3ds/Audio/AlResource.cpp | 4 ++++ src/cpp3ds/Audio/Sound.cpp | 13 +++++++++---- src/cpp3ds/Audio/SoundStream.cpp | 26 ++++++++++++++++++-------- src/emu3ds/Audio/Sound.cpp | 2 +- 7 files changed, 41 insertions(+), 15 deletions(-) diff --git a/include/cpp3ds/Audio/AlResource.hpp b/include/cpp3ds/Audio/AlResource.hpp index 2370f62..0aec05f 100644 --- a/include/cpp3ds/Audio/AlResource.hpp +++ b/include/cpp3ds/Audio/AlResource.hpp @@ -28,10 +28,17 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// +#include +#include namespace cpp3ds { +#ifdef _3DS +extern Mutex g_activeNdspChannelsMutex; +extern Uint32 g_activeNdspChannels; +#endif + //////////////////////////////////////////////////////////// /// \brief Base class for classes that require an OpenAL context /// diff --git a/include/cpp3ds/Audio/Sound.hpp b/include/cpp3ds/Audio/Sound.hpp index 5b898df..02eeaec 100644 --- a/include/cpp3ds/Audio/Sound.hpp +++ b/include/cpp3ds/Audio/Sound.hpp @@ -88,7 +88,7 @@ public : /// \see pause, stop /// //////////////////////////////////////////////////////////// - void play(int channel = -1); + void play(); //////////////////////////////////////////////////////////// /// \brief Pause the sound diff --git a/include/cpp3ds/Audio/SoundStream.hpp b/include/cpp3ds/Audio/SoundStream.hpp index 6d9646c..59b066f 100644 --- a/include/cpp3ds/Audio/SoundStream.hpp +++ b/include/cpp3ds/Audio/SoundStream.hpp @@ -300,7 +300,7 @@ class SoundStream : public SoundSource bool m_loop; ///< Loop flag (true to loop, false to play once) Uint64 m_samplesProcessed; ///< Number of buffers processed since beginning of the stream bool m_endBuffers[BufferCount]; ///< Each buffer is marked as "end buffer" or not, for proper duration calculation -#ifndef EMULATION +#ifdef _3DS ndspWaveBuf m_ndspWaveBuffers[BufferCount]; std::vector> m_buffers[BufferCount]; #else diff --git a/src/cpp3ds/Audio/AlResource.cpp b/src/cpp3ds/Audio/AlResource.cpp index 91dbfcb..c69a687 100644 --- a/src/cpp3ds/Audio/AlResource.cpp +++ b/src/cpp3ds/Audio/AlResource.cpp @@ -30,6 +30,10 @@ namespace cpp3ds { + +Mutex g_activeNdspChannelsMutex; +Uint32 g_activeNdspChannels = 0; + //////////////////////////////////////////////////////////// AlResource::AlResource() { diff --git a/src/cpp3ds/Audio/Sound.cpp b/src/cpp3ds/Audio/Sound.cpp index 259f216..ba70d44 100644 --- a/src/cpp3ds/Audio/Sound.cpp +++ b/src/cpp3ds/Audio/Sound.cpp @@ -30,6 +30,7 @@ #include <3ds.h> #include #include +#include namespace cpp3ds { @@ -76,7 +77,7 @@ Sound::~Sound() //////////////////////////////////////////////////////////// -void Sound::play(int channel) +void Sound::play() { if (!m_buffer || m_buffer->getSampleCount() == 0) return; @@ -87,11 +88,10 @@ void Sound::play(int channel) return; } - m_channel = channel; - if (channel == -1) { + Lock lock(g_activeNdspChannelsMutex); m_channel = 0; - while (m_channel < 24 && ndspChnIsPlaying(m_channel)) + while (m_channel < 24 && ((g_activeNdspChannels >> m_channel) & 1)) m_channel++; } @@ -133,6 +133,11 @@ void Sound::stop() return; ndspChnWaveBufClear(m_channel); + + { + Lock lock(g_activeNdspChannelsMutex); + g_activeNdspChannels &= ~(1 << m_channel); + } } diff --git a/src/cpp3ds/Audio/SoundStream.cpp b/src/cpp3ds/Audio/SoundStream.cpp index 06a2eb9..2621916 100644 --- a/src/cpp3ds/Audio/SoundStream.cpp +++ b/src/cpp3ds/Audio/SoundStream.cpp @@ -120,15 +120,20 @@ void SoundStream::play() return; } - m_channel = 0; - while (m_channel < 24 && (ndspChnIsPlaying(m_channel) || ndspChnIsPaused(m_channel))) - m_channel++; + { + Lock lock(g_activeNdspChannelsMutex); + m_channel = 0; + while (m_channel < 24 && ((g_activeNdspChannels >> m_channel) & 1)) + m_channel++; + + if (m_channel == 24) { + err() << "Failed to play audio stream: all channels are in use." << std::endl; + m_channel = -1; + return; + } - if (m_channel == 24) { - err() << "Failed to play audio stream: all channels are in use." << std::endl; - m_channel = -1; - return; - } + g_activeNdspChannels |= 1 << m_channel; + } ndspChnReset(m_channel); ndspChnSetInterp(m_channel, NDSP_INTERP_LINEAR); @@ -180,6 +185,11 @@ void SoundStream::stop() // Reset the playing position m_samplesProcessed = 0; + + { + Lock lock(g_activeNdspChannelsMutex); + g_activeNdspChannels &= ~(1 << m_channel); + } } diff --git a/src/emu3ds/Audio/Sound.cpp b/src/emu3ds/Audio/Sound.cpp index 3c30c0e..64ed0b0 100644 --- a/src/emu3ds/Audio/Sound.cpp +++ b/src/emu3ds/Audio/Sound.cpp @@ -68,7 +68,7 @@ Sound::~Sound() //////////////////////////////////////////////////////////// -void Sound::play(int channel) +void Sound::play() { alCheck(alSourcePlay(m_source)); } From 4eee3e381dc54967048d9aa5bd893e4d13ed3b1e Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Wed, 25 Jan 2017 21:44:54 -0500 Subject: [PATCH 12/19] Add AAC decoder and playback support --- CMakeLists.txt | 6 +- Dockerfile | 7 +- include/cpp3ds/Audio/SoundFileReaderAAC.hpp | 138 ++++++++++ include/cpp3ds/Audio/SoundStream.hpp | 2 +- src/cpp3ds/Audio/CMakeLists.txt | 6 + src/cpp3ds/Audio/SoundFileFactory.cpp | 6 + src/cpp3ds/Audio/SoundFileReaderAAC.cpp | 271 ++++++++++++++++++++ src/cpp3ds/Audio/SoundStream.cpp | 20 +- src/emu3ds/CMakeLists.txt | 6 + 9 files changed, 443 insertions(+), 19 deletions(-) create mode 100644 include/cpp3ds/Audio/SoundFileReaderAAC.hpp create mode 100644 src/cpp3ds/Audio/SoundFileReaderAAC.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a9f2d65..6b2e43e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,13 +10,17 @@ option(BUILD_EMULATOR "Build cpp3ds emulator (Qt5 required)" ON) option(BUILD_EXAMPLES "Build all cpp3ds example projects" ON) option(BUILD_DOCS "Build doxygen documentation" OFF) option(BUILD_TESTS "Build unit tests" OFF) -option(ENABLE_OGG "Include OGG encoder/decoder classes" ON) +option(ENABLE_OGG "Include OGG decoder classes" ON) +option(ENABLE_AAC "Include AAC decoder classes" OFF) option(ENABLE_FLAC "Include FLAC encoder/decoder classes" OFF) option(ENABLE_MP3 "Include MP3 decoder class" OFF) if(ENABLE_OGG) add_definitions(-DCPP3DS_ENABLE_OGG) endif() +if(ENABLE_AAC) + add_definitions(-DCPP3DS_ENABLE_AAC) +endif() if(ENABLE_FLAC) add_definitions(-DCPP3DS_ENABLE_FLAC) endif() diff --git a/Dockerfile b/Dockerfile index 023ea90..d535d82 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,11 +15,12 @@ RUN apt-get update && apt-get -y install \ libjpeg-dev \ libpng-dev \ libfreetype6-dev \ - libvorbis-dev + libvorbis-dev \ + libfaad2 RUN apt-get -y clean -RUN wget -q https://github.com/cpp3ds/3ds_portlibs/releases/download/r4/portlibs-3ds-r4.tar.xz -O portlibs.tar.xz && \ +RUN wget -q https://github.com/cpp3ds/3ds_portlibs/releases/download/r5/portlibs-3ds-r5.tar.xz -O portlibs.tar.xz && \ tar -xaf portlibs.tar.xz && \ rm portlibs.tar.xz && \ ln -s $(pwd)/portlibs $DEVKITPRO/portlibs && \ @@ -39,7 +40,7 @@ RUN cmake . && \ WORKDIR /usr/src/cpp3ds RUN mkdir build && \ cd build && \ - cmake -DBUILD_EMULATOR=ON -DENABLE_OGG=ON -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=ON .. && \ + cmake -DBUILD_EMULATOR=ON -DENABLE_OGG=ON -DENABLE_AAC=ON -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=ON .. && \ make -j4 && \ mv lib .. && \ cd .. && \ diff --git a/include/cpp3ds/Audio/SoundFileReaderAAC.hpp b/include/cpp3ds/Audio/SoundFileReaderAAC.hpp new file mode 100644 index 0000000..647bb68 --- /dev/null +++ b/include/cpp3ds/Audio/SoundFileReaderAAC.hpp @@ -0,0 +1,138 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef CPP3DS_SOUNDFILEREADERAAC_HPP +#define CPP3DS_SOUNDFILEREADERAAC_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief Implementation of sound file reader that handles AAC encoded files +/// +//////////////////////////////////////////////////////////// +class SoundFileReaderAAC : public SoundFileReader +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Check if this reader can handle a file given by an input stream + /// + /// \param stream Source stream to check + /// + /// \return True if the file is supported by this reader + /// + //////////////////////////////////////////////////////////// + static bool check(InputStream& stream); + +public: + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SoundFileReaderAAC(); + + ~SoundFileReaderAAC(); + + //////////////////////////////////////////////////////////// + /// \brief Open a sound file for reading + /// + /// \param stream Stream to open + /// \param info Structure to fill with the attributes of the loaded sound + /// + //////////////////////////////////////////////////////////// + virtual bool open(cpp3ds::InputStream& stream, Info& info); + + //////////////////////////////////////////////////////////// + /// \brief Change the current read position to the given sample offset + /// + /// If the given offset exceeds to total number of samples, + /// this function must jump to the end of the file. + /// + /// \param sampleOffset Index of the sample to jump to, relative to the beginning + /// + //////////////////////////////////////////////////////////// + virtual void seek(Uint64 sampleOffset); + + //////////////////////////////////////////////////////////// + /// \brief Read audio samples from the open file + /// + /// \param samples Pointer to the sample array to fill + /// \param maxCount Maximum number of samples to read + /// + /// \return Number of samples actually read (may be less than \a maxCount) + /// + //////////////////////////////////////////////////////////// + virtual Uint64 read(Int16* samples, Uint64 maxCount); + +private: + + void close(); + + bool readChunk(); + + //////////////////////////////////////////////////////////// + /// \brief Read the header of the open file + /// + /// \param info Attributes of the sound file + /// + /// \return True on success, false on error + /// + //////////////////////////////////////////////////////////// + bool parseHeader(Info& info); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + InputStream* m_stream; ///< Source stream to read from + unsigned int m_bytesPerSample; ///< Size of a sample, in bytes + Uint64 m_dataStart; ///< Starting position of the audio data in the open file + + unsigned long m_sampleRate; + unsigned char m_channelCount; + + std::vector m_inputBuffer; + std::vector m_sampleBuffer; + int m_inputBufferPosition; + int m_sampleBufferPosition; + + NeAACDecHandle m_handle; +}; + +} // namespace priv + +} // namespace cpp3ds + + +#endif // CPP3DS_SOUNDFILEREADERAAC_HPP diff --git a/include/cpp3ds/Audio/SoundStream.hpp b/include/cpp3ds/Audio/SoundStream.hpp index 59b066f..6d9646c 100644 --- a/include/cpp3ds/Audio/SoundStream.hpp +++ b/include/cpp3ds/Audio/SoundStream.hpp @@ -300,7 +300,7 @@ class SoundStream : public SoundSource bool m_loop; ///< Loop flag (true to loop, false to play once) Uint64 m_samplesProcessed; ///< Number of buffers processed since beginning of the stream bool m_endBuffers[BufferCount]; ///< Each buffer is marked as "end buffer" or not, for proper duration calculation -#ifdef _3DS +#ifndef EMULATION ndspWaveBuf m_ndspWaveBuffers[BufferCount]; std::vector> m_buffers[BufferCount]; #else diff --git a/src/cpp3ds/Audio/CMakeLists.txt b/src/cpp3ds/Audio/CMakeLists.txt index 5acdf63..db03b53 100644 --- a/src/cpp3ds/Audio/CMakeLists.txt +++ b/src/cpp3ds/Audio/CMakeLists.txt @@ -22,6 +22,12 @@ if(ENABLE_OGG) list(APPEND SRC ${SRCROOT}/SoundFileReaderOgg.cpp) endif() +if(ENABLE_AAC) + find_package(Faad REQUIRED) + include_directories(${FAAD_INCLUDE_DIRS}) + list(APPEND SRC + ${SRCROOT}/SoundFileReaderAAC.cpp) +endif() if(ENABLE_MP3) find_package(mpg123 REQUIRED) include_directories(${MPG123_INCLUDE_DIRS}) diff --git a/src/cpp3ds/Audio/SoundFileFactory.cpp b/src/cpp3ds/Audio/SoundFileFactory.cpp index e87eb1c..e63fc4b 100644 --- a/src/cpp3ds/Audio/SoundFileFactory.cpp +++ b/src/cpp3ds/Audio/SoundFileFactory.cpp @@ -34,6 +34,9 @@ #include //#include #endif +#ifdef CPP3DS_ENABLE_AAC +#include +#endif #ifdef CPP3DS_ENABLE_MP3 #include #endif @@ -59,6 +62,9 @@ namespace cpp3ds::SoundFileFactory::registerReader(); // cpp3ds::SoundFileFactory::registerWriter(); #endif +#ifdef CPP3DS_ENABLE_AAC + cpp3ds::SoundFileFactory::registerReader(); +#endif #ifdef CPP3DS_ENABLE_MP3 cpp3ds::SoundFileFactory::registerReader(); #endif diff --git a/src/cpp3ds/Audio/SoundFileReaderAAC.cpp b/src/cpp3ds/Audio/SoundFileReaderAAC.cpp new file mode 100644 index 0000000..82b77e3 --- /dev/null +++ b/src/cpp3ds/Audio/SoundFileReaderAAC.cpp @@ -0,0 +1,271 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace +{ + const cpp3ds::Uint64 mainChunkSize = 64; +} + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +bool SoundFileReaderAAC::check(InputStream& stream) +{ + unsigned char mainChunk[mainChunkSize]; + if (stream.read(mainChunk, sizeof(mainChunk)) != sizeof(mainChunk)) + return false; + + NeAACDecHandle handle = NeAACDecOpen(); + unsigned long samplerate; + unsigned char channels; + long ret = NeAACDecInit(handle, mainChunk, sizeof(mainChunk), &samplerate, &channels); + NeAACDecClose(handle); + if (ret != 0) + return false; + + std::cout << "AAC Samplerate: " << samplerate << " Channels: " << (int)channels << " BytesRead: " << (int)ret << std::endl; + + return true; +} + + +//////////////////////////////////////////////////////////// +SoundFileReaderAAC::SoundFileReaderAAC() : +m_stream (NULL), +m_bytesPerSample(0), +m_dataStart (0) +{ + m_handle = NeAACDecOpen(); + + // Configure the library to our needs + NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(m_handle); + conf->outputFormat = FAAD_FMT_16BIT; // We only support 16bit audio + conf->downMatrix = 1; // Convert from 5.1 to stereo if required + NeAACDecSetConfiguration(m_handle, conf); +} + + +//////////////////////////////////////////////////////////// +SoundFileReaderAAC::~SoundFileReaderAAC() +{ + close(); +} + + +//////////////////////////////////////////////////////////// +bool SoundFileReaderAAC::open(InputStream& stream, Info& info) +{ + m_stream = &stream; + + if (!parseHeader(info)) + { + err() << "Failed to open AAC sound file (invalid or unsupported file)" << std::endl; + return false; + } + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundFileReaderAAC::seek(Uint64 sampleOffset) +{ + assert(m_stream); + + m_stream->seek(m_dataStart + sampleOffset * m_bytesPerSample); + + m_inputBufferPosition = m_inputBuffer.size(); + readChunk(); +} + + +//////////////////////////////////////////////////////////// +bool SoundFileReaderAAC::readChunk() +{ + Int64 bytesRead = 0; + + if (m_inputBufferPosition == 0) + return true; + + // If there still exists some data in the buffer, + // move it to beginning and fill buffer from there. + if (m_inputBufferPosition < m_inputBuffer.size()) + { + int bytesRemaining = m_inputBuffer.size() - m_inputBufferPosition; + memmove(m_inputBuffer.data(), &m_inputBuffer[m_inputBufferPosition], bytesRemaining); + bytesRead = m_stream->read(&m_inputBuffer[bytesRemaining], m_inputBufferPosition); + bytesRead += bytesRemaining; + } + else // Buffer has been completed consumed + { + bytesRead = m_stream->read(m_inputBuffer.data(), m_inputBuffer.size()); + } + + if (!bytesRead) + return false; + if (bytesRead < m_inputBuffer.size()) + { + // Last bytes in file don't fill whole buffer, align accordingly + m_inputBufferPosition = m_inputBuffer.size() - bytesRead; + memmove(&m_inputBuffer[m_inputBufferPosition], m_inputBuffer.data(), bytesRead); + } + else + m_inputBufferPosition = 0; + + return true; +} + + +//////////////////////////////////////////////////////////// +Uint64 SoundFileReaderAAC::read(Int16* samples, Uint64 maxCount) +{ + assert(m_stream); + + NeAACDecFrameInfo frameInfo; + Uint32 count = 0; + Uint8 *buf = m_sampleBuffer.data(); + + while (count < maxCount) + { + size_t bytesLeft = static_cast(maxCount - count) * sizeof(Int16); + + // Keep input buffer full + if (m_inputBufferPosition > m_inputBuffer.size() - 1024) + { + if (!readChunk()) + break; + } + + // Output from sample buffer until it needs to be refilled + size_t bytesToCopy = std::min(bytesLeft, m_sampleBuffer.size() - m_sampleBufferPosition); + if (bytesToCopy > 0) + { + memcpy(samples + count, buf + m_sampleBufferPosition, bytesToCopy); + count += (bytesToCopy/sizeof(Int16)); + m_sampleBufferPosition += bytesToCopy; + } + + // Keep decoded sample buffer filled + if (m_sampleBufferPosition == m_sampleBuffer.size()) + { + NeAACDecDecode2(m_handle, &frameInfo, + m_inputBuffer.data() + m_inputBufferPosition, + m_inputBuffer.size() - m_inputBufferPosition, + reinterpret_cast(&buf), + m_sampleBuffer.size()); + + if (frameInfo.error > 0) + { +// std::cout << "Error (" << (int)frameInfo.error << "): " << NeAACDecGetErrorMessage(frameInfo.error) << std::endl; + if (m_inputBufferPosition == 0) + { + std::cout << "Error (" << (int)frameInfo.error << "): " << NeAACDecGetErrorMessage(frameInfo.error) << std::endl; + break; + } + if (frameInfo.error != 13 && frameInfo.error != 15) + std::cout << "Need to fill input buffer! error: " << (int)frameInfo.error << std::endl; + if (!readChunk()) + break; + } + else // Success + { + m_inputBufferPosition += frameInfo.bytesconsumed; + if (frameInfo.samples) + { + int sampleCapacity = m_sampleBuffer.size() / sizeof(Int16); + if (frameInfo.samples < sampleCapacity) + { + m_sampleBufferPosition = (sampleCapacity - frameInfo.samples) * sizeof(Int16); + memmove(&m_sampleBuffer[m_sampleBufferPosition], m_sampleBuffer.data(), frameInfo.samples * sizeof(Int16)); + } + else + m_sampleBufferPosition = 0; + } + } + } + } + + return count; +} + + +//////////////////////////////////////////////////////////// +bool SoundFileReaderAAC::parseHeader(Info& info) +{ + assert(m_stream); + + unsigned char mainChunk[mainChunkSize]; + if (m_stream->read(mainChunk, sizeof(mainChunk)) != sizeof(mainChunk)) + return false; + + long ret = NeAACDecInit(m_handle, mainChunk, sizeof(mainChunk), &m_sampleRate, &m_channelCount); + if (ret != 0) + return false; + + info.sampleCount = 0; + info.channelCount = m_channelCount; + info.sampleRate = m_sampleRate; + + // TODO: Figure these out + m_dataStart = ret; + m_bytesPerSample = 1; + + m_inputBuffer.resize(m_sampleRate); + m_inputBufferPosition = m_inputBuffer.size(); + m_sampleBuffer.resize(1024*2 * sizeof(uint16_t) * m_channelCount); + m_sampleBufferPosition = m_sampleBuffer.size(); + + m_stream->seek(ret); + + return true; +} + + +//////////////////////////////////////////////////////////// +void SoundFileReaderAAC::close() +{ + NeAACDecClose(m_handle); +} + + +} // namespace priv + +} // namespace cpp3ds diff --git a/src/cpp3ds/Audio/SoundStream.cpp b/src/cpp3ds/Audio/SoundStream.cpp index 2621916..49d35c3 100644 --- a/src/cpp3ds/Audio/SoundStream.cpp +++ b/src/cpp3ds/Audio/SoundStream.cpp @@ -47,6 +47,7 @@ SoundStream::SoundStream() , m_samplesProcessed(0) { m_thread.setPriority(0x1A); + m_thread.setStackSize(1024*64); } @@ -54,15 +55,8 @@ SoundStream::SoundStream() SoundStream::~SoundStream() { // Stop the sound if it was playing - - // Request the thread to terminate - { - Lock lock(m_threadMutex); - m_isStreaming = false; - } - - // Wait for the thread to terminate - m_thread.wait(); + if (m_threadStartState != Stopped) + stop(); } @@ -420,13 +414,11 @@ bool SoundStream::fillAndPushBuffer(unsigned int bufferNum) // Fill the buffer buffer.assign(data.samples, data.samples + data.sampleCount); + DSP_FlushDataCache(buffer.data(), buffer.size() * sizeof(Int16)); + memset(&ndspBuffer, 0, sizeof(ndspWaveBuf)); - ndspBuffer.data_vaddr = &buffer[0]; + ndspBuffer.data_vaddr = buffer.data(); ndspBuffer.nsamples = data.sampleCount / m_channelCount; - ndspBuffer.looping = false; - ndspBuffer.status = NDSP_WBUF_FREE; - - DSP_FlushDataCache((u8*)&buffer[0], data.sampleCount); // Push it into the sound queue ndspChnWaveBufAdd(m_channel, &ndspBuffer); diff --git a/src/emu3ds/CMakeLists.txt b/src/emu3ds/CMakeLists.txt index fefaa79..cb56330 100644 --- a/src/emu3ds/CMakeLists.txt +++ b/src/emu3ds/CMakeLists.txt @@ -121,6 +121,12 @@ if(ENABLE_OGG) ${SRCROOT}/Audio/SoundFileReaderOgg.cpp ${SRCROOT}/Audio/SoundFileWriterOgg.cpp) endif() +if(ENABLE_AAC) + find_package(Faad REQUIRED) + include_directories(${FAAD_INCLUDE_DIRS}) + list(APPEND SRC + ${SRCROOT}/Audio/SoundFileReaderAAC.cpp) +endif() if(ENABLE_MP3) find_package(mpg123 REQUIRED) include_directories(${MPG123_INCLUDE_DIRS}) From c60325a6db8f18d97db436cbd5690e0948a70b5f Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Wed, 25 Jan 2017 22:41:59 -0500 Subject: [PATCH 13/19] Update to DevkitARM r46 and add libfmt3 for I18n/formatting --- Dockerfile | 3 ++- include/cpp3ds/System/I18n.hpp | 17 ++--------------- src/cpp3ds/CMakeLists.txt | 2 ++ src/cpp3ds/Graphics/Console.cpp | 2 +- src/emu3ds/CMakeLists.txt | 2 ++ 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index d535d82..d44fcc1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,8 @@ RUN apt-get update && apt-get -y install \ libpng-dev \ libfreetype6-dev \ libvorbis-dev \ - libfaad2 + libfaad2 \ + libfmt3-dev RUN apt-get -y clean diff --git a/include/cpp3ds/System/I18n.hpp b/include/cpp3ds/System/I18n.hpp index 9486ba6..e4356bb 100644 --- a/include/cpp3ds/System/I18n.hpp +++ b/include/cpp3ds/System/I18n.hpp @@ -10,24 +10,11 @@ #include #include #include +#include #define _(key, ...) (cpp3ds::I18n::getInstance().translate(key, ##__VA_ARGS__)) -namespace { - - template - cpp3ds::String string_format( const std::string& format, Args ... args ) - { - size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0' - std::unique_ptr buf( new char[ size ] ); - snprintf( buf.get(), size, format.c_str(), args ... ); - std::string stringUtf8( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside - return cpp3ds::String::fromUtf8(stringUtf8.begin(), stringUtf8.end()); - } -} - - namespace cpp3ds { enum Language { @@ -65,7 +52,7 @@ class I18n { trans = std::string(key); else trans = it->second; - return string_format(trans, args ...); + return fmt::sprintf(trans, args ...); } template diff --git a/src/cpp3ds/CMakeLists.txt b/src/cpp3ds/CMakeLists.txt index 546cd3c..0fa2008 100644 --- a/src/cpp3ds/CMakeLists.txt +++ b/src/cpp3ds/CMakeLists.txt @@ -12,6 +12,8 @@ set(CMAKE_CXX_FLAGS "-std=c++11") add_definitions(-D_3DS) +find_package(Fmt REQUIRED) + add_subdirectory(Audio) add_subdirectory(Graphics) add_subdirectory(Network) diff --git a/src/cpp3ds/Graphics/Console.cpp b/src/cpp3ds/Graphics/Console.cpp index fab52dd..44e5574 100644 --- a/src/cpp3ds/Graphics/Console.cpp +++ b/src/cpp3ds/Graphics/Console.cpp @@ -22,7 +22,7 @@ namespace cpp3ds { extern "C" { #ifndef EMULATION -ssize_t console_write(struct _reent *r, int fd, const char *ptr, size_t len) { +ssize_t console_write(struct _reent *r, void *fd, const char *ptr, size_t len) { cpp3ds::String s; int i = 0; while (i < len) { diff --git a/src/emu3ds/CMakeLists.txt b/src/emu3ds/CMakeLists.txt index cb56330..c828302 100644 --- a/src/emu3ds/CMakeLists.txt +++ b/src/emu3ds/CMakeLists.txt @@ -134,6 +134,8 @@ if(ENABLE_MP3) ${SRCROOT}/Audio/SoundFileReaderMp3.cpp) endif() +find_package(Fmt REQUIRED) + # ImageLoader.cpp must be compiled with the -fno-strict-aliasing # when gcc is used; otherwise saving PNGs may crash in stb_image_write set_source_files_properties(${SRCROOT}/ImageLoader.cpp PROPERTIES COMPILE_FLAGS -fno-strict-aliasing) From 3c2e3ac44ecf50b6cb7044e62e013ac9b30a126f Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Wed, 25 Jan 2017 23:39:10 -0500 Subject: [PATCH 14/19] Fix some cmake stuff and fix a ndsp channel bug --- CMakeLists.txt | 6 +++--- Dockerfile | 2 +- cmake/FindFaad.cmake | 43 ++++++++++++++++++++++++++++++++++++++ cmake/arm-toolchain.cmake | 2 +- src/cpp3ds/Audio/Sound.cpp | 15 +++++++------ src/cpp3ds/CMakeLists.txt | 2 -- src/emu3ds/CMakeLists.txt | 2 -- test/CMakeLists.txt | 8 ++++++- 8 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 cmake/FindFaad.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b2e43e..08fb1d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,9 +76,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin") # compile flags set(ARCH "-march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft") -set(CPP3DS_ARM_FLAGS "-g -O2 ${ARCH} -ffunction-sections -fdata-sections") -set(CPP3DS_TEST_FLAGS "-g -O2 -coverage") -set(CPP3DS_EMU_FLAGS "-g -O2") +set(CPP3DS_ARM_FLAGS "-g -O3 ${ARCH} -ffunction-sections -fdata-sections") +set(CPP3DS_TEST_FLAGS "-g -O3 -coverage") +set(CPP3DS_EMU_FLAGS "-g -O3") add_subdirectory(src) diff --git a/Dockerfile b/Dockerfile index d44fcc1..deb4d0d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get -y install \ libpng-dev \ libfreetype6-dev \ libvorbis-dev \ - libfaad2 \ + libfaad-dev \ libfmt3-dev RUN apt-get -y clean diff --git a/cmake/FindFaad.cmake b/cmake/FindFaad.cmake new file mode 100644 index 0000000..42b88b8 --- /dev/null +++ b/cmake/FindFaad.cmake @@ -0,0 +1,43 @@ +# Try to find FAAD library and include path. +# Once done this will define +# +# FAAD_INCLUDE_DIRS - where to find faad.h, etc. +# FAAD_LIBRARIES - List of libraries when using libfaad. +# FAAD_FOUND - True if libfaad found. + +if(WIN32) + find_path(FAAD_INCLUDE_DIR faad.h $ENV{PROGRAMFILES}/FAAD/include DOC "The directory where faad.h resides") + find_library(FAAD_LIBRARY NAMES faad PATHS $ENV{PROGRAMFILES}/FAAD/lib DOC "The libfaad library") + +else(WIN32) + find_path(FAAD_INCLUDE_DIR NAMES faad.h faad2/faad.h DOC "The directory where faad.h resides") + find_library(FAAD_LIBRARY NAMES faad DOC "The libfaad library") + +endif(WIN32) + +if(FAAD_INCLUDE_DIR AND FAAD_LIBRARY) + set(FAAD_FOUND 1) + set(FAAD_LIBRARIES ${FAAD_LIBRARY}) + set(FAAD_INCLUDE_DIRS ${FAAD_INCLUDE_DIR}) +else(FAAD_INCLUDE_DIR AND FAAD_LIBRARY) + set(FAAD_FOUND 0) + set(FAAD_LIBRARIES) + set(FAAD_INCLUDE_DIRS) +endif(FAAD_INCLUDE_DIR AND FAAD_LIBRARY) + +mark_as_advanced(FAAD_INCLUDE_DIR) +mark_as_advanced(FAAD_LIBRARY) +mark_as_advanced(FAAD_FOUND) + +if(NOT FAAD_FOUND) + set(FAAD_DIR_MESSAGE "libfaad was not found. Make sure FAAD_LIBRARY and FAAD_INCLUDE_DIR are set.") + if(NOT FAAD_FIND_QUIETLY) + message(STATUS "${FAAD_DIR_MESSAGE}") + else(NOT FAAD_FIND_QUIETLY) + if(FAAD_FIND_REQUIRED) + message(FATAL_ERROR "${FAAD_DIR_MESSAGE}") + endif(FAAD_FIND_REQUIRED) + endif(NOT FAAD_FIND_QUIETLY) +else(NOT FAAD_FOUND) + message(STATUS "Found libfaad: ${FAAD_LIBRARY}") +endif(NOT FAAD_FOUND) diff --git a/cmake/arm-toolchain.cmake b/cmake/arm-toolchain.cmake index 8a912cc..edb35f5 100644 --- a/cmake/arm-toolchain.cmake +++ b/cmake/arm-toolchain.cmake @@ -9,7 +9,7 @@ SET(CMAKE_OBJCOPY ${DEVKITARM}/bin/arm-none-eabi-objcopy) SET(CMAKE_AR ${DEVKITARM}/bin/arm-none-eabi-ar) SET(CMAKE_RANLIB ${DEVKITARM}/bin/arm-none-eabi-ranlib) -set(CMAKE_FIND_ROOT_PATH $ENV{PORTLIBS}/3ds $ENV{PORTLIBS}/armv6k ${DEVKITARM} ${DEVKITPRO} ${DEVKITPRO}/portlibs/3ds ${DEVKITPRO}/portlibs/armv6k) +set(CMAKE_FIND_ROOT_PATH ${DEVKITARM} ${DEVKITPRO} ${DEVKITPRO}/portlibs/3ds ${DEVKITPRO}/portlibs/armv6k ${DEVKITPRO}/portlibs/3ds/lib ${DEVKITPRO}/portlibs/armv6k/lib) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment diff --git a/src/cpp3ds/Audio/Sound.cpp b/src/cpp3ds/Audio/Sound.cpp index ba70d44..14ee59c 100644 --- a/src/cpp3ds/Audio/Sound.cpp +++ b/src/cpp3ds/Audio/Sound.cpp @@ -93,12 +93,14 @@ void Sound::play() m_channel = 0; while (m_channel < 24 && ((g_activeNdspChannels >> m_channel) & 1)) m_channel++; - } - if (m_channel >= 24) { - err() << "Sound::play() failed because all channels are in use." << std::endl; - m_channel = -1; - return; + if (m_channel == 24) { + err() << "Failed to play audio stream: all channels are in use." << std::endl; + m_channel = -1; + return; + } + + g_activeNdspChannels |= 1 << m_channel; } setPlayingOffset(Time::Zero); @@ -110,7 +112,7 @@ void Sound::play() ndspChnSetRate(m_channel, float(m_buffer->getSampleRate())); ndspChnSetFormat(m_channel, (m_buffer->getChannelCount() == 1) ? NDSP_FORMAT_MONO_PCM16 : NDSP_FORMAT_STEREO_PCM16); - DSP_FlushDataCache((u8*)m_buffer->getSamples(), size); + DSP_FlushDataCache(m_buffer->getSamples(), size); ndspChnWaveBufAdd(m_channel, &m_ndspWaveBuf); } @@ -137,6 +139,7 @@ void Sound::stop() { Lock lock(g_activeNdspChannelsMutex); g_activeNdspChannels &= ~(1 << m_channel); + m_channel = -1; } } diff --git a/src/cpp3ds/CMakeLists.txt b/src/cpp3ds/CMakeLists.txt index 0fa2008..546cd3c 100644 --- a/src/cpp3ds/CMakeLists.txt +++ b/src/cpp3ds/CMakeLists.txt @@ -12,8 +12,6 @@ set(CMAKE_CXX_FLAGS "-std=c++11") add_definitions(-D_3DS) -find_package(Fmt REQUIRED) - add_subdirectory(Audio) add_subdirectory(Graphics) add_subdirectory(Network) diff --git a/src/emu3ds/CMakeLists.txt b/src/emu3ds/CMakeLists.txt index c828302..cb56330 100644 --- a/src/emu3ds/CMakeLists.txt +++ b/src/emu3ds/CMakeLists.txt @@ -134,8 +134,6 @@ if(ENABLE_MP3) ${SRCROOT}/Audio/SoundFileReaderMp3.cpp) endif() -find_package(Fmt REQUIRED) - # ImageLoader.cpp must be compiled with the -fno-strict-aliasing # when gcc is used; otherwise saving PNGs may crash in stb_image_write set_source_files_properties(${SRCROOT}/ImageLoader.cpp PROPERTIES COMPILE_FLAGS -fno-strict-aliasing) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cb90e7a..002d383 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -108,6 +108,12 @@ if(ENABLE_OGG) ${SRCROOT}/Audio/SoundFileReaderOgg.cpp ${SRCROOT}/Audio/SoundFileWriterOgg.cpp) endif() +if(ENABLE_AAC) + find_package(Faad REQUIRED) + include_directories(${FAAD_INCLUDE_DIRS}) + list(APPEND SRC + ${SRCROOT}/Audio/SoundFileReaderAAC.cpp) +endif() if(ENABLE_MP3) find_package(mpg123 REQUIRED) include_directories(${MPG123_INCLUDE_DIRS}) @@ -131,7 +137,7 @@ set_target_properties(cpp3ds-test PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} $ set_target_properties(cpp3ds-test PROPERTIES COMPILE_DEFINITIONS "EMULATION;TEST") add_executable(tests ${SRCTESTS} ${SRC} ${RESOURCE_OUTPUT}) -target_link_libraries(tests ${GTEST_BOTH_LIBRARIES} sfml-graphics sfml-window sfml-system sfml-audio openal GLEW GL jpeg freetype vorbisenc vorbisfile vorbis ogg ssl crypto pthread) +target_link_libraries(tests ${GTEST_BOTH_LIBRARIES} sfml-graphics sfml-window sfml-system sfml-audio openal GLEW GL jpeg freetype vorbisenc vorbisfile vorbis ogg faad ssl crypto pthread) set_target_properties(tests PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${CPP3DS_TEST_FLAGS} -std=c++11") set_target_properties(tests PROPERTIES COMPILE_DEFINITIONS "EMULATION;TEST") set_target_properties(tests PROPERTIES LINK_FLAGS "${CMAKE_CXX_FLAGS} ${CPP3DS_TEST_FLAGS}") From 9e5295df41aabe6fefcd8f00e343a1f7fe3e2be6 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Thu, 26 Jan 2017 16:53:37 -0500 Subject: [PATCH 15/19] Fix channel lock bug exhausting all channels --- src/cpp3ds/Audio/Sound.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cpp3ds/Audio/Sound.cpp b/src/cpp3ds/Audio/Sound.cpp index 14ee59c..152b0ff 100644 --- a/src/cpp3ds/Audio/Sound.cpp +++ b/src/cpp3ds/Audio/Sound.cpp @@ -88,6 +88,7 @@ void Sound::play() return; } + if (m_channel == -1) { Lock lock(g_activeNdspChannelsMutex); m_channel = 0; @@ -136,6 +137,7 @@ void Sound::stop() ndspChnWaveBufClear(m_channel); + // TODO: set ndsp callback to make channel inactive after playback finishes { Lock lock(g_activeNdspChannelsMutex); g_activeNdspChannels &= ~(1 << m_channel); From 2d6c142f8a15be018364c60a1809ef4c196aa066 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 27 Jan 2017 02:02:51 -0500 Subject: [PATCH 16/19] Update 3ds-tools dependency --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index deb4d0d..fc1b147 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ RUN wget -q https://github.com/cpp3ds/3ds_portlibs/releases/download/r5/portlibs ln -s $(pwd)/portlibs $DEVKITPRO/portlibs && \ ln -s $DEVKITPRO/portlibs/3ds $DEVKITPRO/portlibs/armv6k -RUN wget -q https://github.com/cpp3ds/3ds-tools/releases/download/r5/3ds-tools-linux-r5.tar.gz -O tools.tar.gz && \ +RUN wget -q https://github.com/cpp3ds/3ds-tools/releases/download/r6/3ds-tools-linux-r6.tar.gz -O tools.tar.gz && \ tar -xaf tools.tar.gz && \ cp 3ds-tools/* $DEVKITARM/bin && \ rm tools.tar.gz From 9cbe76d41feb6a380c79bcc0e6fb062ba96954a4 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 27 Jan 2017 22:37:40 -0500 Subject: [PATCH 17/19] Check if Audio service is enabled (ndspInit succeeds) before playing audio --- src/cpp3ds/Audio/Music.cpp | 10 ++++++++++ src/cpp3ds/Audio/Sound.cpp | 3 +++ 2 files changed, 13 insertions(+) diff --git a/src/cpp3ds/Audio/Music.cpp b/src/cpp3ds/Audio/Music.cpp index d874339..35e6322 100644 --- a/src/cpp3ds/Audio/Music.cpp +++ b/src/cpp3ds/Audio/Music.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -53,6 +54,9 @@ Music::~Music() //////////////////////////////////////////////////////////// bool Music::openFromFile(const std::string& filename) { + if (!Service::isEnabled(Audio)) + return false; + // First stop the music if it was already running stop(); @@ -70,6 +74,9 @@ bool Music::openFromFile(const std::string& filename) //////////////////////////////////////////////////////////// bool Music::openFromMemory(const void* data, std::size_t sizeInBytes) { + if (!Service::isEnabled(Audio)) + return false; + // First stop the music if it was already running stop(); @@ -87,6 +94,9 @@ bool Music::openFromMemory(const void* data, std::size_t sizeInBytes) //////////////////////////////////////////////////////////// bool Music::openFromStream(InputStream& stream) { + if (!Service::isEnabled(Audio)) + return false; + // First stop the music if it was already running stop(); diff --git a/src/cpp3ds/Audio/Sound.cpp b/src/cpp3ds/Audio/Sound.cpp index 152b0ff..9bf87eb 100644 --- a/src/cpp3ds/Audio/Sound.cpp +++ b/src/cpp3ds/Audio/Sound.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace cpp3ds { @@ -79,6 +80,8 @@ Sound::~Sound() //////////////////////////////////////////////////////////// void Sound::play() { + if (!Service::isEnabled(Audio)) + return; if (!m_buffer || m_buffer->getSampleCount() == 0) return; if (getStatus() == Playing) From a80e934523fe6c53446442e7f1e9427c895f9269 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 27 Jan 2017 22:38:32 -0500 Subject: [PATCH 18/19] Update emulator window title --- res/emu/emulator.ui | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/res/emu/emulator.ui b/res/emu/emulator.ui index b74cdd6..e74958b 100644 --- a/res/emu/emulator.ui +++ b/res/emu/emulator.ui @@ -10,14 +10,8 @@ 385 - - - 0 - 0 - - - MainWindow + cpp3ds Emulator @@ -34,16 +28,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -64,7 +49,7 @@ 0 0 318 - 21 + 25 From 7813714776e2134bd75b9f3869ed142c1d4eeaaf Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Sat, 28 Jan 2017 02:37:55 -0500 Subject: [PATCH 19/19] Add ability to define icon flags for bannertool --- cmake/cpp3ds.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/cpp3ds.cmake b/cmake/cpp3ds.cmake index 53fe60e..6d037d8 100644 --- a/cmake/cpp3ds.cmake +++ b/cmake/cpp3ds.cmake @@ -218,7 +218,7 @@ endmacro() function(__add_smdh target APP_TITLE APP_DESCRIPTION APP_AUTHOR APP_ICON) if(BANNERTOOL AND NOT FORCE_SMDHTOOL) - set(__SMDH_COMMAND ${BANNERTOOL} makesmdh -s ${APP_TITLE} -l ${APP_DESCRIPTION} -p ${APP_AUTHOR} -i ${APP_ICON} -o ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target}) + set(__SMDH_COMMAND ${BANNERTOOL} makesmdh -s ${APP_TITLE} -l ${APP_DESCRIPTION} -p ${APP_AUTHOR} -i ${APP_ICON} -o ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target} ${ICON_FLAGS}) else() set(__SMDH_COMMAND ${SMDHTOOL} --create ${APP_TITLE} ${APP_DESCRIPTION} ${APP_AUTHOR} ${APP_ICON} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target}) endif()