OpenShot Library | libopenshot  0.2.6
AudioReaderSource.cpp
Go to the documentation of this file.
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
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
51 {
52  // Clear and delete the buffer
53  delete buffer;
54  buffer = NULL;
55 }
56 
57 // Get more samples from the reader
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
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
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
244 void AudioReaderSource::prepareToPlay(int, double) { }
245 
246 // Release all resources
248 
249 // Set the next read position of this source
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
259 {
260  // return the next read position
261  return position;
262 }
263 
264 // Get the total length (in samples) of this audio source
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
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
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
289 void AudioReaderSource::setBuffer (juce::AudioSampleBuffer *audio_buffer)
290 {
291  buffer = audio_buffer;
293 }
float duration
Length of time (in seconds)
Definition: ReaderBase.h:65
void setBuffer(juce::AudioSampleBuffer *audio_buffer)
Update the internal buffer used by this source.
STL namespace.
void setNextReadPosition(juce::int64 newPosition)
Set the next read position of this source.
juce::int64 getTotalLength() const
Get the total length (in samples) of this audio source.
void setLooping(bool shouldLoop)
Set if this audio source should repeat when it reaches the end.
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:97
void releaseResources()
Release all resources.
juce::int64 getNextReadPosition() const
Get the next read position of this source.
Exception when a reader is closed, and a frame is requested.
Definition: Exceptions.h:337
void AppendDebugMethod(std::string method_name, std::string arg1_name="", float arg1_value=-1.0, std::string arg2_name="", float arg2_value=-1.0, std::string arg3_name="", float arg3_value=-1.0, std::string arg4_name="", float arg4_value=-1.0, std::string arg5_name="", float arg5_value=-1.0, std::string arg6_name="", float arg6_value=-1.0)
Append debug information.
Definition: ZmqLogger.cpp:190
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
int GetSamplesPerFrame(openshot::Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Definition: Frame.cpp:536
Header file for all Exception classes.
void getNextAudioBlock(const juce::AudioSourceChannelInfo &info)
Get the next block of audio samples.
#define int64
Definition: Clip.h:35
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:111
Exception for frames that are out of bounds.
Definition: Exceptions.h:285
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method) ...
Definition: ZmqLogger.cpp:52
Header file for AudioReaderSource class.
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:46
void prepareToPlay(int, double)
Prepare to play this audio source.
bool isLooping() const
Determines if this audio source should repeat when it reaches the end.
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:83
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: ReaderBase.h:70
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:82
virtual bool IsOpen()=0
Determine if reader is open or closed.