2011-10-11 08:44:27 -05:00
|
|
|
/**
|
|
|
|
|
* \file
|
|
|
|
|
* \brief Source code for the Frame class
|
|
|
|
|
* \author Copyright (c) 2011 Jonathan Thomas
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "../include/Frame.h"
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
using namespace openshot;
|
|
|
|
|
|
|
|
|
|
// Constructor - blank frame (300x200 blank image, 48kHz audio silence)
|
2012-08-22 17:31:12 -05:00
|
|
|
Frame::Frame() : number(1), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(2), wave_image(NULL)
|
2011-10-11 08:44:27 -05:00
|
|
|
{
|
|
|
|
|
// Init the image magic and audio buffer
|
2012-08-15 17:27:14 -05:00
|
|
|
image = new Magick::Image(Magick::Geometry(1,1), Magick::Color("red"));
|
2012-07-02 00:51:10 -05:00
|
|
|
audio = new juce::AudioSampleBuffer(channels, 1600);
|
2011-10-11 08:44:27 -05:00
|
|
|
|
|
|
|
|
// initialize the audio samples to zero (silence)
|
|
|
|
|
audio->clear();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Constructor - image only (48kHz audio silence)
|
2011-12-11 20:42:50 -06:00
|
|
|
Frame::Frame(int number, int width, int height, string color)
|
2012-08-22 17:31:12 -05:00
|
|
|
: number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(2), wave_image(NULL)
|
2011-10-11 08:44:27 -05:00
|
|
|
{
|
|
|
|
|
// Init the image magic and audio buffer
|
2012-08-15 17:27:14 -05:00
|
|
|
image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color));
|
2012-07-02 00:51:10 -05:00
|
|
|
audio = new juce::AudioSampleBuffer(channels, 1600);
|
2011-10-11 08:44:27 -05:00
|
|
|
|
|
|
|
|
// initialize the audio samples to zero (silence)
|
|
|
|
|
audio->clear();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Constructor - image only from pixel array (48kHz audio silence)
|
2011-10-24 08:22:21 -05:00
|
|
|
Frame::Frame(int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels)
|
2012-08-22 17:31:12 -05:00
|
|
|
: number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(2), wave_image(NULL)
|
2011-10-11 08:44:27 -05:00
|
|
|
{
|
|
|
|
|
// Init the image magic and audio buffer
|
|
|
|
|
image = new Magick::Image(width, height, map, type, pixels);
|
2012-07-02 00:51:10 -05:00
|
|
|
audio = new juce::AudioSampleBuffer(channels, 1600);
|
2011-10-11 08:44:27 -05:00
|
|
|
|
|
|
|
|
// initialize the audio samples to zero (silence)
|
|
|
|
|
audio->clear();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Constructor - audio only (300x200 blank image)
|
2011-12-11 20:42:50 -06:00
|
|
|
Frame::Frame(int number, int samples, int channels) :
|
2012-08-22 17:31:12 -05:00
|
|
|
number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(channels), wave_image(NULL)
|
2011-10-11 08:44:27 -05:00
|
|
|
{
|
|
|
|
|
// Init the image magic and audio buffer
|
2012-08-15 17:27:14 -05:00
|
|
|
image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color("white"));
|
2011-10-11 08:44:27 -05:00
|
|
|
audio = new juce::AudioSampleBuffer(channels, samples);
|
|
|
|
|
|
|
|
|
|
// initialize the audio samples to zero (silence)
|
|
|
|
|
audio->clear();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Constructor - image & audio
|
2011-12-11 20:42:50 -06:00
|
|
|
Frame::Frame(int number, int width, int height, string color, int samples, int channels)
|
2012-08-22 17:31:12 -05:00
|
|
|
: number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(channels), wave_image(NULL)
|
2011-10-11 08:44:27 -05:00
|
|
|
{
|
|
|
|
|
// Init the image magic and audio buffer
|
2012-08-15 17:27:14 -05:00
|
|
|
image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color));
|
2011-10-11 08:44:27 -05:00
|
|
|
audio = new juce::AudioSampleBuffer(channels, samples);
|
|
|
|
|
|
|
|
|
|
// initialize the audio samples to zero (silence)
|
|
|
|
|
audio->clear();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Destructor
|
|
|
|
|
Frame::~Frame()
|
|
|
|
|
{
|
|
|
|
|
// deallocate image and audio memory
|
|
|
|
|
DeletePointers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy constructor
|
|
|
|
|
Frame::Frame ( const Frame &other )
|
|
|
|
|
{
|
|
|
|
|
// copy pointers and data
|
|
|
|
|
DeepCopy(other);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assignment operator
|
|
|
|
|
Frame& Frame::operator= (const Frame& other)
|
|
|
|
|
{
|
|
|
|
|
if (this != &other) {
|
|
|
|
|
// deallocate image and audio memory
|
|
|
|
|
DeletePointers();
|
|
|
|
|
|
|
|
|
|
// copy pointers and data
|
|
|
|
|
DeepCopy(other);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return this instance
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy data and pointers from another Frame instance
|
|
|
|
|
void Frame::DeepCopy(const Frame& other)
|
|
|
|
|
{
|
|
|
|
|
number = other.number;
|
|
|
|
|
image = new Magick::Image(*(other.image));
|
|
|
|
|
audio = new juce::AudioSampleBuffer(*(other.audio));
|
2011-12-11 20:42:50 -06:00
|
|
|
pixel_ratio = Fraction(other.pixel_ratio.num, other.pixel_ratio.den);
|
|
|
|
|
sample_rate = other.sample_rate;
|
2012-07-02 00:51:10 -05:00
|
|
|
channels = other.channels;
|
2011-10-11 08:44:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Deallocate image and audio memory
|
|
|
|
|
void Frame::DeletePointers()
|
|
|
|
|
{
|
|
|
|
|
// deallocate image memory
|
|
|
|
|
delete image;
|
|
|
|
|
image = NULL;
|
|
|
|
|
delete audio;
|
|
|
|
|
audio = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Display the frame image to the screen (primarily used for debugging reasons)
|
|
|
|
|
void Frame::Display()
|
|
|
|
|
{
|
2011-12-11 20:42:50 -06:00
|
|
|
// Make a copy of the image (since we might resize it)
|
|
|
|
|
Magick::Image copy;
|
|
|
|
|
copy = *image;
|
|
|
|
|
|
2011-10-27 11:38:58 -05:00
|
|
|
// display the image (if any)
|
2011-12-11 20:42:50 -06:00
|
|
|
if (copy.size().width() > 1 && copy.size().height() > 1)
|
|
|
|
|
{
|
|
|
|
|
// Resize image (if needed)
|
|
|
|
|
if (pixel_ratio.num != 1 || pixel_ratio.den != 1)
|
|
|
|
|
{
|
|
|
|
|
// Calculate correct DAR (display aspect ratio)
|
|
|
|
|
int new_width = copy.size().width();
|
|
|
|
|
int new_height = copy.size().height() * pixel_ratio.Reciprocal().ToDouble();
|
|
|
|
|
|
|
|
|
|
// Resize image
|
|
|
|
|
Magick::Geometry new_size(new_width, new_height);
|
|
|
|
|
new_size.aspect(true);
|
|
|
|
|
copy.resize(new_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Disply image
|
|
|
|
|
copy.display();
|
|
|
|
|
}
|
2011-10-11 08:44:27 -05:00
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:31:12 -05:00
|
|
|
// Get an audio waveform image
|
|
|
|
|
Magick::Image* Frame::GetWaveform(int width, int height)
|
2011-10-24 17:32:26 -05:00
|
|
|
{
|
2012-08-22 17:31:12 -05:00
|
|
|
// Clear any existing waveform image
|
|
|
|
|
ClearWaveform();
|
2011-10-24 17:32:26 -05:00
|
|
|
|
|
|
|
|
// Init a list of lines
|
|
|
|
|
list<Magick::Drawable> lines;
|
|
|
|
|
lines.push_back(Magick::DrawableFillColor("#0070ff"));
|
|
|
|
|
lines.push_back(Magick::DrawablePointSize(16));
|
|
|
|
|
|
2012-08-22 17:31:12 -05:00
|
|
|
// Calculate 1/2 the width of an image based on the # of samples
|
|
|
|
|
int total_samples = audio->getNumSamples();
|
2011-10-27 11:27:44 -05:00
|
|
|
|
2012-08-22 17:31:12 -05:00
|
|
|
// Determine how many samples can be skipped (to speed things up)
|
|
|
|
|
int step = 1;
|
|
|
|
|
if (total_samples > width)
|
|
|
|
|
// Set the # of samples to move forward for each pixel we draw
|
|
|
|
|
step = round((float) total_samples / (float) width) + 1;
|
|
|
|
|
|
|
|
|
|
if (total_samples > 0)
|
2011-10-24 17:32:26 -05:00
|
|
|
{
|
2011-10-27 11:27:44 -05:00
|
|
|
// If samples are present...
|
2012-08-22 17:31:12 -05:00
|
|
|
int new_height = 200 * audio->getNumChannels();
|
2011-10-27 11:27:44 -05:00
|
|
|
int height_padding = 20 * (audio->getNumChannels() - 1);
|
2012-08-22 17:31:12 -05:00
|
|
|
int total_height = new_height + height_padding;
|
|
|
|
|
int total_width = 0;
|
2011-10-24 17:32:26 -05:00
|
|
|
|
2011-10-27 11:27:44 -05:00
|
|
|
// Loop through each audio channel
|
|
|
|
|
int Y = 100;
|
|
|
|
|
for (int channel = 0; channel < audio->getNumChannels(); channel++)
|
2011-10-24 17:32:26 -05:00
|
|
|
{
|
2012-08-22 17:31:12 -05:00
|
|
|
int X = 0;
|
|
|
|
|
|
|
|
|
|
// Change stroke and color
|
|
|
|
|
lines.push_back(Magick::DrawableStrokeColor("#0070ff"));
|
|
|
|
|
lines.push_back(Magick::DrawableStrokeWidth(1));
|
|
|
|
|
|
2011-10-27 11:27:44 -05:00
|
|
|
// Get audio for this channel
|
|
|
|
|
float *samples = audio->getSampleData(channel);
|
2011-10-24 17:32:26 -05:00
|
|
|
|
2012-08-22 17:31:12 -05:00
|
|
|
for (int sample = 0; sample < audio->getNumSamples(); sample+=step, X++)
|
2011-10-27 11:27:44 -05:00
|
|
|
{
|
|
|
|
|
// Sample value (scaled to -100 to 100)
|
|
|
|
|
float value = samples[sample] * 100;
|
2011-10-24 17:32:26 -05:00
|
|
|
|
2011-10-27 11:27:44 -05:00
|
|
|
// Append a line segment for each sample
|
|
|
|
|
if (value != 0.0)
|
|
|
|
|
// LINE
|
2012-08-22 17:31:12 -05:00
|
|
|
lines.push_back(Magick::DrawableLine(X,Y, X,Y-value)); // sample=X coordinate, Y=100 is the middle
|
2011-10-27 11:27:44 -05:00
|
|
|
else
|
|
|
|
|
// DOT
|
2012-08-22 17:31:12 -05:00
|
|
|
lines.push_back(Magick::DrawablePoint(X,Y));
|
2011-10-24 17:32:26 -05:00
|
|
|
}
|
2011-10-27 11:27:44 -05:00
|
|
|
|
|
|
|
|
// Add Channel Label
|
2012-08-22 17:31:12 -05:00
|
|
|
// stringstream label;
|
|
|
|
|
// label << "Channel " << channel;
|
|
|
|
|
// lines.push_back(Magick::DrawableStrokeColor("#ffffff"));
|
|
|
|
|
// lines.push_back(Magick::DrawableFillColor("#ffffff"));
|
|
|
|
|
// lines.push_back(Magick::DrawableStrokeWidth(0.1));
|
|
|
|
|
// lines.push_back(Magick::DrawableText(5, Y - 5, label.str()));
|
2011-10-27 11:27:44 -05:00
|
|
|
|
|
|
|
|
// Increment Y
|
|
|
|
|
Y += (200 + height_padding);
|
2012-08-22 17:31:12 -05:00
|
|
|
total_width = X;
|
2011-10-24 17:32:26 -05:00
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:31:12 -05:00
|
|
|
// Create image
|
|
|
|
|
wave_image = new Magick::Image(Magick::Geometry(total_width, total_height), Magick::Color("#000000"));
|
|
|
|
|
|
2011-10-27 11:27:44 -05:00
|
|
|
// Draw the waveform
|
2012-08-22 17:31:12 -05:00
|
|
|
wave_image->draw(lines);
|
2011-10-27 11:27:44 -05:00
|
|
|
|
|
|
|
|
// Resize Image (if requested)
|
2012-08-22 17:31:12 -05:00
|
|
|
if (width != total_width || height != total_height)
|
|
|
|
|
{
|
|
|
|
|
Magick::Geometry new_size(width, height);
|
|
|
|
|
new_size.aspect(true);
|
2012-08-24 15:57:49 -05:00
|
|
|
wave_image->scale(new_size);
|
2012-08-22 17:31:12 -05:00
|
|
|
}
|
|
|
|
|
|
2011-10-27 11:27:44 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// No audio samples present
|
2012-08-22 17:31:12 -05:00
|
|
|
wave_image = new Magick::Image(Magick::Geometry(width, height), Magick::Color("#000000"));
|
2011-10-27 11:27:44 -05:00
|
|
|
|
2011-10-24 17:32:26 -05:00
|
|
|
// Add Channel Label
|
|
|
|
|
lines.push_back(Magick::DrawableStrokeColor("#ffffff"));
|
|
|
|
|
lines.push_back(Magick::DrawableFillColor("#ffffff"));
|
|
|
|
|
lines.push_back(Magick::DrawableStrokeWidth(0.1));
|
2012-08-22 17:31:12 -05:00
|
|
|
lines.push_back(Magick::DrawableText((width / 2) - 100, height / 2, "No Audio Samples Found"));
|
2011-10-24 17:32:26 -05:00
|
|
|
|
2011-10-27 11:27:44 -05:00
|
|
|
// Draw the waveform
|
2012-08-22 17:31:12 -05:00
|
|
|
wave_image->draw(lines);
|
2011-10-24 17:32:26 -05:00
|
|
|
}
|
|
|
|
|
|
2012-08-22 17:31:12 -05:00
|
|
|
// Return new image
|
|
|
|
|
return wave_image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clear the waveform image (and deallocate it's memory)
|
|
|
|
|
void Frame::ClearWaveform()
|
|
|
|
|
{
|
|
|
|
|
if (wave_image)
|
|
|
|
|
{
|
|
|
|
|
delete wave_image;
|
|
|
|
|
wave_image = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get an audio waveform image pixels
|
|
|
|
|
const Magick::PixelPacket* Frame::GetWaveformPixels(int width, int height)
|
|
|
|
|
{
|
|
|
|
|
// Get audio wave form image
|
|
|
|
|
Magick::Image *wave_image = GetWaveform(width, height);
|
|
|
|
|
|
|
|
|
|
// Return array of pixel packets
|
|
|
|
|
return wave_image->getConstPixels(0,0, wave_image->columns(), wave_image->rows());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Display the wave form
|
|
|
|
|
void Frame::DisplayWaveform()
|
|
|
|
|
{
|
|
|
|
|
// Get audio wave form image
|
|
|
|
|
Magick::Image *wave_image = GetWaveform(720, 480);
|
|
|
|
|
|
2011-10-24 17:32:26 -05:00
|
|
|
// Display Image
|
2012-08-22 17:31:12 -05:00
|
|
|
wave_image->display();
|
|
|
|
|
|
|
|
|
|
// Deallocate waveform image
|
|
|
|
|
ClearWaveform();
|
2011-10-24 17:32:26 -05:00
|
|
|
}
|
|
|
|
|
|
2012-07-09 01:22:11 -05:00
|
|
|
// Get an array of sample data
|
|
|
|
|
float* Frame::GetAudioSamples(int channel)
|
|
|
|
|
{
|
|
|
|
|
// return JUCE audio data for this channel
|
|
|
|
|
return audio->getSampleData(channel);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-30 02:37:19 -05:00
|
|
|
// Get an array of sample data (all channels interleaved together), using any sample rate
|
2012-08-05 15:17:37 -05:00
|
|
|
float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* resampler, int* sample_count)
|
2012-07-24 12:50:17 -05:00
|
|
|
{
|
2012-07-30 02:37:19 -05:00
|
|
|
float *output = NULL;
|
|
|
|
|
AudioSampleBuffer *buffer = audio;
|
|
|
|
|
int num_of_channels = audio->getNumChannels();
|
|
|
|
|
int num_of_samples = audio->getNumSamples();
|
|
|
|
|
|
2012-07-30 11:05:36 -05:00
|
|
|
// DEBUG CODE
|
2012-07-30 02:37:19 -05:00
|
|
|
// if (number == 1)
|
2012-07-30 11:05:36 -05:00
|
|
|
// for (int s = 0; s < num_of_samples; s++)
|
|
|
|
|
// for (int c = 0; c < num_of_channels; c++)
|
|
|
|
|
// cout << buffer->getSampleData(c)[s] << endl;
|
2012-07-30 02:37:19 -05:00
|
|
|
|
|
|
|
|
// Resample to new sample rate (if needed)
|
|
|
|
|
if (new_sample_rate != sample_rate)
|
|
|
|
|
{
|
|
|
|
|
// YES, RESAMPLE AUDIO
|
2012-08-05 15:17:37 -05:00
|
|
|
resampler->SetBuffer(audio, sample_rate, new_sample_rate);
|
2012-07-30 02:37:19 -05:00
|
|
|
|
2012-08-05 15:17:37 -05:00
|
|
|
// Resample data, and return new buffer pointer
|
|
|
|
|
buffer = resampler->GetResampledBuffer();
|
2012-07-30 02:37:19 -05:00
|
|
|
|
|
|
|
|
// Update num_of_samples
|
2012-08-05 15:17:37 -05:00
|
|
|
num_of_samples = buffer->getNumSamples();
|
2012-07-30 02:37:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// INTERLEAVE all samples together (channel 1 + channel 2 + channel 1 + channel 2, etc...)
|
|
|
|
|
output = new float[num_of_channels * num_of_samples];
|
2012-07-24 12:50:17 -05:00
|
|
|
int position = 0;
|
|
|
|
|
|
|
|
|
|
// Loop through samples in each channel (combining them)
|
2012-07-30 02:37:19 -05:00
|
|
|
for (int sample = 0; sample < num_of_samples; sample++)
|
2012-07-24 12:50:17 -05:00
|
|
|
{
|
2012-07-30 02:37:19 -05:00
|
|
|
for (int channel = 0; channel < num_of_channels; channel++)
|
2012-07-24 12:50:17 -05:00
|
|
|
{
|
|
|
|
|
// Add sample to output array
|
2012-07-30 02:37:19 -05:00
|
|
|
//cout << position << ", " << channel << ", " << sample << endl;
|
|
|
|
|
output[position] = buffer->getSampleData(channel)[sample];
|
|
|
|
|
|
2012-07-24 12:50:17 -05:00
|
|
|
// increment position
|
|
|
|
|
position++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-30 02:37:19 -05:00
|
|
|
// Update sample count (since it might have changed due to resampling)
|
|
|
|
|
*sample_count = num_of_samples;
|
|
|
|
|
|
2012-07-24 12:50:17 -05:00
|
|
|
// return combined array
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-09 01:22:11 -05:00
|
|
|
// Get number of audio channels
|
|
|
|
|
int Frame::GetAudioChannelsCount()
|
|
|
|
|
{
|
|
|
|
|
return audio->getNumChannels();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get number of audio samples
|
|
|
|
|
int Frame::GetAudioSamplesCount()
|
|
|
|
|
{
|
|
|
|
|
return audio->getNumSamples();
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-24 12:50:17 -05:00
|
|
|
// Get the audio sample rate
|
|
|
|
|
int Frame::GetAudioSamplesRate()
|
|
|
|
|
{
|
|
|
|
|
return sample_rate;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-11 08:44:27 -05:00
|
|
|
// Get pixel data (as packets)
|
|
|
|
|
const Magick::PixelPacket* Frame::GetPixels()
|
|
|
|
|
{
|
2012-08-20 14:26:49 -05:00
|
|
|
// Return array of pixel packets
|
2011-10-11 08:44:27 -05:00
|
|
|
return image->getConstPixels(0,0, image->columns(), image->rows());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get pixel data (for only a single scan-line)
|
|
|
|
|
const Magick::PixelPacket* Frame::GetPixels(int row)
|
|
|
|
|
{
|
2012-08-20 14:26:49 -05:00
|
|
|
// Return array of pixel packets
|
2011-10-11 08:44:27 -05:00
|
|
|
return image->getConstPixels(0,row, image->columns(), 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get pixel data (for a resized image)
|
|
|
|
|
const Magick::PixelPacket* Frame::GetPixels(unsigned int width, unsigned int height, int frame)
|
|
|
|
|
{
|
|
|
|
|
// Create a new resized image
|
2011-10-11 23:20:26 -05:00
|
|
|
//Magick::Image newImage = *image;
|
|
|
|
|
small_image = new Magick::Image(*(image));
|
|
|
|
|
small_image->resize(Magick::Geometry(width, height));
|
|
|
|
|
small_image->colorize(255, 0, 0, Magick::Color(0,0,255));
|
|
|
|
|
small_image->blur(5.0, 5.0);
|
2011-10-11 08:44:27 -05:00
|
|
|
|
2012-08-20 14:26:49 -05:00
|
|
|
// stringstream file;
|
|
|
|
|
// file << "frame" << frame << ".png";
|
|
|
|
|
// small_image->write(file.str());
|
2011-10-11 08:44:27 -05:00
|
|
|
|
|
|
|
|
// Return arry of pixel packets
|
2011-10-11 23:20:26 -05:00
|
|
|
return small_image->getConstPixels(0,0, small_image->columns(), small_image->rows());
|
2011-10-11 08:44:27 -05:00
|
|
|
}
|
|
|
|
|
|
2011-12-11 20:42:50 -06:00
|
|
|
// Set Pixel Aspect Ratio
|
|
|
|
|
void Frame::SetPixelRatio(int num, int den)
|
|
|
|
|
{
|
|
|
|
|
pixel_ratio.num = num;
|
|
|
|
|
pixel_ratio.den = den;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set Sample Rate
|
|
|
|
|
void Frame::SetSampleRate(int rate)
|
|
|
|
|
{
|
|
|
|
|
sample_rate = rate;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-11 08:44:27 -05:00
|
|
|
// Get height of image
|
|
|
|
|
int Frame::GetHeight()
|
|
|
|
|
{
|
|
|
|
|
// return height
|
|
|
|
|
return image->rows();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get height of image
|
|
|
|
|
int Frame::GetWidth()
|
|
|
|
|
{
|
|
|
|
|
// return width
|
|
|
|
|
return image->columns();
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-05 16:43:09 -05:00
|
|
|
// Save the frame image to the specified path. The image format is determined from the extension (i.e. image.PNG, image.JPEG)
|
|
|
|
|
void Frame::Save(string path, float scale)
|
2011-10-11 08:44:27 -05:00
|
|
|
{
|
2012-08-05 16:43:09 -05:00
|
|
|
// Make a copy of the image (since we might resize it)
|
|
|
|
|
Magick::Image copy;
|
|
|
|
|
copy = *image;
|
|
|
|
|
|
|
|
|
|
// display the image (if any)
|
|
|
|
|
if (copy.size().width() > 1 && copy.size().height() > 1)
|
|
|
|
|
{
|
|
|
|
|
// Resize image (if needed)
|
|
|
|
|
if (pixel_ratio.num != 1 || pixel_ratio.den != 1)
|
|
|
|
|
{
|
|
|
|
|
// Calculate correct DAR (display aspect ratio)
|
|
|
|
|
int new_width = copy.size().width();
|
|
|
|
|
int new_height = copy.size().height() * pixel_ratio.Reciprocal().ToDouble();
|
|
|
|
|
|
|
|
|
|
// Resize image
|
|
|
|
|
Magick::Geometry new_size(new_width, new_height);
|
|
|
|
|
new_size.aspect(true);
|
|
|
|
|
copy.resize(new_size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// scale image if needed
|
|
|
|
|
if (abs(scale) > 1.001 || abs(scale) < 0.999)
|
|
|
|
|
{
|
|
|
|
|
// Resize image
|
|
|
|
|
Magick::Geometry new_size(copy.size().width() * scale, copy.size().height() * scale);
|
|
|
|
|
new_size.aspect(true);
|
|
|
|
|
copy.resize(new_size);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-11 08:44:27 -05:00
|
|
|
// save the image
|
2012-08-05 16:43:09 -05:00
|
|
|
copy.write(path);
|
2011-10-11 08:44:27 -05:00
|
|
|
}
|
|
|
|
|
|
2011-10-24 08:22:21 -05:00
|
|
|
// Add (or replace) pixel data to the frame
|
|
|
|
|
void Frame::AddImage(int width, int height, const string map, const Magick::StorageType type, const void *pixels)
|
|
|
|
|
{
|
|
|
|
|
// Deallocate image memory
|
2012-08-29 15:29:15 -05:00
|
|
|
if (image)
|
|
|
|
|
{
|
|
|
|
|
delete image;
|
|
|
|
|
image = NULL;
|
|
|
|
|
}
|
2011-10-24 08:22:21 -05:00
|
|
|
|
|
|
|
|
// Create new image object, and fill with pixel data
|
|
|
|
|
image = new Magick::Image(width, height, map, type, pixels);
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-29 15:29:15 -05:00
|
|
|
// Add (or replace) pixel data to the frame
|
|
|
|
|
void Frame::AddImage(Magick::Image* new_image)
|
|
|
|
|
{
|
|
|
|
|
// Deallocate image memory
|
|
|
|
|
if (image)
|
|
|
|
|
{
|
|
|
|
|
delete image;
|
|
|
|
|
image = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assign image data
|
|
|
|
|
image = new_image;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-11 08:44:27 -05:00
|
|
|
// Add audio samples to a specific channel
|
|
|
|
|
void Frame::AddAudio(int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource = 1.0f)
|
|
|
|
|
{
|
|
|
|
|
// Add samples to frame's audio buffer
|
|
|
|
|
audio->addFrom(destChannel, destStartSample, source, numSamples, gainToApplyToSource);
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-11 21:13:05 -05:00
|
|
|
// Experimental method to add effects to this frame
|
|
|
|
|
void Frame::AddEffect(string name)
|
|
|
|
|
{
|
|
|
|
|
if (name == "negate")
|
|
|
|
|
image->negate(false);
|
|
|
|
|
else if (name == "flip")
|
|
|
|
|
image->flip();
|
|
|
|
|
else if (name == "oilPaint")
|
|
|
|
|
image->oilPaint(3.0);
|
|
|
|
|
else if (name == "swirl")
|
|
|
|
|
image->swirl(30.0);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-11 08:44:27 -05:00
|
|
|
// Play audio samples for this frame
|
|
|
|
|
void Frame::Play()
|
|
|
|
|
{
|
2011-10-27 11:27:44 -05:00
|
|
|
// Check if samples are present
|
|
|
|
|
if (!audio->getNumSamples())
|
|
|
|
|
return;
|
|
|
|
|
|
2011-10-11 08:44:27 -05:00
|
|
|
AudioDeviceManager deviceManager;
|
|
|
|
|
deviceManager.initialise (0, /* number of input channels */
|
2012-06-17 23:15:47 -05:00
|
|
|
2, /* number of output channels */
|
2011-10-11 08:44:27 -05:00
|
|
|
0, /* no XML settings.. */
|
|
|
|
|
true /* select default device on failure */);
|
2012-06-17 23:15:47 -05:00
|
|
|
//deviceManager.playTestSound();
|
2011-10-11 08:44:27 -05:00
|
|
|
|
|
|
|
|
AudioSourcePlayer audioSourcePlayer;
|
|
|
|
|
deviceManager.addAudioCallback (&audioSourcePlayer);
|
|
|
|
|
|
|
|
|
|
ScopedPointer<AudioBufferSource> my_source;
|
2012-07-30 10:19:35 -05:00
|
|
|
my_source = new AudioBufferSource(audio);
|
2011-10-11 08:44:27 -05:00
|
|
|
|
2012-06-17 23:15:47 -05:00
|
|
|
// Create TimeSliceThread for audio buffering
|
|
|
|
|
TimeSliceThread my_thread("Audio buffer thread");
|
|
|
|
|
|
|
|
|
|
// Start thread
|
|
|
|
|
my_thread.startThread();
|
|
|
|
|
|
2011-10-11 08:44:27 -05:00
|
|
|
AudioTransportSource transport1;
|
|
|
|
|
transport1.setSource (my_source,
|
|
|
|
|
5000, // tells it to buffer this many samples ahead
|
2012-06-17 23:15:47 -05:00
|
|
|
&my_thread,
|
|
|
|
|
(double) sample_rate,
|
|
|
|
|
audio->getNumChannels()); // sample rate of source
|
2011-10-11 08:44:27 -05:00
|
|
|
transport1.setPosition (0);
|
|
|
|
|
transport1.setGain(1.0);
|
|
|
|
|
|
2012-06-17 23:15:47 -05:00
|
|
|
|
2011-10-11 08:44:27 -05:00
|
|
|
// Create MIXER
|
|
|
|
|
MixerAudioSource mixer;
|
|
|
|
|
mixer.addInputSource(&transport1, false);
|
|
|
|
|
audioSourcePlayer.setSource (&mixer);
|
|
|
|
|
|
|
|
|
|
// Start transports
|
|
|
|
|
transport1.start();
|
|
|
|
|
|
|
|
|
|
while (transport1.isPlaying())
|
|
|
|
|
{
|
|
|
|
|
cout << "playing" << endl;
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cout << "DONE!!!" << endl;
|
|
|
|
|
|
|
|
|
|
transport1.stop();
|
|
|
|
|
transport1.setSource (0);
|
|
|
|
|
audioSourcePlayer.setSource (0);
|
2012-06-17 23:15:47 -05:00
|
|
|
my_thread.stopThread(500);
|
2011-10-11 08:44:27 -05:00
|
|
|
deviceManager.removeAudioCallback (&audioSourcePlayer);
|
|
|
|
|
deviceManager.closeAudioDevice();
|
|
|
|
|
deviceManager.removeAllChangeListeners();
|
|
|
|
|
deviceManager.dispatchPendingMessages();
|
|
|
|
|
|
|
|
|
|
cout << "End of Play()" << endl;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|