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 }
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:179
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:547
void getNextAudioBlock(const juce::AudioSourceChannelInfo &info)
Get the next block of audio samples.
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:45
This namespace is the default namespace for all code in the openshot library.
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
Exception when too many seek attempts happen.
Definition: Exceptions.h:369
virtual bool IsOpen()=0
Determine if reader is open or closed.