1 /**
2 * @file
3 * @brief Source file for AudioReaderSource class
4 * @author Jonathan Thomas <jonathan@openshot.org>
5 *
6 * @ref License
7 */
8
9 /* LICENSE
10 *
11 * Copyright (c) 2008-2019 OpenShot Studios, LLC
12 * <http://www.openshotstudios.com/>. This file is part of
13 * OpenShot Library (libopenshot), an open-source project dedicated to
14 * delivering high quality video editing and animation solutions to the
15 * world. For more information visit <http://www.openshot.org/>.
16 *
17 * OpenShot Library (libopenshot) is free software: you can redistribute it
18 * and/or modify it under the terms of the GNU Lesser General Public License
19 * as published by the Free Software Foundation, either version 3 of the
20 * License, or (at your option) any later version.
21 *
22 * OpenShot Library (libopenshot) is distributed in the hope that it will be
23 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public License
28 * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
29 */
30
31 #include "AudioReaderSource.h"
32 #include "Exceptions.h"
33
34 using namespace std;
35 using namespace openshot;
36
37 // Constructor that reads samples from a reader
AudioReaderSource(ReaderBase * audio_reader,int64_t starting_frame_number,int buffer_size)38 AudioReaderSource::AudioReaderSource(ReaderBase *audio_reader, int64_t starting_frame_number, int buffer_size)
39 : reader(audio_reader), frame_number(starting_frame_number),
40 size(buffer_size), position(0), frame_position(0), estimated_frame(0), speed(1) {
41
42 // Initialize an audio buffer (based on reader)
43 buffer = new juce::AudioSampleBuffer(reader->info.channels, size);
44
45 // initialize the audio samples to zero (silence)
46 buffer->clear();
47 }
48
49 // Destructor
~AudioReaderSource()50 AudioReaderSource::~AudioReaderSource()
51 {
52 // Clear and delete the buffer
53 delete buffer;
54 buffer = NULL;
55 }
56
57 // Get more samples from the reader
GetMoreSamplesFromReader()58 void AudioReaderSource::GetMoreSamplesFromReader()
59 {
60 // Determine the amount of samples needed to fill up this buffer
61 int amount_needed = position; // replace these used samples
62 int amount_remaining = size - amount_needed; // these are unused samples, and need to be carried forward
63 if (!frame) {
64 // If no frame, load entire buffer
65 amount_needed = size;
66 amount_remaining = 0;
67 }
68
69 // Debug
70 ZmqLogger::Instance()->AppendDebugMethod("AudioReaderSource::GetMoreSamplesFromReader", "amount_needed", amount_needed, "amount_remaining", amount_remaining);
71
72 // Init estimated buffer equal to the current frame position (before getting more samples)
73 estimated_frame = frame_number;
74
75 // Init new buffer
76 juce::AudioSampleBuffer *new_buffer = new juce::AudioSampleBuffer(reader->info.channels, size);
77 new_buffer->clear();
78
79 // Move the remaining samples into new buffer (if any)
80 if (amount_remaining > 0) {
81 for (int channel = 0; channel < buffer->getNumChannels(); channel++)
82 new_buffer->addFrom(channel, 0, *buffer, channel, position, amount_remaining);
83
84 position = amount_remaining;
85 } else
86 // reset position to 0
87 position = 0;
88
89 // Loop through frames until buffer filled
90 while (amount_needed > 0 && speed == 1 && frame_number >= 1 && frame_number <= reader->info.video_length) {
91
92 // Get the next frame (if position is zero)
93 if (frame_position == 0) {
94 try {
95 // Get frame object
96 frame = reader->GetFrame(frame_number);
97 frame_number = frame_number + speed;
98
99 } catch (const ReaderClosed & e) {
100 break;
101 } catch (const OutOfBoundsFrame & e) {
102 break;
103 }
104 }
105
106 bool frame_completed = false;
107 int amount_to_copy = 0;
108 if (frame)
109 amount_to_copy = frame->GetAudioSamplesCount() - frame_position;
110 if (amount_to_copy > amount_needed) {
111 // Don't copy too many samples (we don't want to overflow the buffer)
112 amount_to_copy = amount_needed;
113 amount_needed = 0;
114 } else {
115 // Not enough to fill the buffer (so use the entire frame)
116 amount_needed -= amount_to_copy;
117 frame_completed = true;
118 }
119
120 // Load all of its samples into the buffer
121 if (frame)
122 for (int channel = 0; channel < new_buffer->getNumChannels(); channel++)
123 new_buffer->addFrom(channel, position, *frame->GetAudioSampleBuffer(), channel, frame_position, amount_to_copy);
124
125 // Adjust remaining samples
126 position += amount_to_copy;
127 if (frame_completed)
128 // Reset frame buffer position (which will load a new frame on the next loop)
129 frame_position = 0;
130 else
131 // Continue tracking the current frame's position
132 frame_position += amount_to_copy;
133 }
134
135 // Delete old buffer
136 buffer->clear();
137 delete buffer;
138
139 // Replace buffer and reset position
140 buffer = new_buffer;
141 position = 0;
142 }
143
144 // Reverse an audio buffer
reverse_buffer(juce::AudioSampleBuffer * buffer)145 juce::AudioSampleBuffer* AudioReaderSource::reverse_buffer(juce::AudioSampleBuffer* buffer)
146 {
147 int number_of_samples = buffer->getNumSamples();
148 int channels = buffer->getNumChannels();
149
150 // Debug
151 ZmqLogger::Instance()->AppendDebugMethod("AudioReaderSource::reverse_buffer", "number_of_samples", number_of_samples, "channels", channels);
152
153 // Reverse array (create new buffer to hold the reversed version)
154 juce::AudioSampleBuffer *reversed = new juce::AudioSampleBuffer(channels, number_of_samples);
155 reversed->clear();
156
157 for (int channel = 0; channel < channels; channel++)
158 {
159 int n=0;
160 for (int s = number_of_samples - 1; s >= 0; s--, n++)
161 reversed->getWritePointer(channel)[n] = buffer->getWritePointer(channel)[s];
162 }
163
164 // Copy the samples back to the original array
165 buffer->clear();
166 // Loop through channels, and get audio samples
167 for (int channel = 0; channel < channels; channel++)
168 // Get the audio samples for this channel
169 buffer->addFrom(channel, 0, reversed->getReadPointer(channel), number_of_samples, 1.0f);
170
171 delete reversed;
172 reversed = NULL;
173
174 // return pointer or passed in object (so this method can be chained together)
175 return buffer;
176 }
177
178 // Get the next block of audio samples
getNextAudioBlock(const juce::AudioSourceChannelInfo & info)179 void AudioReaderSource::getNextAudioBlock(const juce::AudioSourceChannelInfo& info)
180 {
181 int buffer_samples = buffer->getNumSamples();
182 int buffer_channels = buffer->getNumChannels();
183
184 if (info.numSamples > 0) {
185 int number_to_copy = 0;
186
187 // Do we need more samples?
188 if (speed == 1) {
189 // Only refill buffers if speed is normal
190 if ((reader && reader->IsOpen() && !frame) or
191 (reader && reader->IsOpen() && buffer_samples - position < info.numSamples))
192 // Refill buffer from reader
193 GetMoreSamplesFromReader();
194 } else {
195 // Fill buffer with silence and clear current frame
196 info.buffer->clear();
197 return;
198 }
199
200 // Determine how many samples to copy
201 if (position + info.numSamples <= buffer_samples)
202 {
203 // copy the full amount requested
204 number_to_copy = info.numSamples;
205 }
206 else if (position > buffer_samples)
207 {
208 // copy nothing
209 number_to_copy = 0;
210 }
211 else if (buffer_samples - position > 0)
212 {
213 // only copy what is left in the buffer
214 number_to_copy = buffer_samples - position;
215 }
216 else
217 {
218 // copy nothing
219 number_to_copy = 0;
220 }
221
222
223 // Determine if any samples need to be copied
224 if (number_to_copy > 0)
225 {
226 // Debug
227 ZmqLogger::Instance()->AppendDebugMethod("AudioReaderSource::getNextAudioBlock", "number_to_copy", number_to_copy, "buffer_samples", buffer_samples, "buffer_channels", buffer_channels, "info.numSamples", info.numSamples, "speed", speed, "position", position);
228
229 // Loop through each channel and copy some samples
230 for (int channel = 0; channel < buffer_channels; channel++)
231 info.buffer->copyFrom(channel, info.startSample, *buffer, channel, position, number_to_copy);
232
233 // Update the position of this audio source
234 position += number_to_copy;
235 }
236
237 // Adjust estimate frame number (the estimated frame number that is being played)
238 estimated_samples_per_frame = Frame::GetSamplesPerFrame(estimated_frame, reader->info.fps, reader->info.sample_rate, buffer_channels);
239 estimated_frame += double(info.numSamples) / double(estimated_samples_per_frame);
240 }
241 }
242
243 // Prepare to play this audio source
prepareToPlay(int,double)244 void AudioReaderSource::prepareToPlay(int, double) { }
245
246 // Release all resources
releaseResources()247 void AudioReaderSource::releaseResources() { }
248
249 // Set the next read position of this source
setNextReadPosition(juce::int64 newPosition)250 void AudioReaderSource::setNextReadPosition (juce::int64 newPosition)
251 {
252 // set position (if the new position is in range)
253 if (newPosition >= 0 && newPosition < buffer->getNumSamples())
254 position = newPosition;
255 }
256
257 // Get the next read position of this source
getNextReadPosition() const258 juce::int64 AudioReaderSource::getNextReadPosition() const
259 {
260 // return the next read position
261 return position;
262 }
263
264 // Get the total length (in samples) of this audio source
getTotalLength() const265 juce::int64 AudioReaderSource::getTotalLength() const
266 {
267 // Get the length
268 if (reader)
269 return reader->info.sample_rate * reader->info.duration;
270 else
271 return 0;
272 }
273
274 // Determines if this audio source should repeat when it reaches the end
isLooping() const275 bool AudioReaderSource::isLooping() const
276 {
277 // return if this source is looping
278 return repeat;
279 }
280
281 // Set if this audio source should repeat when it reaches the end
setLooping(bool shouldLoop)282 void AudioReaderSource::setLooping (bool shouldLoop)
283 {
284 // Set the repeat flag
285 repeat = shouldLoop;
286 }
287
288 // Update the internal buffer used by this source
setBuffer(juce::AudioSampleBuffer * audio_buffer)289 void AudioReaderSource::setBuffer (juce::AudioSampleBuffer *audio_buffer)
290 {
291 buffer = audio_buffer;
292 setNextReadPosition(0);
293 }
294