OpenShot Library | libopenshot  0.1.9
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 }
void setBuffer(AudioSampleBuffer *audio_buffer)
Update the internal buffer used by this source.
float duration
Length of time (in seconds)
Definition: ReaderBase.h:64
void getNextAudioBlock(const AudioSourceChannelInfo &info)
Get the next block of audio samples.
void setNextReadPosition(int64 newPosition)
Set the next read position of this 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:95
void releaseResources()
Release all resources.
Exception when a reader is closed, and a frame is requested.
Definition: Exceptions.h:234
virtual std::shared_ptr< Frame > GetFrame(int64_t number)=0
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
int64 getNextReadPosition() const
Get the next read position of this source.
ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:111
Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: ReaderBase.h:69
Exception for frames that are out of bounds.
Definition: Exceptions.h:202
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method) ...
Definition: ZmqLogger.cpp:38
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:82
int64 getTotalLength() const
Get the total length (in samples) of this audio source.
int GetSamplesPerFrame(Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Definition: Frame.cpp:505
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:81
Exception when too many seek attempts happen.
Definition: Exceptions.h:254
virtual bool IsOpen()=0
Determine if reader is open or closed.