LMMS
Loading...
Searching...
No Matches
juce_MemoryAudioSource.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26MemoryAudioSource::MemoryAudioSource (AudioBuffer<float>& bufferToUse, bool copyMemory, bool shouldLoop)
27 : isCurrentlyLooping (shouldLoop)
28{
29 if (copyMemory)
30 buffer.makeCopyOf (bufferToUse);
31 else
32 buffer.setDataToReferTo (bufferToUse.getArrayOfWritePointers(),
33 bufferToUse.getNumChannels(),
34 bufferToUse.getNumSamples());
35}
36
37//==============================================================================
38void MemoryAudioSource::prepareToPlay (int /*samplesPerBlockExpected*/, double /*sampleRate*/)
39{
40 position = 0;
41}
42
44
46{
47 if (buffer.getNumSamples() == 0)
48 {
49 bufferToFill.clearActiveBufferRegion();
50 return;
51 }
52
53 auto& dst = *bufferToFill.buffer;
54 auto channels = jmin (dst.getNumChannels(), buffer.getNumChannels());
55 int max = 0, pos = 0;
56 auto n = buffer.getNumSamples();
57 auto m = bufferToFill.numSamples;
58
59 int i = position;
60 for (; (i < n || isCurrentlyLooping) && (pos < m); i += max)
61 {
62 max = jmin (m - pos, n - (i % n));
63
64 int ch = 0;
65 for (; ch < channels; ++ch)
66 dst.copyFrom (ch, bufferToFill.startSample + pos, buffer, ch, i % n, max);
67
68 for (; ch < dst.getNumChannels(); ++ch)
69 dst.clear (ch, bufferToFill.startSample + pos, max);
70
71 pos += max;
72 }
73
74 if (pos < m)
75 dst.clear (bufferToFill.startSample + pos, m - pos);
76
77 position = i;
78}
79
80//==============================================================================
82{
83 position = (int) newPosition;
84}
85
90
92{
93 return buffer.getNumSamples();
94}
95
96//==============================================================================
98{
99 return isCurrentlyLooping;
100}
101
102void MemoryAudioSource::setLooping (bool shouldLoop)
103{
104 isCurrentlyLooping = shouldLoop;
105}
106
107//==============================================================================
108//==============================================================================
109#if JUCE_UNIT_TESTS
110
111static bool operator== (const AudioBuffer<float>& a, const AudioBuffer<float>& b)
112{
113 if (a.getNumChannels() != b.getNumChannels())
114 return false;
115
116 for (int channel = 0; channel < a.getNumChannels(); ++channel)
117 {
118 auto* aPtr = a.getReadPointer (channel);
119 auto* bPtr = b.getReadPointer (channel);
120
121 if (std::vector<float> (aPtr, aPtr + a.getNumSamples())
122 != std::vector<float> (bPtr, bPtr + b.getNumSamples()))
123 {
124 return false;
125 }
126 }
127
128 return true;
129}
130
131struct MemoryAudioSourceTests : public UnitTest
132{
133 MemoryAudioSourceTests() : UnitTest ("MemoryAudioSource", UnitTestCategories::audio) {}
134
135 void runTest() override
136 {
137 constexpr int blockSize = 512;
138 AudioBuffer<float> bufferToFill { 2, blockSize };
139 AudioSourceChannelInfo channelInfo { bufferToFill };
140
141 beginTest ("A zero-length buffer produces silence, whether or not looping is enabled");
142 {
143 for (const bool enableLooping : { false, true })
144 {
145 AudioBuffer<float> buffer;
146 MemoryAudioSource source { buffer, true, false };
147 source.setLooping (enableLooping);
148 source.prepareToPlay (blockSize, 44100.0);
149
150 for (int i = 0; i < 2; ++i)
151 {
152 play (source, channelInfo);
153 expect (isSilent (bufferToFill));
154 }
155 }
156 }
157
158 beginTest ("A short buffer without looping is played once and followed by silence");
159 {
160 auto buffer = getShortBuffer();
161 MemoryAudioSource source { buffer, true, false };
162 source.setLooping (false);
163 source.prepareToPlay (blockSize, 44100.0);
164
165 play (source, channelInfo);
166
167 auto copy = buffer;
168 copy.setSize (buffer.getNumChannels(), blockSize, true, true, false);
169
170 expect (bufferToFill == copy);
171
172 play (source, channelInfo);
173
174 expect (isSilent (bufferToFill));
175 }
176
177 beginTest ("A short buffer with looping is played multiple times");
178 {
179 auto buffer = getShortBuffer();
180 MemoryAudioSource source { buffer, true, false };
181 source.setLooping (true);
182 source.prepareToPlay (blockSize, 44100.0);
183
184 play (source, channelInfo);
185
186 for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
187 expect (bufferToFill.getSample (0, sample + buffer.getNumSamples()) == buffer.getSample (0, sample));
188
189 expect (! isSilent (bufferToFill));
190 }
191
192 beginTest ("A long buffer without looping is played once");
193 {
194 auto buffer = getLongBuffer();
195 MemoryAudioSource source { buffer, true, false };
196 source.setLooping (false);
197 source.prepareToPlay (blockSize, 44100.0);
198
199 play (source, channelInfo);
200
201 auto copy = buffer;
202 copy.setSize (buffer.getNumChannels(), blockSize, true, true, false);
203
204 expect (bufferToFill == copy);
205
206 for (int i = 0; i < 10; ++i)
207 play (source, channelInfo);
208
209 expect (isSilent (bufferToFill));
210 }
211
212 beginTest ("A long buffer with looping is played multiple times");
213 {
214 auto buffer = getLongBuffer();
215 MemoryAudioSource source { buffer, true, false };
216 source.setLooping (true);
217 source.prepareToPlay (blockSize, 44100.0);
218
219 for (int i = 0; i < 100; ++i)
220 {
221 play (source, channelInfo);
222 expect (bufferToFill.getSample (0, 0) == buffer.getSample (0, (i * blockSize) % buffer.getNumSamples()));
223 }
224 }
225 }
226
227 static AudioBuffer<float> getTestBuffer (int length)
228 {
229 AudioBuffer<float> buffer { 2, length };
230
231 for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
232 for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
233 buffer.setSample (channel, sample, jmap ((float) sample, 0.0f, (float) length, -1.0f, 1.0f));
234
235 return buffer;
236 }
237
238 static AudioBuffer<float> getShortBuffer() { return getTestBuffer (5); }
239 static AudioBuffer<float> getLongBuffer() { return getTestBuffer (1000); }
240
241 static void play (MemoryAudioSource& source, AudioSourceChannelInfo& info)
242 {
243 info.clearActiveBufferRegion();
244 source.getNextAudioBlock (info);
245 }
246
247 static bool isSilent (const AudioBuffer<float>& b)
248 {
249 for (int channel = 0; channel < b.getNumChannels(); ++channel)
250 if (b.findMinMax (channel, 0, b.getNumSamples()) != Range<float>{})
251 return false;
252
253 return true;
254 }
255};
256
257static MemoryAudioSourceTests memoryAudioSourceTests;
258
259#endif
260
261} // namespace juce
#define copy(x)
Definition ADnoteParameters.cpp:1011
Type jmin(const Type a, const Type b)
Definition MathsFunctions.h:60
uint8_t a
Definition Spc_Cpu.h:141
Definition juce_AudioSampleBuffer.h:34
int getNumChannels() const noexcept
Definition juce_AudioSampleBuffer.h:236
int getNumSamples() const noexcept
Definition juce_AudioSampleBuffer.h:242
Type ** getArrayOfWritePointers() noexcept
Definition juce_AudioSampleBuffer.h:342
bool isLooping() const override
Definition juce_MemoryAudioSource.cpp:97
bool isCurrentlyLooping
Definition juce_MemoryAudioSource.h:76
int64 getNextReadPosition() const override
Definition juce_MemoryAudioSource.cpp:86
MemoryAudioSource(AudioBuffer< float > &audioBuffer, bool copyMemory, bool shouldLoop=false)
Definition juce_MemoryAudioSource.cpp:26
void setNextReadPosition(int64 newPosition) override
Definition juce_MemoryAudioSource.cpp:81
int64 getTotalLength() const override
Definition juce_MemoryAudioSource.cpp:91
void prepareToPlay(int samplesPerBlockExpected, double sampleRate) override
Definition juce_MemoryAudioSource.cpp:38
void setLooping(bool shouldLoop) override
Definition juce_MemoryAudioSource.cpp:102
int position
Definition juce_MemoryAudioSource.h:75
AudioBuffer< float > buffer
Definition juce_MemoryAudioSource.h:74
void getNextAudioBlock(const AudioSourceChannelInfo &bufferToFill) override
Definition juce_MemoryAudioSource.cpp:45
void releaseResources() override
Definition juce_MemoryAudioSource.cpp:43
unsigned * m
Definition inflate.c:1559
register unsigned i
Definition inflate.c:1575
struct backing_store_struct * info
Definition jmemsys.h:183
JOCTET * buffer
Definition juce_JPEGLoader.cpp:302
Definition carla_juce.cpp:31
constexpr Type jmap(Type value0To1, Type targetRangeMin, Type targetRangeMax)
Definition juce_MathsFunctions.h:120
long long int64
Definition juce_MathsFunctions.h:54
bool isSilent(const SampleFrame *src, int frames)
Definition MixHelpers.cpp:72
#define max(x, y)
Definition os.h:78
png_uint_32 length
Definition png.c:2247
Definition juce_AudioSource.h:33
int numSamples
Definition juce_AudioSource.h:81
void clearActiveBufferRegion() const
Definition juce_AudioSource.h:84
AudioBuffer< float > * buffer
Definition juce_AudioSource.h:73
int startSample
Definition juce_AudioSource.h:77
signed int sample
Definition tap_dynamics_m.c:41
int n
Definition crypt.c:458
b
Definition crypt.c:628
typedef int(UZ_EXP MsgFn)()