diff --git a/src/Plugins/WavAudioImporter/CMakeLists.txt b/src/Plugins/WavAudioImporter/CMakeLists.txt new file mode 100644 index 000000000..0d2e69d3d --- /dev/null +++ b/src/Plugins/WavAudioImporter/CMakeLists.txt @@ -0,0 +1,51 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +find_package(Magnum REQUIRED Audio) + +include_directories(${MAGNUM_AUDIO_INCLUDE_DIRS}) + +set(WavAudioImporter_SRCS + WavImporter.cpp) + +set(WavAudioImporter_HEADERS + WavHeader.h + WavImporter.h) + +add_library(WavAudioImporterObjects OBJECT ${WavAudioImporter_SRCS}) +set_target_properties(WavAudioImporterObjects PROPERTIES COMPILE_FLAGS "-DWavAudioImporterObjects_EXPORTS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") + +add_plugin(WavAudioImporter ${MAGNUM_PLUGINS_AUDIOIMPORTER_INSTALL_DIR} + WavAudioImporter.conf + $ + pluginRegistrationWavAudioImporter.cpp) +target_link_libraries(WavAudioImporter ${MAGNUM_AUDIO_LIBRARIES}) + +install(FILES ${WavAudioImporter_HEADERS} DESTINATION ${MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR}/WavAudioImporter) + +if(BUILD_TESTS) + add_library(WavAudioImporterTestLib STATIC $) + target_link_libraries(WavAudioImporterTestLib ${MAGNUM_LIBRARIES} ${MAGNUM_AUDIO_LIBRARIES}) + add_subdirectory(Test) +endif() diff --git a/src/Plugins/WavAudioImporter/Test/CMakeLists.txt b/src/Plugins/WavAudioImporter/Test/CMakeLists.txt new file mode 100644 index 000000000..fda7c7e61 --- /dev/null +++ b/src/Plugins/WavAudioImporter/Test/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/configure.h) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +corrade_add_test(WavAudioImporterTest WavImporterTest.cpp LIBRARIES WavAudioImporterTestLib) diff --git a/src/Plugins/WavAudioImporter/Test/WavImporterTest.cpp b/src/Plugins/WavAudioImporter/Test/WavImporterTest.cpp new file mode 100644 index 000000000..1a9593379 --- /dev/null +++ b/src/Plugins/WavAudioImporter/Test/WavImporterTest.cpp @@ -0,0 +1,123 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include "WavAudioImporter/WavImporter.h" + +#include "configure.h" + +namespace Magnum { namespace Audio { namespace Test { + +class WavImporterTest: public TestSuite::Tester { + public: + explicit WavImporterTest(); + + void wrongSize(); + void wrongSignature(); + void unsupportedFormat(); + void unsupportedChannelCount(); + void mono16(); + void stereo8(); +}; + +WavImporterTest::WavImporterTest() { + addTests({&WavImporterTest::wrongSize, + &WavImporterTest::wrongSignature, + &WavImporterTest::unsupportedFormat, + &WavImporterTest::unsupportedChannelCount, + &WavImporterTest::mono16, + &WavImporterTest::stereo8}); +} + +void WavImporterTest::wrongSize() { + std::ostringstream out; + Error::setOutput(&out); + + WavImporter importer; + CORRADE_VERIFY(!importer.openData(Containers::Array(43))); + CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): the file is too short: 43 bytes\n"); +} + +void WavImporterTest::wrongSignature() { + std::ostringstream out; + Error::setOutput(&out); + + WavImporter importer; + CORRADE_VERIFY(!importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "wrongSignature.wav"))); + CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): the file signature is invalid\n"); +} + +void WavImporterTest::unsupportedFormat() { + std::ostringstream out; + Error::setOutput(&out); + + WavImporter importer; + CORRADE_VERIFY(!importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "unsupportedFormat.wav"))); + CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): unsupported audio format 2\n"); +} + +void WavImporterTest::unsupportedChannelCount() { + std::ostringstream out; + Error::setOutput(&out); + + WavImporter importer; + CORRADE_VERIFY(!importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "unsupportedChannelCount.wav"))); + CORRADE_COMPARE(out.str(), "Audio::WavImporter::openData(): unsupported channel count 6 with 8 bits per sample\n"); +} + +void WavImporterTest::mono16() { + WavImporter importer; + CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "mono16.wav"))); + + CORRADE_COMPARE(importer.format(), Buffer::Format::Mono16); + CORRADE_COMPARE(importer.frequency(), 44000); + Containers::Array data = importer.data(); + CORRADE_COMPARE(data.size(), 4); + CORRADE_COMPARE(data[0], 0x1d); + CORRADE_COMPARE(data[1], 0x10); + CORRADE_COMPARE(data[2], 0x71); + CORRADE_COMPARE(data[3], 0xC5); +} + +void WavImporterTest::stereo8() { + WavImporter importer; + CORRADE_VERIFY(importer.openFile(Utility::Directory::join(WAVAUDIOIMPORTER_TEST_DIR, "stereo8.wav"))); + + CORRADE_COMPARE(importer.format(), Buffer::Format::Stereo8); + CORRADE_COMPARE(importer.frequency(), 96000); + Containers::Array data = importer.data(); + CORRADE_COMPARE(data.size(), 4); + CORRADE_COMPARE(data[0], 0xde); + CORRADE_COMPARE(data[1], 0xfe); + CORRADE_COMPARE(data[2], 0xca); + CORRADE_COMPARE(data[3], 0x7e); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Audio::Test::WavImporterTest) diff --git a/src/Plugins/WavAudioImporter/Test/configure.h.cmake b/src/Plugins/WavAudioImporter/Test/configure.h.cmake new file mode 100644 index 000000000..d5a41dac3 --- /dev/null +++ b/src/Plugins/WavAudioImporter/Test/configure.h.cmake @@ -0,0 +1,25 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#define WAVAUDIOIMPORTER_TEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}" diff --git a/src/Plugins/WavAudioImporter/Test/mono16.wav b/src/Plugins/WavAudioImporter/Test/mono16.wav new file mode 100644 index 000000000..30d898274 Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/mono16.wav differ diff --git a/src/Plugins/WavAudioImporter/Test/stereo8.wav b/src/Plugins/WavAudioImporter/Test/stereo8.wav new file mode 100644 index 000000000..02298ef3b Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/stereo8.wav differ diff --git a/src/Plugins/WavAudioImporter/Test/unsupportedChannelCount.wav b/src/Plugins/WavAudioImporter/Test/unsupportedChannelCount.wav new file mode 100644 index 000000000..2f0b89221 Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/unsupportedChannelCount.wav differ diff --git a/src/Plugins/WavAudioImporter/Test/unsupportedFormat.wav b/src/Plugins/WavAudioImporter/Test/unsupportedFormat.wav new file mode 100644 index 000000000..443eefa82 Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/unsupportedFormat.wav differ diff --git a/src/Plugins/WavAudioImporter/Test/wrongSignature.wav b/src/Plugins/WavAudioImporter/Test/wrongSignature.wav new file mode 100644 index 000000000..e50f1cd12 Binary files /dev/null and b/src/Plugins/WavAudioImporter/Test/wrongSignature.wav differ diff --git a/src/Plugins/WavAudioImporter/WavAudioImporter.conf b/src/Plugins/WavAudioImporter/WavAudioImporter.conf new file mode 100644 index 000000000..e69de29bb diff --git a/src/Plugins/WavAudioImporter/WavHeader.h b/src/Plugins/WavAudioImporter/WavHeader.h new file mode 100644 index 000000000..e472b8f5f --- /dev/null +++ b/src/Plugins/WavAudioImporter/WavHeader.h @@ -0,0 +1,60 @@ +#ifndef Magnum_Audio_WavHeader_h +#define Magnum_Audio_WavHeader_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Struct Magnum::Audio::WavHeader + */ + +#include + +namespace Magnum { namespace Audio { + +#pragma pack(1) +/** @brief WAV file header */ +struct WavHeader { + char chunkId[4]; /**< @brief `RIFF` characters */ + UnsignedInt chunkSize; /**< @brief Size of the rest of the file */ + char format[4]; /**< @brief `WAVE` characters */ + + char subChunk1Id[4]; /**< @brief `fmt ` characters */ + UnsignedInt subChunk1Size; /**< @brief 16 for PCM */ + UnsignedShort audioFormat; /**< @brief 1 = PCM */ + UnsignedShort numChannels; /**< @brief 1 = Mono, 2 = Stereo */ + UnsignedInt sampleRate; /**< @brief Sample rate in Hz */ + UnsignedInt byteRate; /**< @brief Bytes per second */ + UnsignedShort blockAlign; /**< @brief Bytes per sample (all channels) */ + UnsignedShort bitsPerSample; /**< @brief Bits per sample (one channel) */ + + char subChunk2Id[4]; /**< @brief `data` characters */ + UnsignedInt subChunk2Size; /**< @brief Size of the following data */ +}; +#pragma pack() + +static_assert(sizeof(WavHeader) == 44, "WavHeader size is not 44 bytes"); + +}} + +#endif diff --git a/src/Plugins/WavAudioImporter/WavImporter.cpp b/src/Plugins/WavAudioImporter/WavImporter.cpp new file mode 100644 index 000000000..db93e0885 --- /dev/null +++ b/src/Plugins/WavAudioImporter/WavImporter.cpp @@ -0,0 +1,130 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "WavImporter.h" + +#include +#include +#include + +#include "WavHeader.h" + +namespace Magnum { namespace Audio { + +WavImporter::WavImporter() = default; + +WavImporter::WavImporter(PluginManager::AbstractManager* manager, std::string plugin): AbstractImporter(manager, std::move(plugin)) {} + +WavImporter::~WavImporter() { close(); } + +auto WavImporter::doFeatures() const -> Features { return Feature::OpenData; } + +bool WavImporter::doIsOpened() const { return _data; } + +void WavImporter::doOpenData(Containers::ArrayReference data) { + /* Check file size */ + if(data.size() < sizeof(WavHeader)) { + Error() << "Audio::WavImporter::openData(): the file is too short:" << data.size() << "bytes"; + return; + } + + /* Get header contents and fix endianness */ + WavHeader header(*reinterpret_cast(data.begin())); + Utility::Endianness::littleEndianInPlace(header.chunkSize, + header.subChunk1Size, header.audioFormat, header.numChannels, + header.sampleRate, header.byteRate, header.blockAlign, + header.bitsPerSample, header.subChunk2Size); + + /* Check file signature */ + if(std::strncmp(header.chunkId, "RIFF", 4) != 0 || + std::strncmp(header.format, "WAVE", 4) != 0 || + std::strncmp(header.subChunk1Id, "fmt ", 4) != 0 || + std::strncmp(header.subChunk2Id, "data", 4) != 0) { + Error() << "Audio::WavImporter::openData(): the file signature is invalid"; + return; + } + + /* Check file size */ + if(header.chunkSize + 8 != data.size()) { + Error() << "Audio::WavImporter::openData(): the file has improper size, expected" + << header.chunkSize + 8 << "but got" << data.size(); + return; + } + + /* Check PCM format */ + if(header.audioFormat != 1) { + Error() << "Audio::WavImporter::openData(): unsupported audio format" << header.audioFormat; + return; + } + + /* Verify more things */ + if(header.subChunk1Size != 16 || + header.subChunk2Size + 44 != data.size() || + header.blockAlign != header.numChannels*header.bitsPerSample/8 || + header.byteRate != header.sampleRate*header.blockAlign) { + Error() << "Audio::WavImporter::openData(): the file is corrupted"; + return; + } + + /* Decide about format */ + if(header.numChannels == 1 && header.bitsPerSample == 8) + _format = Buffer::Format::Mono8; + else if(header.numChannels == 1 && header.bitsPerSample == 16) + _format = Buffer::Format::Mono16; + else if(header.numChannels == 2 && header.bitsPerSample == 8) + _format = Buffer::Format::Stereo8; + else if(header.numChannels == 2 && header.bitsPerSample == 16) + _format = Buffer::Format::Stereo16; + else { + Error() << "Audio::WavImporter::openData(): unsupported channel count" + << header.numChannels << "with" << header.bitsPerSample + << "bits per sample"; + return; + } + + /* Save frequency */ + _frequency = header.sampleRate; + + /** @todo Convert the data from little endian too */ + CORRADE_INTERNAL_ASSERT(!Utility::Endianness::isBigEndian()); + + /* Copy the data */ + _data = Containers::Array(header.subChunk2Size); + std::copy(data.begin()+sizeof(WavHeader), data.end(), _data.begin()); + return; +} + +void WavImporter::doClose() { _data = nullptr; } + +Buffer::Format WavImporter::doFormat() const { return _format; } + +UnsignedInt WavImporter::doFrequency() const { return _frequency; } + +Containers::Array WavImporter::doData() { + Containers::Array copy(_data.size()); + std::copy(_data.begin(), _data.end(), copy.begin()); + return copy; +} + +}} diff --git a/src/Plugins/WavAudioImporter/WavImporter.h b/src/Plugins/WavAudioImporter/WavImporter.h new file mode 100644 index 000000000..c780d964f --- /dev/null +++ b/src/Plugins/WavAudioImporter/WavImporter.h @@ -0,0 +1,72 @@ +#ifndef Magnum_Audio_WavImporter_h +#define Magnum_Audio_WavImporter_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Audio::WavImporter + */ + +#include +#include +#include