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