-
/*
* CINELERRA
- * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 1997-2019 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
SpectrogramFrame::SpectrogramFrame(int data_size)
+ : PluginClientFrame()
{
this->data_size = data_size;
data = new float[data_size];
- force = 0;
+// force = 0;
}
SpectrogramFrame::~SpectrogramFrame()
SpectrogramMode::SpectrogramMode(Spectrogram *plugin,
int x,
int y)
- : BC_PopupMenu(x,
- y,
- 120,
+ : BC_PopupMenu(x, y, xS(120),
mode_to_text(plugin->config.mode))
{
this->plugin = plugin;
int SpectrogramMode::handle_event()
{
- if(plugin->config.mode != text_to_mode(get_text()))
- {
+ if( plugin->config.mode != text_to_mode(get_text()) ) {
SpectrogramWindow *window = (SpectrogramWindow*)plugin->thread->window;
window->probe_x = -1;
window->probe_y = -1;
const char* SpectrogramMode::mode_to_text(int mode)
{
- switch(mode)
+ switch( mode )
{
case VERTICAL:
return _("Vertical");
int SpectrogramMode::text_to_mode(const char *text)
{
- if(!strcmp(mode_to_text(VERTICAL), text)) return VERTICAL;
+ if( !strcmp(mode_to_text(VERTICAL), text) ) return VERTICAL;
return HORIZONTAL;
}
SpectrogramWindowSize::SpectrogramWindowSize(Spectrogram *plugin,
- int x,
- int y,
- char *text)
- : BC_PopupMenu(x,
- y,
- 80,
- text)
+ int x, int y, char *text)
+ : BC_PopupMenu(x, y, xS(120), text)
{
this->plugin = plugin;
}
int SpectrogramWindowSizeTumbler::handle_up_event()
{
plugin->config.window_size *= 2;
- if(plugin->config.window_size > MAX_WINDOW)
+ if( plugin->config.window_size > MAX_WINDOW )
plugin->config.window_size = MAX_WINDOW;
char string[BCTEXTLEN];
sprintf(string, "%d", plugin->config.window_size);
int SpectrogramWindowSizeTumbler::handle_down_event()
{
plugin->config.window_size /= 2;
- if(plugin->config.window_size < MIN_WINDOW)
+ if( plugin->config.window_size < MIN_WINDOW )
plugin->config.window_size = MIN_WINDOW;
char string[BCTEXTLEN];
sprintf(string, "%d", plugin->config.window_size);
SpectrogramFreq::SpectrogramFreq(Spectrogram *plugin, int x, int y)
- : BC_TextBox(x,
- y,
- 100,
- 1,
+ : BC_TextBox(x, y, xS(100), 1,
(int)plugin->config.frequency)
{
this->plugin = plugin;
int SpectrogramCanvas::button_press_event()
{
- if(is_event_win() && cursor_inside())
- {
+ if( is_event_win() && cursor_inside() ) {
calculate_point();
current_operation = DRAG;
plugin->send_configure_change();
int SpectrogramCanvas::button_release_event()
{
- if(current_operation == DRAG)
- {
+ if( current_operation == DRAG ) {
current_operation = NONE;
return 1;
}
int SpectrogramCanvas::cursor_motion_event()
{
- if(current_operation == DRAG)
- {
+ if( current_operation == DRAG ) {
calculate_point();
}
return 0;
{
int x = get_cursor_x();
int y = get_cursor_y();
- CLAMP(x, 0, get_w() - 1);
- CLAMP(y, 0, get_h() - 1);
+ CLAMP(x, 0, get_w()-1);
+ CLAMP(y, 0, get_h()-1);
((SpectrogramWindow*)plugin->thread->window)->calculate_frequency(
x,
void SpectrogramCanvas::draw_overlay()
{
SpectrogramWindow *window = (SpectrogramWindow*)plugin->thread->window;
- if(window->probe_x >= 0 || window->probe_y >= 0)
- {
+ if( window->probe_x >= 0 || window->probe_y >= 0 ) {
set_color(GREEN);
set_inverse();
- if(plugin->config.mode == HORIZONTAL) draw_line(0, window->probe_y, get_w(), window->probe_y);
+ if( plugin->config.mode == HORIZONTAL ) draw_line(0, window->probe_y, get_w(), window->probe_y);
draw_line(window->probe_x, 0, window->probe_x, get_h());
set_opaque();
}
SpectrogramWindow::SpectrogramWindow(Spectrogram *plugin)
- : PluginClientWindow(plugin,
- plugin->w,
- plugin->h,
- 320,
- 320,
- 1)
+ : PluginClientWindow(plugin, plugin->w, plugin->h,
+ xS(320), yS(320), 1)
{
this->plugin = plugin;
probe_x = probe_y = -1;
add_subwindow(canvas = new SpectrogramCanvas(plugin,
- 0,
- 0,
- get_w(),
- get_h() -
- BC_Pot::calculate_h() * 2 -
+ 0, 0, get_w(), get_h() - BC_Pot::calculate_h() * 2 -
plugin->get_theme()->widget_border * 3));
canvas->set_cursor(CROSS_CURSOR, 0, 0);
x += window_size->get_w();
add_subwindow(window_size_tumbler = new SpectrogramWindowSizeTumbler(plugin, x, y));
- for(int i = MIN_WINDOW; i <= MAX_WINDOW; i *= 2)
- {
+ for( int i = MIN_WINDOW; i <= MAX_WINDOW; i *= 2 ) {
sprintf(string, "%d", i);
window_size->add_item(new BC_MenuItem(string));
}
int y_diff = -canvas_h + canvas->get_h();
// Remove all columns which may be a different size.
- plugin->frame_buffer.remove_all_objects();
+// plugin->frame_buffer.remove_all_objects();
plugin->frame_history.remove_all_objects();
level_title->reposition_window(
void SpectrogramWindow::calculate_frequency(int x, int y, int do_overlay)
{
- if(x < 0 && y < 0) return;
+ if( x < 0 && y < 0 ) return;
// Clear previous overlay
- if(do_overlay) canvas->draw_overlay();
+ if( do_overlay ) canvas->draw_overlay();
// New probe position
probe_x = x;
// Convert to coordinates in frame history
int freq_pixel, time_pixel;
- if(plugin->config.mode == VERTICAL)
- {
+ if( plugin->config.mode == VERTICAL ) {
freq_pixel = get_w() - x;
time_pixel = 0;
}
- else
- {
+ else {
freq_pixel = y;
time_pixel = get_w() - x;
}
CLAMP(time_pixel, 0, plugin->frame_history.size() - 1);
- if(plugin->frame_history.size())
- {
+ if( plugin->frame_history.size() ) {
SpectrogramFrame *ptr = plugin->frame_history.get(
plugin->frame_history.size() - time_pixel - 1);
int pixels;
int freq_index;
- if(plugin->config.mode == VERTICAL)
- {
+ if( plugin->config.mode == VERTICAL ) {
pixels = canvas->get_w();
freq_index = (pixels - freq_pixel) * TOTALFREQS / pixels;
}
- else
- {
+ else {
pixels = canvas->get_h();
freq_index = (pixels - freq_pixel) * TOTALFREQS / pixels;
}
amplitude_title->update(string);
}
- if(do_overlay)
- {
+ if( do_overlay ) {
canvas->draw_overlay();
canvas->flash();
}
: PluginAClient(server)
{
reset();
- timer = new Timer;
- w = 640;
- h = 480;
+ w = xS(640);
+ h = yS(480);
}
Spectrogram::~Spectrogram()
{
delete fft;
- delete [] data;
delete audio_buffer;
delete [] freq_real;
delete [] freq_imag;
- delete timer;
- frame_buffer.remove_all_objects();
frame_history.remove_all_objects();
}
thread = 0;
fft = 0;
done = 0;
- data = 0;
audio_buffer = 0;
audio_buffer_start = -MAX_WINDOW * 2;
freq_real = 0;
freq_imag = 0;
allocated_data = 0;
- total_windows = 0;
- bzero(&header, sizeof(data_header_t));
}
int64_t start_position,
int sample_rate)
{
-// Pass through
- read_samples(buffer,
- 0,
- sample_rate,
- start_position,
- size);
+ int dir = get_direction() == PLAY_REVERSE ? -1 : 1;
+ double start_pos = (double)start_position / sample_rate;
+// Pass through
+ read_samples(buffer, 0, sample_rate, start_position, size);
load_configuration();
-
// Reset audio buffer
- if(window_size != config.window_size)
- {
+ if( window_size != config.window_size ) {
render_stop();
window_size = config.window_size;
}
-
-
-
-
- if(!fft)
- {
+ if( !fft )
fft = new FFT;
- }
-
- if(!data)
- {
- data = new unsigned char[sizeof(data_header_t)];
- allocated_data = 0;
- }
- if(!freq_real)
- {
+ if( !freq_real ) {
freq_real = new double[MAX_WINDOW];
freq_imag = new double[MAX_WINDOW];
}
- if(!audio_buffer)
- {
+ if( !audio_buffer )
audio_buffer = new Samples(MAX_WINDOW);
- }
-// Accumulate audio
+// Allocate more audio buffer
int needed = buffer_size + size;
- if(audio_buffer->get_allocated() < needed)
- {
+ if( audio_buffer->get_allocated() < needed ) {
Samples *new_samples = new Samples(needed);
memcpy(new_samples->get_data(),
audio_buffer->get_data(),
double *audio_samples = audio_buffer->get_data();
memcpy(audio_samples + buffer_size,
- buffer->get_data(),
- sizeof(double) * size);
+ buffer->get_data(), sizeof(double) * size);
buffer_size += size;
-
-//printf("Spectrogram::process_buffer %d %d\n", __LINE__, buffer_size);
-
// Append a windows to end of GUI buffer
- total_windows = 0;
- while(buffer_size >= window_size)
- {
+ while(buffer_size >= window_size) {
// Process FFT
fft->do_fft(window_size, // must be a power of 2
- 0, // 0 = forward FFT, 1 = inverse
- audio_samples, // array of input's real samples
- 0, // array of input's imag samples
- freq_real, // array of output's reals
- freq_imag);
+ 0, // 0 = forward FFT, 1 = inverse
+ audio_samples, // array of input's real samples
+ 0, // array of input's imag samples
+ freq_real, // array of output's reals
+ freq_imag);
// Get peak in waveform
double max = 0;
- for(int i = 0; i < window_size; i++)
- {
+ for( int i = 0; i < window_size; i++ ) {
double sample = fabs(audio_samples[i]);
- if(sample > max) max = sample;
+ if( sample > max ) max = sample;
}
-// Append to end of data buffer
- if(allocated_data < (total_windows + 1) * (HALF_WINDOW + 1))
- {
- int new_allocation = (total_windows + 1) * (HALF_WINDOW + 1);
- unsigned char *new_data = new unsigned char[sizeof(data_header_t) +
- sizeof(float) * new_allocation];
- data_header_t *new_header = (data_header_t*)new_data;
- data_header_t *old_header = (data_header_t*)data;
- memcpy(new_header->samples,
- old_header->samples,
- sizeof(float) * allocated_data);
- delete [] data;
- data = new_data;
- allocated_data = new_allocation;
- }
- data_header_t *header = (data_header_t*)data;
- float *sample_output = header->samples + total_windows * (HALF_WINDOW + 1);
-// 1st sample is maximum
- sample_output[0] = max;
- for(int i = 0; i < HALF_WINDOW; i++)
- {
- sample_output[i + 1] = sqrt(freq_real[i] * freq_real[i] +
- freq_imag[i] * freq_imag[i]);
-// sample_output[i + 1] = freq_real[i];
+// send to the GUI
+ SpectrogramFrame *frame = new SpectrogramFrame(HALF_WINDOW + 1);
+ double widx = get_gui_frames();
+ frame->position = start_pos + dir * window_size * widx / get_samplerate();
+ frame->data[0] = max;
+ for( int i = 0; i < HALF_WINDOW; i++ ) {
+ frame->data[i + 1] = hypot(freq_real[i], freq_imag[i]);
}
+ frame->window_size = window_size;
+ frame->sample_rate = sample_rate;
+ frame->level = DB::fromdb(config.level);
+ add_gui_frame(frame);
// Shift audio buffer out
memcpy(audio_samples,
audio_samples + window_size,
(buffer_size - window_size) * sizeof(double));
- total_windows++;
buffer_size -= window_size;
}
- data_header_t *header = (data_header_t*)data;
- header->window_size = window_size;
- header->sample_rate = sample_rate;
- header->total_windows = total_windows;
-// Linear output level
- header->level = DB::fromdb(config.level);
-
- send_render_gui(data,
- sizeof(data_header_t) +
- sizeof(float) * total_windows * (HALF_WINDOW + 1));
-
+ last_position = start_position + dir * size;
return 0;
}
{
buffer_size = 0;
audio_buffer_start = -MAX_WINDOW * 2;
- frame_buffer.remove_all_objects();
+// frame_buffer.remove_all_objects();
frame_history.remove_all_objects();
}
-
-
-
NEW_WINDOW_MACRO(Spectrogram, SpectrogramWindow)
void Spectrogram::update_gui()
{
- if(thread)
- {
- int result = load_configuration();
- SpectrogramWindow *window = (SpectrogramWindow*)thread->get_window();
- window->lock_window("Spectrogram::update_gui");
- if(result) window->update_gui();
-
-
-//printf("Spectrogram::update_gui %d\n", __LINE__);
-// Shift in accumulated canvas columns
- if(frame_buffer.size())
- {
- SpectrogramCanvas *canvas = (SpectrogramCanvas*)window->canvas;
- canvas->draw_overlay();
-// Z to draw in this iteration
- int total_frames = timer->get_difference() *
- header.sample_rate /
- header.window_size /
- 1000;
-
-//printf("Spectrogram::update_gui %d %d %ld\n", __LINE__, frame_buffer.size(), timer->get_difference());
- if(total_frames) timer->subtract(total_frames *
- header.window_size *
- 1000 /
- header.sample_rate);
-
-// Add forced column drawing
- for(int i = 0; i < frame_buffer.size(); i++)
- if(frame_buffer.get(i)->force) total_frames++;
- total_frames = MIN(frame_buffer.size(), total_frames);
-
-// Limit to canvas width
- if(config.mode == HORIZONTAL)
- total_frames = MIN(canvas->get_w(), total_frames);
-
-
-
- if(config.mode == HORIZONTAL)
- {
+ if( !thread ) return;
+ SpectrogramWindow *window = (SpectrogramWindow*)thread->get_window();
+ if( !window ) return;
+ int result = load_configuration();
+ int total_frames = pending_gui_frames();
+ if( !result && !total_frames ) return;
+
+ window->lock_window("Spectrogram::update_gui");
+ if( result ) // widgets
+ window->update_gui();
+ if( total_frames ) { // spectrogram
+ SpectrogramCanvas *canvas = (SpectrogramCanvas*)window->canvas;
+ canvas->draw_overlay();
+
+ if( config.mode == HORIZONTAL ) {
// Shift left
- int pixels = canvas->get_h();
- canvas->copy_area(total_frames * config.xzoom,
- 0,
- 0,
- 0,
- canvas->get_w() - total_frames * config.xzoom,
- canvas->get_h());
+ int pixels = canvas->get_h();
+ canvas->copy_area(total_frames * config.xzoom,
+ 0, 0, 0,
+ canvas->get_w() - total_frames * config.xzoom,
+ canvas->get_h());
// Draw new columns
- for(int frame = 0;
- frame < total_frames;
- frame++)
- {
- int x = canvas->get_w() - (total_frames - frame) * config.xzoom;
- SpectrogramFrame *ptr = frame_buffer.get(0);
-
- for(int i = 0; i < pixels; i++)
- {
- float db = ptr->data[
- MIN(i, ptr->data_size - 1)];
- float h, s, v;
- float r_out, g_out, b_out;
- int r, g, b;
-
+ for( int frame = 0; frame < total_frames; frame++ ) {
+ int x = canvas->get_w() - (total_frames - frame) * config.xzoom;
+ SpectrogramFrame *ptr = (SpectrogramFrame*)get_gui_frame(-1, 0);
+ fix_gui_frame(ptr);
+
+ for( int i = 0; i < pixels; i++ ) {
+ float db = ptr->data[MIN(i, ptr->data_size - 1)];
+ float h, s, v;
+ float r_out, g_out, b_out;
+ int r, g, b;
#define DIVISION1 0.0
#define DIVISION2 -20.0
#define DIVISION3 INFINITYGAIN
- if(db > DIVISION2)
- {
- h = 240 - (float)(db - DIVISION2) / (DIVISION1 - DIVISION2) *
- 240;
- CLAMP(h, 0, 240);
- s = 1.0;
- v = 1.0;
- HSV::hsv_to_rgb(r_out, g_out, b_out, h, s, v);
- r = (int)(r_out * 0xff);
- g = (int)(g_out * 0xff);
- b = (int)(b_out * 0xff);
- }
- else
- if(db > DIVISION3)
- {
- h = 0.0;
- s = 0.0;
- v = (float)(db - DIVISION3) / (DIVISION2 - DIVISION3);
- HSV::hsv_to_rgb(r_out, g_out, b_out, h, s, v);
- r = (int)(r_out * 0xff);
- g = (int)(g_out * 0xff);
- b = (int)(b_out * 0xff);
- }
- else
- {
- r = g = b = 0;
- }
-
- canvas->set_color((r << 16) |
- (g << 8) |
- (b));
- if(config.xzoom == 1)
- canvas->draw_pixel(x, i);
- else
- canvas->draw_line(x,
- i,
- x + config.xzoom,
- i);
+ if( db > DIVISION2 ) {
+ h = 240 - (float)(db - DIVISION2) / (DIVISION1 - DIVISION2) *
+ 240;
+ CLAMP(h, 0, 240);
+ s = 1.0;
+ v = 1.0;
+ HSV::hsv_to_rgb(r_out, g_out, b_out, h, s, v);
+ r = (int)(r_out * 0xff);
+ g = (int)(g_out * 0xff);
+ b = (int)(b_out * 0xff);
}
-
-// Push frames onto history
- for(int i = 0; i < config.xzoom; i++)
- {
- SpectrogramFrame *new_frame = new SpectrogramFrame(
- ptr->data_size);
- frame_history.append(new_frame);
- memcpy(new_frame->data, ptr->data, sizeof(float) * ptr->data_size);
+ else if( db > DIVISION3 ) {
+ h = 0.0;
+ s = 0.0;
+ v = (float)(db - DIVISION3) / (DIVISION2 - DIVISION3);
+ HSV::hsv_to_rgb(r_out, g_out, b_out, h, s, v);
+ r = (int)(r_out * 0xff);
+ g = (int)(g_out * 0xff);
+ b = (int)(b_out * 0xff);
+ }
+ else {
+ r = g = b = 0;
}
-// Clip history to canvas size
- while(frame_history.size() > canvas->get_w())
- frame_history.remove_object_number(0);
+ canvas->set_color((r << 16) | (g << 8) | (b));
+ if( config.xzoom == 1 )
+ canvas->draw_pixel(x, i);
+ else
+ canvas->draw_line(x, i, x + config.xzoom, i);
+ }
- frame_buffer.remove_object_number(0);
+// Copy a frame into history for each pixel
+ for( int i = 0; i < config.xzoom; i++ ) {
+ SpectrogramFrame *new_frame = new SpectrogramFrame(
+ ptr->data_size);
+ frame_history.append(new_frame);
+ memcpy(new_frame->data, ptr->data,
+ sizeof(float) * ptr->data_size);
}
+// Clip history to canvas size
+ while(frame_history.size() > canvas->get_w())
+ frame_history.remove_object_number(0);
+
+ delete ptr;
}
- else
+ }
+ else {
// mode == VERTICAL
- {
-// Shift frames into history
- for(int frame = 0; frame < total_frames; frame++)
- {
- if(frame_history.size() >= config.history_size)
- frame_history.remove_object_number(0);
-
- frame_history.append(frame_buffer.get(0));
- frame_buffer.remove_number(0);
- }
-
+// Shift frames into history buffer
+ for( int frame = 0; frame < total_frames; frame++ ) {
+ SpectrogramFrame *ptr = (SpectrogramFrame*)get_gui_frame(-1, 0);
+ fix_gui_frame(ptr);
+ frame_history.append(ptr);
+ }
// Reduce history size
- while(frame_history.size() > config.history_size)
- frame_history.remove_object_number(0);
+ while(frame_history.size() > config.history_size)
+ frame_history.remove_object_number(0);
// Draw frames from history
- canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
- for(int frame = 0; frame < frame_history.size(); frame++)
- {
- SpectrogramFrame *ptr = frame_history.get(frame);
+ canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
+ for( int frame = 0; frame < frame_history.size(); frame++ ) {
+ SpectrogramFrame *ptr = frame_history.get(frame);
//printf("%d %d\n", canvas->get_w(), ptr->data_size);
- int luma = (frame + 1) * 0x80 / frame_history.size();
- if(frame == frame_history.size() - 1)
- {
- canvas->set_color(WHITE);
- canvas->set_line_width(2);
- }
- else
- canvas->set_color((luma << 16) |
- (luma << 8) |
- luma);
-
-
- int x1 = 0;
- int y1 = 0;
- int w = canvas->get_w();
- int h = canvas->get_h();
- int number = 0;
+ int luma = (frame + 1) * 0x80 / frame_history.size();
+ if( frame == frame_history.size() - 1 ) {
+ canvas->set_color(WHITE);
+ canvas->set_line_width(2);
+ }
+ else
+ canvas->set_color((luma << 16) | (luma << 8) | luma);
+ int x1 = 0, y1 = 0;
+ int w = canvas->get_w();
+ int h = canvas->get_h();
+ int number = 0;
//printf("Spectrogram::update_gui %d ", __LINE__);
- for(int x2 = 0; x2 < w; x2++)
- {
- float db = ptr->data[
- MIN((w - x2), ptr->data_size - 1)];
-//if(x2 > w - 10) printf("%.02f ", ptr->data[x2]);
- int y2 = h - 1 - (int)((db - INFINITYGAIN) /
- (0 - INFINITYGAIN) *
- h);
- CLAMP(y2, 0, h - 1);
-
- if(number)
- {
- canvas->draw_line(x1, y1, x2, y2);
- }
- else
- {
- number++;
- }
-
- x1 = x2;
- y1 = y2;
+ for( int x2 = 0; x2 < w; x2++ ) {
+ float db = ptr->data[
+ MIN((w - x2), ptr->data_size - 1)];
+//if( x2 > w - 10 ) printf("%.02f ", ptr->data[x2]);
+ int y2 = h - 1 - (int)((db - INFINITYGAIN) /
+ (0 - INFINITYGAIN) *
+ h);
+ CLAMP(y2, 0, h - 1);
+
+ if( number ) {
+ canvas->draw_line(x1, y1, x2, y2);
}
-
- canvas->set_line_width(1);
-//printf("\n");
+ else {
+ number++;
+ }
+ x1 = x2;
+ y1 = y2;
}
+ canvas->set_line_width(1);
+//printf("\n");
}
-
-// Recompute probe level
- window->calculate_frequency(window->probe_x, window->probe_y, 0);
-
- canvas->draw_overlay();
- canvas->flash();
}
+// Recompute probe level
+ window->calculate_frequency(window->probe_x, window->probe_y, 0);
- while(frame_buffer.size() > MAX_COLUMNS)
- frame_buffer.remove_object_number(0);
-
- window->unlock_window();
+ canvas->draw_overlay();
+ canvas->flash();
}
+
+ window->unlock_window();
}
-void Spectrogram::render_gui(void *data, int size)
+
+// convert GUI frame to canvas dimensions & normalized DB
+void Spectrogram::fix_gui_frame(SpectrogramFrame *frame)
{
- if(thread)
- {
- thread->get_window()->lock_window("Spectrogram::render_gui");
- data_header_t *header = (data_header_t*)data;
- memcpy(&this->header, header, sizeof(data_header_t));
- BC_SubWindow *canvas = ((SpectrogramWindow*)thread->get_window())->canvas;
- int pixels = canvas->get_w();
- if(config.mode == HORIZONTAL) pixels = canvas->get_h();
-
-// Set all previous columns to draw immediately
- for(int i = 0; i < frame_buffer.size(); i++)
- frame_buffer.get(i)->force = 1;
-
-
- for(int current_window = 0;
- current_window < header->total_windows;
- current_window++)
- {
- float *frame = header->samples +
- current_window * (header->window_size / 2 + 1);
- float frame_max = *frame;
- frame++;
- int niquist = get_project_samplerate() / 2;
- int total_slots = header->window_size / 2;
- int max_slot = total_slots - 1;
-// int slot1 = total_slots - 1;
- SpectrogramFrame *ptr =
- new SpectrogramFrame(
- pixels);
+ int niquist = get_project_samplerate() / 2;
+ int total_slots = frame->window_size / 2;
+ int max_slot = total_slots - 1;
+ BC_SubWindow *canvas = ((SpectrogramWindow*)thread->get_window())->canvas;
+ int pixels = canvas->get_w();
+ if( config.mode == HORIZONTAL ) pixels = canvas->get_h();
+
+// allocate new frame
+ float *out_data = new float[pixels];
+ float *in_data = frame->data;
// Scale slots to pixels
- for(int i = 0; i < pixels; i++)
- {
+ for( int i = 0; i < pixels; i++ ) {
// Low frequency of row
- int freq_index1 = (int)((pixels - i) * TOTALFREQS / pixels);
+ int freq_index1 = (int)((pixels - i) * TOTALFREQS / pixels);
// High frequency of row
- int freq_index2 = (int)((pixels - i + 1) * TOTALFREQS / pixels);
- int freq1 = Freq::tofreq(freq_index1);
- int freq2 = Freq::tofreq(freq_index2);
- float slot1_f = (float)freq1 * max_slot / niquist;
- float slot2_f = (float)freq2 * max_slot / niquist;
- int slot1 = (int)(slot1_f);
- int slot2 = (int)(slot2_f);
- slot1 = MIN(slot1, max_slot);
- slot2 = MIN(slot2, max_slot);
- double sum = 0;
+ int freq_index2 = (int)((pixels - i + 1) * TOTALFREQS / pixels);
+ int freq1 = Freq::tofreq(freq_index1);
+ int freq2 = Freq::tofreq(freq_index2);
+ float slot1_f = (float)freq1 * max_slot / niquist;
+ float slot2_f = (float)freq2 * max_slot / niquist;
+ int slot1 = (int)(slot1_f);
+ int slot2 = (int)(slot2_f);
+ slot1 = MIN(slot1, max_slot);
+ slot2 = MIN(slot2, max_slot);
+ double sum = 0;
// Accumulate multiple slots in the same pixel
- if(slot2 > slot1 + 1)
- {
- for(int j = slot1; j <= slot2; j++)
- sum += frame[j];
+ if( slot2 > slot1 + 1 ) {
+ for( int j = slot1; j <= slot2; j++ )
+ sum += in_data[j];
- sum /= slot2 - slot1 + 1;
- }
- else
+ sum /= slot2 - slot1 + 1;
+ }
+ else {
// Blend 2 slots to create pixel
- {
- float weight = slot1_f - floor(slot1_f);
- int slot3 = MIN(slot1 + 1, max_slot);
- sum = frame[slot1] * (1.0 - weight) +
- frame[slot3] * weight;
- }
+ float weight = slot1_f - floor(slot1_f);
+ int slot3 = MIN(slot1 + 1, max_slot);
+ sum = in_data[slot1] * (1.0 - weight) +
+ in_data[slot3] * weight;
+ }
+
+ out_data[i] = sum;
+ }
- ptr->data[i] = sum;
-// slot1 = slot2;
- }
// Normalize
- if(config.normalize)
- {
+ if( config.normalize ) {
// Get the maximum level in the spectrogram
- float max = 0;
- for(int i = 0; i < pixels; i++)
- {
- if(ptr->data[i] > max) max = ptr->data[i];
- }
+ float max = 0;
+ for( int i = 0; i < pixels; i++ ) {
+ if( out_data[i] > max ) max = out_data[i];
+ }
// Scale all levels
- for(int i = 0; i < pixels; i++)
- {
- ptr->data[i] = header->level *
- ptr->data[i] /
- max;
- }
- }
- else
- {
+ for( int i = 0; i < pixels; i++ ) {
+ out_data[i] = frame->level *
+ out_data[i] /
+ max;
+ }
+ }
+ else {
// Get the maximum level in the spectrogram
- float max = 0;
- for(int i = 0; i < pixels; i++)
- {
- if(ptr->data[i] > max) max = ptr->data[i];
- }
+ float max = 0;
+ for( int i = 0; i < pixels; i++ ) {
+ if( out_data[i] > max ) max = out_data[i];
+ }
// Maximum level in spectrogram is the maximum waveform level
- for(int i = 0; i < pixels; i++)
- {
- ptr->data[i] = header->level *
- frame_max *
- ptr->data[i] /
- max;
- }
-
-
-// for(int i = 0; i < pixels; i++)
-// {
-// ptr->data[i] = header->level * ptr->data[i];
-// }
- }
+ float frame_max = in_data[0];
+ for( int i = 0; i < pixels; i++ ) {
+ out_data[i] = frame->level *
+ frame_max * out_data[i] / max;
+ }
+ }
// DB conversion
//printf("Spectrogram::render_gui %d ", __LINE__);
- for(int i = 0; i < pixels; i++)
- {
- ptr->data[i] = DB::todb(ptr->data[i]);
-//if(i > pixels - 10) printf("%.02f ", ptr->data[i]);
+ for( int i = 0; i < pixels; i++ ) {
+ out_data[i] = DB::todb(out_data[i]);
+//if( i > pixels - 10 ) printf("%.02f ", ptr->data[i]);
- }
-//printf("\n");
-
-
- frame_buffer.append(ptr);
- total_windows++;
- }
-
- timer->update();
- thread->get_window()->unlock_window();
}
+
+ delete [] in_data;
+ frame->data = out_data;
+ frame->data_size = pixels;
}
+
LOAD_CONFIGURATION_MACRO(Spectrogram, SpectrogramConfig)
void Spectrogram::read_data(KeyFrame *keyframe)
{
+//printf("Spectrogram::read_data %d this=%p\n", __LINE__, this);
FileXML input;
input.set_shared_input(keyframe->xbuf);
int result = 0;
- while(!result)
- {
- result = input.read_tag();
-
- if(!result)
- {
- if(input.tag.title_is("SPECTROGRAM"))
- {
- config.level = input.tag.get_property("LEVEL", config.level);
- config.normalize = input.tag.get_property("NORMALIZE", config.normalize);
- config.window_size = input.tag.get_property("WINDOW_SIZE", config.window_size);
- config.xzoom = input.tag.get_property("XZOOM", config.xzoom);
- config.mode = input.tag.get_property("MODE", config.mode);
- config.history_size = input.tag.get_property("HISTORY_SIZE", config.history_size);
- if(is_defaults())
- {
- w = input.tag.get_property("W", w);
- h = input.tag.get_property("H", h);
- }
+ while( !(result = input.read_tag()) ) {
+ if( input.tag.title_is("SPECTROGRAM") ) {
+ config.level = input.tag.get_property("LEVEL", config.level);
+ config.normalize = input.tag.get_property("NORMALIZE", config.normalize);
+ config.window_size = input.tag.get_property("WINDOW_SIZE", config.window_size);
+ config.xzoom = input.tag.get_property("XZOOM", config.xzoom);
+ config.mode = input.tag.get_property("MODE", config.mode);
+ config.history_size = input.tag.get_property("HISTORY_SIZE", config.history_size);
+ if( is_defaults() ) {
+ w = input.tag.get_property("W", w);
+ h = input.tag.get_property("H", h);
}
}
}
output.terminate_string();
}
-
-
-
-