From c1d69c28d4a768c190e697257e8ad782cb3ecca5 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquemin Date: Mon, 27 May 2019 18:51:41 +0200 Subject: [PATCH] Audio: add support for buffer loop points. This feature requires the AL_SOFT_loop_points extension. Also, a test for Buffer::setData() was added to BufferALTest. --- doc/openal-support.dox | 2 + src/Magnum/Audio/Buffer.cpp | 54 ++++++++++++++ src/Magnum/Audio/Buffer.h | 55 ++++++++++++++- src/Magnum/Audio/CMakeLists.txt | 1 + src/Magnum/Audio/Context.cpp | 1 + src/Magnum/Audio/Extensions.h | 9 ++- src/Magnum/Audio/Test/BufferALTest.cpp | 98 +++++++++++++++++++++++++- src/MagnumExternal/OpenAL/extensions.h | 7 ++ 8 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 src/Magnum/Audio/Buffer.cpp diff --git a/doc/openal-support.dox b/doc/openal-support.dox index f9c5c39c4..66aaad645 100644 --- a/doc/openal-support.dox +++ b/doc/openal-support.dox @@ -4,6 +4,7 @@ Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Vladimír Vondruš Copyright © 2015 Jonathan Hale + Copyright © 2019 Guillaume Jacquemin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -58,6 +59,7 @@ Extension | Status ------------------------------------------- | ------ @alc_extension{SOFTX,HRTF} | done @alc_extension{SOFT,HRTF} | done +@al_extension{SOFT,loop_points} | done */ } diff --git a/src/Magnum/Audio/Buffer.cpp b/src/Magnum/Audio/Buffer.cpp new file mode 100644 index 000000000..ffe8f969a --- /dev/null +++ b/src/Magnum/Audio/Buffer.cpp @@ -0,0 +1,54 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 + Vladimír Vondruš + Copyright © 2019 Guillaume Jacquemin + + 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 "Buffer.h" + +#include "Magnum/Math/Functions.h" + +namespace Magnum { namespace Audio { + +Buffer& Buffer::setLoopPoints(Int loopStart, Int loopEnd) { + ALint sizeInBytes; + ALint channels; + ALint bits; + + alGetBufferi(_id, AL_SIZE, &sizeInBytes); + alGetBufferi(_id, AL_CHANNELS, &channels); + alGetBufferi(_id, AL_BITS, &bits); + + ALint lengthInSamples = sizeInBytes * 8 / (channels * bits); + + ALint loopPoints[2] = { + Math::max(0, loopStart), + Math::min(loopEnd, lengthInSamples) + }; + + alBufferiv(_id, AL_LOOP_POINTS_SOFT, &loopPoints[0]); + + return *this; +} + +}} diff --git a/src/Magnum/Audio/Buffer.h b/src/Magnum/Audio/Buffer.h index bf750158d..51c9b0f90 100644 --- a/src/Magnum/Audio/Buffer.h +++ b/src/Magnum/Audio/Buffer.h @@ -5,6 +5,7 @@ Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Vladimír Vondruš + Copyright © 2019 Guillaume Jacquemin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,6 +30,7 @@ * @brief Class @ref Magnum::Audio::Buffer */ +#include #include #include #include @@ -48,7 +50,7 @@ namespace Magnum { namespace Audio { /** @brief Sample buffer */ -class Buffer { +class MAGNUM_AUDIO_EXPORT Buffer { public: #ifdef MAGNUM_BUILD_DEPRECATED /** @brief @copybrief BufferFormat @@ -102,6 +104,57 @@ class Buffer { return *this; } + /** + * @brief Set buffer loop points + * @param loopStart The loop's start point in samples + * @param loopEnd The loop's end point in samples + * @return Reference to self (for method chaining) + * + * @requires_al_extension Extension @al_extension{SOFT,loop_points} + */ + Buffer& setLoopPoints(Int loopStart, Int loopEnd); + + /** + * @brief Set buffer to loop from the beginning until a certain point + * + * Equivalent to calling @ref setLoopPoints() with @p loopStart equal to + * 0. + * @param loopEnd The loop's end point in samples + * @return Reference to self (for method chaining) + * + * @requires_al_extension Extension @al_extension{SOFT,loop_points} + */ + Buffer& setLoopUntil(Int loopEnd) { + return setLoopPoints(0, loopEnd); + } + + /** + * @brief Set buffer to loop from the a certain point until the end + * + * Equivalent to calling @ref setLoopPoints() with @p loopEnd equal to + * @p INT_MAX. + * @param loopStart The loop's start point in samples + * @return Reference to self (for method chaining) + * + * @requires_al_extension Extension @al_extension{SOFT,loop_points} + */ + Buffer& setLoopSince(Int loopStart) { + return setLoopPoints(loopStart, INT_MAX); + } + + /** + * @brief Resets the loop points + * + * Equivalent to calling @ref setLoopPoints() with @p loopStart equal to + * 0, and @p loopEnd equal to @p INT_MAX. + * @return Reference to self (for method chaining) + * + * @requires_al_extension Extension @al_extension{SOFT,loop_points} + */ + Buffer& resetLoopPoints() { + return setLoopPoints(0, INT_MAX); + } + private: ALuint _id; }; diff --git a/src/Magnum/Audio/CMakeLists.txt b/src/Magnum/Audio/CMakeLists.txt index 89512713c..f269f0c3b 100644 --- a/src/Magnum/Audio/CMakeLists.txt +++ b/src/Magnum/Audio/CMakeLists.txt @@ -29,6 +29,7 @@ find_package(OpenAL REQUIRED) set(MagnumAudio_SRCS AbstractImporter.cpp Audio.cpp + Buffer.cpp BufferFormat.cpp Context.cpp Renderer.cpp diff --git a/src/Magnum/Audio/Context.cpp b/src/Magnum/Audio/Context.cpp index 47b16a2e7..aa25c62e4 100644 --- a/src/Magnum/Audio/Context.cpp +++ b/src/Magnum/Audio/Context.cpp @@ -50,6 +50,7 @@ constexpr Extension ExtensionList[]{ _extension(AL,EXT,ALAW), _extension(AL,EXT,MULAW), _extension(AL,EXT,MCFORMATS), + _extension(AL,SOFT,loop_points), _extension(ALC,EXT,ENUMERATION), _extension(ALC,SOFTX,HRTF), _extension(ALC,SOFT,HRTF) diff --git a/src/Magnum/Audio/Extensions.h b/src/Magnum/Audio/Extensions.h index a40dc3d1f..6b8ba91d4 100644 --- a/src/Magnum/Audio/Extensions.h +++ b/src/Magnum/Audio/Extensions.h @@ -84,15 +84,18 @@ namespace AL { _extension(4,AL,EXT,MULAW) // #??? _extension(5,AL,EXT,MCFORMATS) // #??? } + namespace SOFT { + _extension(6,AL,SOFT,loop_points) // #??? + } } namespace ALC { namespace EXT { - _extension_rev(6,ALC,EXT,ENUMERATION) // #??? + _extension_rev(7,ALC,EXT,ENUMERATION) // #??? } namespace SOFTX { - _extension(7,ALC,SOFTX,HRTF) // #??? + _extension(8,ALC,SOFTX,HRTF) // #??? } namespace SOFT { - _extension(8,ALC,SOFT,HRTF) // #??? + _extension(9,ALC,SOFT,HRTF) // #??? } } #undef _extension diff --git a/src/Magnum/Audio/Test/BufferALTest.cpp b/src/Magnum/Audio/Test/BufferALTest.cpp index 850a4c989..952b401fd 100644 --- a/src/Magnum/Audio/Test/BufferALTest.cpp +++ b/src/Magnum/Audio/Test/BufferALTest.cpp @@ -3,6 +3,7 @@ Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Vladimír Vondruš + Copyright © 2019 Guillaume Jacquemin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,10 +24,14 @@ DEALINGS IN THE SOFTWARE. */ +#include +#include #include #include "Magnum/Audio/Buffer.h" +#include "Magnum/Audio/BufferFormat.h" #include "Magnum/Audio/Context.h" +#include "Magnum/Audio/Extensions.h" namespace Magnum { namespace Audio { namespace Test { namespace { @@ -35,11 +40,23 @@ struct BufferALTest: TestSuite::Tester { void construct(); + void setData(); + void setLoopPoints(); + void setLoopSince(); + void setLoopUntil(); + void resetLoopPoints(); + Context _context; }; BufferALTest::BufferALTest() { - addTests({&BufferALTest::construct}); + addTests({&BufferALTest::construct, + + &BufferALTest::setData, + &BufferALTest::setLoopPoints, + &BufferALTest::setLoopSince, + &BufferALTest::setLoopUntil, + &BufferALTest::resetLoopPoints}); } void BufferALTest::construct() { @@ -47,6 +64,85 @@ void BufferALTest::construct() { CORRADE_VERIFY(buf.id() != 0); } +void BufferALTest::setData() { + Buffer buf; + constexpr char data[] { 25, 17, 24, 122, 67, 24, 48, 96 }; + + buf.setData(BufferFormat::Mono8, data, 22050); + + ALint bufSize; + alGetBufferi(buf.id(), AL_SIZE, &bufSize); + CORRADE_VERIFY(bufSize == 8); +} + +void BufferALTest::setLoopPoints() { + if(!_context.isExtensionSupported()) { + CORRADE_SKIP("Extension AL_SOFT_loop_points isn't supported on this system."); + } + + Buffer buf; + constexpr char data[] { 25, 17, 24, 122, 67, 24, 48, 96 }; + + buf.setData(BufferFormat::Mono8, data, 22050).setLoopPoints(1, 6); + + Containers::Array points{Containers::InPlaceInit, { 0, 0 }}; + alGetBufferiv(buf.id(), AL_LOOP_POINTS_SOFT, points.data()); + CORRADE_COMPARE_AS(points, + (Containers::Array{Containers::InPlaceInit, { 1, 6 }}), + TestSuite::Compare::Container>); +} + +void BufferALTest::setLoopSince() { + if(!_context.isExtensionSupported()) { + CORRADE_SKIP("Extension AL_SOFT_loop_points isn't supported on this system."); + } + + Buffer buf; + constexpr char data[] { 25, 17, 24, 122, 67, 24, 48, 96 }; + + buf.setData(BufferFormat::Mono8, data, 22050).setLoopSince(3); + + Containers::Array points{Containers::InPlaceInit, { 0, 0 }}; + alGetBufferiv(buf.id(), AL_LOOP_POINTS_SOFT, points.data()); + CORRADE_COMPARE_AS(points, + (Containers::Array{Containers::InPlaceInit, { 3, 8 }}), + TestSuite::Compare::Container>); +} + +void BufferALTest::setLoopUntil() { + if(!_context.isExtensionSupported()) { + CORRADE_SKIP("Extension AL_SOFT_loop_points isn't supported on this system."); + } + + Buffer buf; + constexpr char data[] { 25, 17, 24, 122, 67, 24, 48, 96 }; + + buf.setData(BufferFormat::Mono8, data, 22050).setLoopUntil(5); + + Containers::Array points{Containers::InPlaceInit, { 0, 0 }}; + alGetBufferiv(buf.id(), AL_LOOP_POINTS_SOFT, points.data()); + CORRADE_COMPARE_AS(points, + (Containers::Array{Containers::InPlaceInit, { 0, 5 }}), + TestSuite::Compare::Container>); +} + +void BufferALTest::resetLoopPoints() { + if(!_context.isExtensionSupported()) { + CORRADE_SKIP("Extension AL_SOFT_loop_points isn't supported on this system."); + } + + Buffer buf; + constexpr char data[] { 25, 17, 24, 122, 67, 24, 48, 96 }; + + buf.setData(BufferFormat::Mono8, data, 22050).resetLoopPoints(); + + Containers::Array points{Containers::InPlaceInit, { 0, 0 }}; + alGetBufferiv(buf.id(), AL_LOOP_POINTS_SOFT, points.data()); + CORRADE_COMPARE_AS(points, + (Containers::Array{Containers::InPlaceInit, { 0, 8 }}), + TestSuite::Compare::Container>); +} + }}}} CORRADE_TEST_MAIN(Magnum::Audio::Test::BufferALTest) diff --git a/src/MagnumExternal/OpenAL/extensions.h b/src/MagnumExternal/OpenAL/extensions.h index 3bb99bfa4..1a00a5f44 100644 --- a/src/MagnumExternal/OpenAL/extensions.h +++ b/src/MagnumExternal/OpenAL/extensions.h @@ -6,6 +6,7 @@ Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Vladimír Vondruš Copyright © 2015 Jonathan Hale + Copyright © 2019 Guillaume Jacquemin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -88,6 +89,12 @@ extern "C" { #define AL_FORMAT_71CHN32 0x1212 #endif +/* AL_SOFT_loop_points */ +#ifndef AL_SOFT_loop_points +#define AL_SOFT_loop_points 1 +#define AL_LOOP_POINTS_SOFT 0x2015 +#endif + /* ALC_SOFTX_HRTF */ #ifndef ALC_SOFTX_HRTF #define ALC_SOFTX_HRTF 1