OpenShot Library | libopenshot  0.2.5
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 "../include/AudioReaderSource.h"
32 
33 using namespace std;
34 using namespace openshot;
35 
36 // Constructor that reads samples from a reader
37 AudioReaderSource::AudioReaderSource(ReaderBase *audio_reader, int64_t starting_frame_number, int buffer_size)
38  : reader(audio_reader), frame_number(starting_frame_number), original_frame_number(starting_frame_number),
39  size(buffer_size), position(0), frame_position(0), estimated_frame(0), speed(1) {
40 
41  // Initialize an audio buffer (based on reader)
42  buffer = new juce::AudioSampleBuffer(reader->info.channels, size);
43 
44  // initialize the audio samples to zero (silence)
45  buffer->clear();
46 }
47 
48 // Destructor
50 {
51  // Clear and delete the buffer
52  delete buffer;
53  buffer = NULL;
54 }
55 
56 // Get more samples from the reader
57 void AudioReaderSource::GetMoreSamplesFromReader()
58 {
59  // Determine the amount of samples needed to fill up this buffer
60  int amount_needed = position; // replace these used samples
61  int amount_remaining = size - amount_needed; // these are unused samples, and need to be carried forward
62  if (!frame) {
63  // If no frame, load entire buffer
64  amount_needed = size;
65  amount_remaining = 0;
66  }
67 
68  // Debug
69  ZmqLogger::Instance()->AppendDebugMethod("AudioReaderSource::GetMoreSamplesFromReader", "amount_needed", amount_needed, "amount_remaining", amount_remaining);
70 
71  // Init estimated buffer equal to the current frame position (before getting more samples)
72  estimated_frame = frame_number;
73 
74  // Init new buffer
75  juce::AudioSampleBuffer *new_buffer = new juce::AudioSampleBuffer(reader->info.channels, size);
76  new_buffer->clear();
77 
78  // Move the remaining samples into new buffer (if any)
79  if (amount_remaining > 0) {
80  for (int channel = 0; channel < buffer->getNumChannels(); channel++)
81  new_buffer->addFrom(channel, 0, *buffer, channel, position, amount_remaining);
82 
83  position = amount_remaining;
84  } else
85  // reset position to 0
86  position = 0;
87 
88  // Loop through frames until buffer filled
89  while (amount_needed > 0 && speed == 1 && frame_number >= 1 && frame_number <= reader->info.video_length) {
90 
91  // Get the next frame (if position is zero)
92  if (frame_position == 0) {
93  try {
94  // Get frame object
95  frame = reader->GetFrame(frame_number);
96  frame_number = frame_number + speed;
97 
98  } catch (const ReaderClosed & e) {
99  break;
100  } catch (const TooManySeeks & e) {
101  break;
102  } catch (const OutOfBoundsFrame & e) {
103  break;
104  }
105  }
106 
107  bool frame_completed = false;
108  int amount_to_copy = 0;
109  if (frame)
110  amount_to_copy = frame->GetAudioSamplesCount() - frame_position;
111  if (amount_to_copy > amount_needed) {
112  // Don't copy too many samples (we don't want to overflow the buffer)
113  amount_to_copy = amount_needed;
114  amount_needed = 0;
115  } else {
116  // Not enough to fill the buffer (so use the entire frame)
117  amount_needed -= amount_to_copy;
118  frame_completed = true;
119  }
120 
121  // Load all of its samples into the buffer
122  if (frame)
123  for (int channel = 0; channel < new_buffer->getNumChannels(); channel++)
124  new_buffer->addFrom(channel, position, *frame->GetAudioSampleBuffer(), channel, frame_position, amount_to_copy);
125 
126  // Adjust remaining samples
127  position += amount_to_copy;
128  if (frame_completed)
129  // Reset frame buffer position (which will load a new frame on the next loop)
130  frame_position = 0;
131  else
132  // Continue tracking the current frame's position
133  frame_position += amount_to_copy;
134  }
135 
136  // Delete old buffer
137  buffer->clear();
138  delete buffer;
139 
140  // Replace buffer and reset position
141  buffer = new_buffer;
142  position = 0;
143 }
144 
145 // Reverse an audio buffer
146 juce::AudioSampleBuffer* AudioReaderSource::reverse_buffer(juce::AudioSampleBuffer* buffer)
147 {
148  int number_of_samples = buffer->getNumSamples();
149  int channels = buffer->getNumChannels();
150 
151  // Debug
152  ZmqLogger::Instance()->AppendDebugMethod("AudioReaderSource::reverse_buffer", "number_of_samples", number_of_samples, "channels", channels);
153 
154  // Reverse array (create new buffer to hold the reversed version)
155  juce::AudioSampleBuffer *reversed = new juce::AudioSampleBuffer(channels, number_of_samples);
156  reversed->clear();
157 
158  for (int channel = 0; channel < channels; channel++)
159  {
160  int n=0;
161  for (int s = number_of_samples - 1; s >= 0; s--, n++)
162  reversed->getWritePointer(channel)[n] = buffer->getWritePointer(channel)[s];
163  }
164 
165  // Copy the samples back to the original array
166  buffer->clear();
167  // Loop through channels, and get audio samples
168  for (int channel = 0; channel < channels; channel++)
169  // Get the audio samples for this channel
170  buffer->addFrom(channel, 0, reversed->getReadPointer(channel), number_of_samples, 1.0f);
171 
172  delete reversed;
173  reversed = NULL;
174 
175  // return pointer or passed in object (so this method can be chained together)
176  return buffer;
177 }
178 
179 // Get the next block of audio samples
180 void AudioReaderSource::getNextAudioBlock(const juce::AudioSourceChannelInfo& info)
181 {
182  int buffer_samples = buffer->getNumSamples();
183  int buffer_channels = buffer->getNumChannels();
184 
185  if (info.numSamples > 0) {
186  int number_to_copy = 0;
187 
188  // Do we need more samples?
189  if (speed == 1) {
190  // Only refill buffers if speed is normal
191  if ((reader && reader->IsOpen() && !frame) or
192  (reader && reader->IsOpen() && buffer_samples - position < info.numSamples))
193  // Refill buffer from reader
194  GetMoreSamplesFromReader();
195  } else {
196  // Fill buffer with silence and clear current frame
197  info.buffer->clear();
198  return;
199  }
200 
201  // Determine how many samples to copy
202  if (position + info.numSamples <= buffer_samples)
203  {
204  // copy the full amount requested
205  number_to_copy = info.numSamples;
206  }
207  else if (position > buffer_samples)
208  {
209  // copy nothing
210  number_to_copy = 0;
211  }
212  else if (buffer_samples - position > 0)
213  {
214  // only copy what is left in the buffer
215  number_to_copy = buffer_samples - position;
216  }
217  else
218  {
219  // copy nothing
220  number_to_copy = 0;
221  }
222 
223 
224  // Determine if any samples need to be copied
225  if (number_to_copy > 0)
226  {
227  // Debug
228  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);
229 
230  // Loop through each channel and copy some samples
231  for (int channel = 0; channel < buffer_channels; channel++)
232  info.buffer->copyFrom(channel, info.startSample, *buffer, channel, position, number_to_copy);
233 
234  // Update the position of this audio source
235  position += number_to_copy;
236  }
237 
238  // Adjust estimate frame number (the estimated frame number that is being played)
239  estimated_samples_per_frame = Frame::GetSamplesPerFrame(estimated_frame, reader->info.fps, reader->info.sample_rate, buffer_channels);
240  estimated_frame += double(info.numSamples) / double(estimated_samples_per_frame);
241  }
242 }
243 
244 // Prepare to play this audio source
245 void AudioReaderSource::prepareToPlay(int, double) { }
246 
247 // Release all resources
249 
250 // Set the next read position of this source
251 void AudioReaderSource::setNextReadPosition (juce::int64 newPosition)
252 {
253  // set position (if the new position is in range)
254  if (newPosition >= 0 && newPosition < buffer->getNumSamples())
255  position = newPosition;
256 }
257 
258 // Get the next read position of this source
260 {
261  // return the next read position
262  return position;
263 }
264 
265 // Get the total length (in samples) of this audio source
267 {
268  // Get the length
269  if (reader)
270  return reader->info.sample_rate * reader->info.duration;
271  else
272  return 0;
273 }
274 
275 // Determines if this audio source should repeat when it reaches the end
277 {
278  // return if this source is looping
279  return repeat;
280 }
281 
282 // Set if this audio source should repeat when it reaches the end
283 void AudioReaderSource::setLooping (bool shouldLoop)
284 {
285  // Set the repeat flag
286  repeat = shouldLoop;
287 }
288 
289 // Update the internal buffer used by this source
290 void AudioReaderSource::setBuffer (juce::AudioSampleBuffer *audio_buffer)
291 {
292  buffer = audio_buffer;
294 }
openshot::AudioReaderSource::isLooping
bool isLooping() const
Determines if this audio source should repeat when it reaches the end.
Definition: AudioReaderSource.cpp:276
openshot::ReaderInfo::sample_rate
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:82
openshot::ReaderBase::GetFrame
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: AudioBufferSource.h:39
openshot::AudioReaderSource::~AudioReaderSource
~AudioReaderSource()
Destructor.
Definition: AudioReaderSource.cpp:49
openshot::AudioReaderSource::setLooping
void setLooping(bool shouldLoop)
Set if this audio source should repeat when it reaches the end.
Definition: AudioReaderSource.cpp:283
openshot::ReaderBase::info
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:111
openshot::AudioReaderSource::prepareToPlay
void prepareToPlay(int, double)
Prepare to play this audio source.
Definition: AudioReaderSource.cpp:245
openshot::AudioReaderSource::setBuffer
void setBuffer(juce::AudioSampleBuffer *audio_buffer)
Update the internal buffer used by this source.
Definition: AudioReaderSource.cpp:290
openshot::ReaderInfo::duration
float duration
Length of time (in seconds)
Definition: ReaderBase.h:65
openshot::AudioReaderSource::setNextReadPosition
void setNextReadPosition(juce::int64 newPosition)
Set the next read position of this source.
Definition: AudioReaderSource.cpp:251
openshot::TooManySeeks
Exception when too many seek attempts happen.
Definition: Exceptions.h:370
openshot::OutOfBoundsFrame
Exception for frames that are out of bounds.
Definition: Exceptions.h:286
openshot::ReaderBase::IsOpen
virtual bool IsOpen()=0
Determine if reader is open or closed.
openshot::AudioReaderSource::getTotalLength
juce::int64 getTotalLength() const
Get the total length (in samples) of this audio source.
Definition: AudioReaderSource.cpp:266
openshot::Frame::GetSamplesPerFrame
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:547
openshot::ZmqLogger::Instance
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition: ZmqLogger.cpp:45
openshot::ZmqLogger::AppendDebugMethod
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:179
openshot::ReaderClosed
Exception when a reader is closed, and a frame is requested.
Definition: Exceptions.h:338
openshot::AudioReaderSource::getNextAudioBlock
void getNextAudioBlock(const juce::AudioSourceChannelInfo &info)
Get the next block of audio samples.
Definition: AudioReaderSource.cpp:180
openshot::ReaderInfo::fps
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: ReaderBase.h:70
openshot::ReaderBase
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:98
openshot::AudioReaderSource::getNextReadPosition
juce::int64 getNextReadPosition() const
Get the next read position of this source.
Definition: AudioReaderSource.cpp:259
openshot::AudioReaderSource::releaseResources
void releaseResources()
Release all resources.
Definition: AudioReaderSource.cpp:248
openshot::ReaderInfo::channels
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:83