4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "audioscope.h"
23 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
33 #include "transportque.inc"
42 REGISTER_PLUGIN(AudioScope)
45 AudioScopeConfig::AudioScopeConfig()
47 window_size = MAX_WINDOW;
53 int AudioScopeConfig::equivalent(AudioScopeConfig &that)
55 return window_size == that.window_size &&
56 history_size == that.history_size &&
58 EQUIV(trigger_level, that.trigger_level);
61 void AudioScopeConfig::copy_from(AudioScopeConfig &that)
63 window_size = that.window_size;
64 history_size = that.history_size;
66 trigger_level = that.trigger_level;
69 void AudioScopeConfig::interpolate(AudioScopeConfig &prev,
70 AudioScopeConfig &next,
73 int64_t current_frame)
77 CLAMP(history_size, MIN_HISTORY, MAX_HISTORY - 1);
82 AudioScopeFrame::AudioScopeFrame(int data_size, int channels)
84 this->size = data_size;
85 this->channels = channels;
86 for(int i = 0; i < CHANNELS; i++)
87 data[i] = new float[data_size];
91 AudioScopeFrame::~AudioScopeFrame()
93 for(int i = 0; i < CHANNELS; i++)
103 AudioScopeHistory::AudioScopeHistory(AudioScope *plugin,
108 plugin->config.history_size,
112 this->plugin = plugin;
115 int AudioScopeHistory::handle_event()
117 plugin->config.history_size = get_value();
118 plugin->send_configure_change();
129 AudioScopeWindowSize::AudioScopeWindowSize(AudioScope *plugin,
138 this->plugin = plugin;
141 int AudioScopeWindowSize::handle_event()
143 plugin->config.window_size = atoi(get_text());
144 plugin->send_configure_change();
149 AudioScopeWindowSizeTumbler::AudioScopeWindowSizeTumbler(AudioScope *plugin, int x, int y)
153 this->plugin = plugin;
156 int AudioScopeWindowSizeTumbler::handle_up_event()
158 plugin->config.window_size *= 2;
159 if(plugin->config.window_size > MAX_WINDOW)
160 plugin->config.window_size = MAX_WINDOW;
161 char string[BCTEXTLEN];
162 sprintf(string, "%d", plugin->config.window_size);
163 ((AudioScopeWindow*)plugin->get_thread()->get_window())->window_size->set_text(string);
164 plugin->send_configure_change();
168 int AudioScopeWindowSizeTumbler::handle_down_event()
170 plugin->config.window_size /= 2;
171 if(plugin->config.window_size < MIN_WINDOW)
172 plugin->config.window_size = MIN_WINDOW;
173 char string[BCTEXTLEN];
174 sprintf(string, "%d", plugin->config.window_size);
175 ((AudioScopeWindow*)plugin->get_thread()->get_window())->window_size->set_text(string);
176 plugin->send_configure_change();
184 AudioScopeCanvas::AudioScopeCanvas(AudioScope *plugin,
189 : BC_SubWindow(x, y, w, h, BLACK)
191 this->plugin = plugin;
192 current_operation = NONE;
195 int AudioScopeCanvas::button_press_event()
197 if(is_event_win() && cursor_inside())
200 current_operation = DRAG;
201 plugin->send_configure_change();
207 int AudioScopeCanvas::button_release_event()
209 if(current_operation == DRAG)
211 current_operation = NONE;
217 int AudioScopeCanvas::cursor_motion_event()
219 if(current_operation == DRAG)
228 void AudioScopeCanvas::calculate_point()
230 int x = get_cursor_x();
231 int y = get_cursor_y();
232 CLAMP(x, 0, get_w() - 1);
233 CLAMP(y, 0, get_h() - 1);
235 ((AudioScopeWindow*)plugin->thread->window)->calculate_probe(
240 //printf("AudioScopeCanvas::calculate_point %d %d\n", __LINE__, Freq::tofreq(freq_index));
249 AudioScopeTriggerLevel::AudioScopeTriggerLevel(AudioScope *plugin, int x, int y)
250 : BC_FPot(x, y, plugin->config.trigger_level, (float)-1.0, (float)1.0)
252 this->plugin = plugin;
256 int AudioScopeTriggerLevel::handle_event()
258 AudioScopeWindow *window = (AudioScopeWindow*)plugin->thread->window;
259 window->draw_trigger();
260 plugin->config.trigger_level = get_value();
261 plugin->send_configure_change();
262 window->draw_trigger();
263 window->canvas->flash();
271 AudioScopeMode::AudioScopeMode(AudioScope *plugin,
277 mode_to_text(plugin->config.mode))
279 this->plugin = plugin;
282 void AudioScopeMode::create_objects()
284 add_item(new BC_MenuItem(mode_to_text(XY_MODE)));
285 add_item(new BC_MenuItem(mode_to_text(WAVEFORM_NO_TRIGGER)));
286 add_item(new BC_MenuItem(mode_to_text(WAVEFORM_RISING_TRIGGER)));
287 add_item(new BC_MenuItem(mode_to_text(WAVEFORM_FALLING_TRIGGER)));
290 int AudioScopeMode::handle_event()
292 if(plugin->config.mode != text_to_mode(get_text()))
294 AudioScopeWindow *window = (AudioScopeWindow*)plugin->thread->window;
295 window->probe_x = -1;
296 window->probe_y = -1;
297 plugin->config.mode = text_to_mode(get_text());
298 plugin->send_configure_change();
300 window->canvas->clear_box(0, 0, window->canvas->get_w(), window->canvas->get_h());
301 window->draw_overlay();
302 window->canvas->flash();
307 const char* AudioScopeMode::mode_to_text(int mode)
313 case WAVEFORM_NO_TRIGGER:
314 return _("Waveform");
315 case WAVEFORM_RISING_TRIGGER:
316 return _("Rising Trigger");
317 case WAVEFORM_FALLING_TRIGGER:
319 return _("Falling Trigger");
323 int AudioScopeMode::text_to_mode(const char *text)
325 if(!strcmp(mode_to_text(XY_MODE), text)) return XY_MODE;
326 if(!strcmp(mode_to_text(WAVEFORM_NO_TRIGGER), text)) return WAVEFORM_NO_TRIGGER;
327 if(!strcmp(mode_to_text(WAVEFORM_RISING_TRIGGER), text)) return WAVEFORM_RISING_TRIGGER;
328 if(!strcmp(mode_to_text(WAVEFORM_FALLING_TRIGGER), text)) return WAVEFORM_FALLING_TRIGGER;
340 AudioScopeWindow::AudioScopeWindow(AudioScope *plugin)
341 : PluginClientWindow(plugin,
348 this->plugin = plugin;
351 AudioScopeWindow::~AudioScopeWindow()
355 void AudioScopeWindow::create_objects()
357 int x = plugin->get_theme()->widget_border;
359 char string[BCTEXTLEN];
361 add_subwindow(canvas = new AudioScopeCanvas(plugin,
366 plugin->get_theme()->widget_border * 4 -
367 BC_Title::calculate_h(this, "X") * 3));
368 canvas->set_cursor(CROSS_CURSOR, 0, 0);
371 y += canvas->get_h() + plugin->get_theme()->widget_border;
373 add_subwindow(history_size_title = new BC_Title(x, y, _("History Size:")));
374 x += history_size_title->get_w() + plugin->get_theme()->widget_border;
375 add_subwindow(history_size = new AudioScopeHistory(plugin,
378 x += history_size->get_w() + plugin->get_theme()->widget_border;
382 sprintf(string, "%d", plugin->config.window_size);
383 add_subwindow(window_size_title = new BC_Title(x, y, _("Window Size:")));
385 x += window_size_title->get_w() + plugin->get_theme()->widget_border;
386 add_subwindow(window_size = new AudioScopeWindowSize(plugin, x, y, string));
387 x += window_size->get_w();
388 add_subwindow(window_size_tumbler = new AudioScopeWindowSizeTumbler(plugin, x, y));
390 for(int i = MIN_WINDOW; i <= MAX_WINDOW; i *= 2)
392 sprintf(string, "%d", i);
393 window_size->add_item(new BC_MenuItem(string));
396 x += window_size_tumbler->get_w() + plugin->get_theme()->widget_border;
400 y += window_size->get_h() + plugin->get_theme()->widget_border;
401 add_subwindow(mode_title = new BC_Title(x, y, _("Mode:")));
403 x += mode_title->get_w() + plugin->get_theme()->widget_border;
404 add_subwindow(mode = new AudioScopeMode(plugin, x, y));
405 mode->create_objects();
407 x += mode->get_w() + plugin->get_theme()->widget_border;
409 add_subwindow(trigger_level_title = new BC_Title(x, y, _("Trigger level:")));
411 x += trigger_level_title->get_w() + plugin->get_theme()->widget_border;
412 add_subwindow(trigger_level = new AudioScopeTriggerLevel(plugin, x, y));
415 x += trigger_level->get_w() + plugin->get_theme()->widget_border;
417 add_subwindow(probe_sample = new BC_Title(x, y, _("Sample: 0")));
418 y += probe_sample->get_h() + plugin->get_theme()->widget_border;
419 add_subwindow(probe_level0 = new BC_Title(x, y, _("Level 0: 0"), MEDIUMFONT, CHANNEL0_COLOR));
420 y += probe_level0->get_h() + plugin->get_theme()->widget_border;
421 add_subwindow(probe_level1 = new BC_Title(x, y, _("Level 1: 0"), MEDIUMFONT, CHANNEL1_COLOR));
422 y += probe_level1->get_h() + plugin->get_theme()->widget_border;
429 int AudioScopeWindow::resize_event(int w, int h)
431 int y_diff = h - get_h();
433 int canvas_factor = get_h() - canvas->get_h();
434 canvas->reposition_window(0,
438 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
443 // Remove all columns which may be a different size.
444 plugin->frame_buffer.remove_all_objects();
446 window_size_title->reposition_window(window_size_title->get_x(),
447 window_size_title->get_y() + y_diff);
448 window_size->reposition_window(window_size->get_x(),
449 window_size->get_y() + y_diff);
450 window_size_tumbler->reposition_window(window_size_tumbler->get_x(),
451 window_size_tumbler->get_y() + y_diff);
455 history_size_title->reposition_window(history_size_title->get_x(),
456 history_size_title->get_y() + y_diff);
457 history_size->reposition_window(history_size->get_x(),
458 history_size->get_y() + y_diff);
460 mode_title->reposition_window(mode_title->get_x(),
461 mode_title->get_y() + y_diff);
462 mode->reposition_window(mode->get_x(),
463 mode->get_y() + y_diff);
466 trigger_level_title->reposition_window(trigger_level_title->get_x(),
467 trigger_level_title->get_y() + y_diff);
468 trigger_level->reposition_window(trigger_level->get_x(),
469 trigger_level->get_y() + y_diff);
472 probe_sample->reposition_window(probe_sample->get_x(),
473 probe_sample->get_y() + y_diff);
474 probe_level0->reposition_window(probe_level0->get_x(),
475 probe_level0->get_y() + y_diff);
476 probe_level1->reposition_window(probe_level1->get_x(),
477 probe_level1->get_y() + y_diff);
486 void AudioScopeWindow::draw_overlay()
488 canvas->set_color(GREEN);
493 canvas->get_h() / 2);
494 if(plugin->config.mode == XY_MODE)
496 canvas->draw_line(canvas->get_w() / 2,
504 //printf("AudioScopeWindow::draw_overlay %d\n", __LINE__);
507 void AudioScopeWindow::draw_trigger()
509 if(plugin->config.mode == WAVEFORM_RISING_TRIGGER ||
510 plugin->config.mode == WAVEFORM_FALLING_TRIGGER)
512 int y = (int)(-plugin->config.trigger_level *
513 canvas->get_h() / 2 +
514 canvas->get_h() / 2);
515 CLAMP(y, 0, canvas->get_h() - 1);
516 canvas->set_inverse();
517 canvas->set_color(RED);
518 canvas->draw_line(0, y, canvas->get_w(), y);
519 canvas->set_opaque();
523 void AudioScopeWindow::draw_probe()
525 if(probe_x >= 0 || probe_y >= 0)
527 canvas->set_color(GREEN);
528 canvas->set_inverse();
530 if(plugin->config.mode == XY_MODE)
532 canvas->draw_line(0, probe_y, get_w(), probe_y);
533 canvas->draw_line(probe_x, 0, probe_x, get_h());
537 canvas->draw_line(probe_x, 0, probe_x, get_h());
540 canvas->set_opaque();
547 void AudioScopeWindow::calculate_probe(int x, int y, int do_overlay)
549 if(x < 0 && y < 0) return;
551 // Clear previous overlay
552 if(do_overlay) draw_probe();
554 // New probe position
561 if(plugin->config.mode == XY_MODE)
563 channel0 = (float)(probe_x - canvas->get_w() / 2) / (canvas->get_w() / 2);
564 channel1 = (float)(canvas->get_h() / 2 - probe_y) / (canvas->get_h() / 2);
567 if(plugin->current_frame)
569 sample = probe_x * plugin->current_frame->size / canvas->get_w();
570 CLAMP(sample, 0, plugin->current_frame->size - 1);
571 channel0 = plugin->current_frame->data[0][sample];
572 channel1 = plugin->current_frame->data[1][sample];
576 char string[BCTEXTLEN];
577 sprintf(string, _("Sample: %d"), sample);
578 probe_sample->update(string);
580 sprintf(string, _("Level 0: %.2f"), channel0);
581 probe_level0->update(string);
583 sprintf(string, _("Level 1: %.2f"), channel1);
584 probe_level1->update(string);
598 void AudioScopeWindow::update_gui()
600 char string[BCTEXTLEN];
601 sprintf(string, "%d", plugin->config.window_size);
602 window_size->set_text(string);
603 history_size->update(plugin->config.history_size);
630 AudioScope::AudioScope(PluginServer *server)
631 : PluginAClient(server)
639 AudioScope::~AudioScope()
642 for(int i = 0; i < CHANNELS; i++)
643 delete audio_buffer[i];
645 frame_buffer.remove_all_objects();
646 frame_history.remove_all_objects();
650 void AudioScope::reset()
654 for(int i = 0; i < CHANNELS; i++)
659 bzero(&header, sizeof(data_header_t));
664 const char* AudioScope::plugin_title() { return _("AudioScope"); }
665 int AudioScope::is_realtime() { return 1; }
666 int AudioScope::is_multichannel() { return 1; }
668 int AudioScope::process_buffer(int64_t size,
670 int64_t start_position,
673 int channels = MIN(get_total_buffers(), CHANNELS);
676 for(int i = 0; i < get_total_buffers(); i++)
678 read_samples(buffer[i],
685 load_configuration();
687 // Reset audio buffer
688 if(window_size != config.window_size)
691 window_size = config.window_size;
696 data = new unsigned char[sizeof(data_header_t)];
702 for(int i = 0; i < CHANNELS; i++)
704 audio_buffer[i] = new Samples(MAX_WINDOW);
709 int needed = buffer_size + size;
710 if(audio_buffer[0]->get_allocated() < needed)
712 for(int i = 0; i < CHANNELS; i++)
714 Samples *new_samples = new Samples(needed);
715 memcpy(new_samples->get_data(),
716 audio_buffer[i]->get_data(),
717 sizeof(double) * buffer_size);
718 delete audio_buffer[i];
719 audio_buffer[i] = new_samples;
723 for(int i = 0; i < CHANNELS; i++)
725 memcpy(audio_buffer[i]->get_data() + buffer_size,
726 buffer[MIN(i, channels - 1)]->get_data(),
727 sizeof(double) * size);
732 // Append a windows to end of GUI buffer
734 while(buffer_size >= window_size)
736 if(allocated_data < (total_windows + 1) * window_size * CHANNELS)
738 int new_allocation = (total_windows + 1) *
741 unsigned char *new_data = new unsigned char[sizeof(data_header_t) +
742 sizeof(float) * new_allocation];
743 data_header_t *new_header = (data_header_t*)new_data;
744 data_header_t *old_header = (data_header_t*)data;
745 memcpy(new_header->samples,
747 sizeof(float) * allocated_data);
750 allocated_data = new_allocation;
753 // Search for trigger
754 int need_trigger = 0;
756 int trigger_sample = 0;
757 //printf("AudioScope::process_buffer %d\n", __LINE__);
758 if(config.mode == WAVEFORM_RISING_TRIGGER)
761 double *trigger_data = audio_buffer[0]->get_data();
762 for(int i = 1; i < buffer_size - window_size; i++)
764 if(trigger_data[i - 1] < config.trigger_level &&
765 trigger_data[i] >= config.trigger_level)
774 if(config.mode == WAVEFORM_FALLING_TRIGGER)
777 double *trigger_data = audio_buffer[0]->get_data();
778 for(int i = 1; i < buffer_size - window_size; i++)
780 if(trigger_data[i - 1] > config.trigger_level &&
781 trigger_data[i] <= config.trigger_level)
790 //printf("AudioScope::process_buffer %d\n", __LINE__);
792 if(need_trigger && !got_trigger)
794 //printf("AudioScope::process_buffer %d\n", __LINE__);
795 for(int j = 0; j < CHANNELS; j++)
797 double *sample_input = audio_buffer[j]->get_data();
799 sample_input + buffer_size - window_size,
800 sizeof(double) * window_size);
803 buffer_size = window_size;
804 if(buffer_size == window_size) break;
805 //printf("AudioScope::process_buffer %d\n", __LINE__);
809 data_header_t *header = (data_header_t*)data;
810 //printf("AudioScope::process_buffer %d\n", __LINE__);
811 for(int j = 0; j < CHANNELS; j++)
813 float *sample_output = header->samples +
814 total_windows * CHANNELS * window_size +
816 double *sample_input = audio_buffer[j]->get_data();
817 for(int i = 0; i < window_size; i++)
819 sample_output[i] = sample_input[i + trigger_sample];
822 // Shift accumulation buffer
823 //printf("AudioScope::process_buffer %d\n", __LINE__);
825 sample_input + trigger_sample + window_size,
826 sizeof(double) * (buffer_size - trigger_sample - window_size));
827 //printf("AudioScope::process_buffer %d\n", __LINE__);
830 //printf("AudioScope::process_buffer %d\n", __LINE__);
833 buffer_size -= window_size + trigger_sample;
834 //printf("AudioScope::process_buffer %d\n", __LINE__);
838 data_header_t *header = (data_header_t*)data;
839 header->window_size = window_size;
840 header->sample_rate = sample_rate;
841 header->channels = channels;
842 header->total_windows = total_windows;
844 send_render_gui(data,
845 sizeof(data_header_t) +
846 sizeof(float) * total_windows * window_size * CHANNELS);
851 void AudioScope::render_stop()
854 frame_buffer.remove_all_objects();
860 NEW_WINDOW_MACRO(AudioScope, AudioScopeWindow)
862 void AudioScope::update_gui()
866 int result = load_configuration();
867 AudioScopeWindow *window = (AudioScopeWindow*)thread->get_window();
868 window->lock_window("AudioScope::update_gui");
869 if(result) window->update_gui();
871 // Shift in accumulated frames
872 if(frame_buffer.size())
874 BC_SubWindow *canvas = window->canvas;
875 // Frames to draw in this iteration
876 int total_frames = timer->get_difference() *
880 if(total_frames) timer->subtract(total_frames *
885 // Add forced frame drawing
886 for(int i = 0; i < frame_buffer.size(); i++)
887 if(frame_buffer.get(i)->force) total_frames++;
888 total_frames = MIN(frame_buffer.size(), total_frames);
889 //printf("AudioScope::update_gui %d %d\n", __LINE__, total_frames);
893 // Shift frames into history
894 for(int frame = 0; frame < total_frames; frame++)
896 if(frame_history.size() >= config.history_size)
897 frame_history.remove_object_number(0);
899 frame_history.append(frame_buffer.get(0));
900 frame_buffer.remove_number(0);
903 // Reduce history size
904 while(frame_history.size() > config.history_size)
905 frame_history.remove_object_number(0);
907 // Point probe data at history
908 current_frame = frame_history.get(frame_history.size() - 1);
910 // Draw frames from history
911 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
912 for(int frame = 0; frame < frame_history.size(); frame++)
914 AudioScopeFrame *ptr = frame_history.get(frame);
916 int luma = (frame + 1) * 0x80 / frame_history.size();
917 if(frame == frame_history.size() - 1)
919 canvas->set_color(WHITE);
920 canvas->set_line_width(2);
924 canvas->set_color((luma << 16) |
931 int w = canvas->get_w();
932 int h = canvas->get_h();
933 float *channel0 = ptr->data[0];
934 float *channel1 = ptr->data[1];
936 if(config.mode == XY_MODE)
940 for(int point = 0; point < ptr->size; point++)
942 int x2 = (int)(channel0[point] * w / 2 + w / 2);
943 int y2 = (int)(-channel1[point] * h / 2 + h / 2);
949 canvas->draw_line(x1, y1, x2, y2);
962 for(int channel = ptr->channels - 1; channel >= 0; channel--)
966 if(frame == frame_history.size() - 1)
968 canvas->set_color(PINK);
969 canvas->set_line_width(2);
972 canvas->set_color(((luma * 0xff / 0xff) << 16) |
973 ((luma * 0x80 / 0xff) << 8) |
974 ((luma * 0x80 / 0xff)));
978 if(frame == frame_history.size() - 1)
979 canvas->set_color(WHITE);
981 canvas->set_color((luma << 16) |
988 for(int point = 0; point < ptr->size; point++)
990 int x2 = point * w / ptr->size;
991 int y2 = (int)(-ptr->data[channel][point] * h / 2 + h / 2);
995 canvas->draw_line(x1, y1, x2, y2);
1004 for(int x2 = 0; x2 < w; x2++)
1006 int sample1 = x2 * ptr->size / w;
1007 int sample2 = (x2 + 1) * ptr->size / w;
1008 double min = ptr->data[channel][sample1];
1009 double max = ptr->data[channel][sample1];
1010 for(int i = sample1 + 1; i < sample2; i++)
1012 double value = ptr->data[channel][i];
1013 if(value < min) min = value;
1014 if(value > max) max = value;
1017 int min2 = (int)(-min * h / 2 + h / 2);
1018 int max2 = (int)(-max * h / 2 + h / 2);
1019 CLAMP(min2, 0, h - 1);
1020 CLAMP(max2, 0, h - 1);
1021 int y2 = (min2 + max2) / 2;
1022 canvas->draw_line(x2, min2, x2, max2);
1025 canvas->draw_line(x2, y1, x2, y2);
1034 canvas->set_line_width(1);
1037 // Recompute probe level
1038 window->calculate_probe(window->probe_x, window->probe_y, 0);
1042 window->draw_overlay();
1048 while(frame_buffer.size() > MAX_COLUMNS)
1049 frame_buffer.remove_object_number(0);
1051 thread->get_window()->unlock_window();
1055 void AudioScope::render_gui(void *data, int size)
1059 thread->get_window()->lock_window("AudioScope::render_gui");
1060 data_header_t *header = (data_header_t*)data;
1061 memcpy(&this->header, header, sizeof(data_header_t));
1062 //BC_SubWindow *canvas = ((AudioScopeWindow*)thread->get_window())->canvas;
1063 //int h = canvas->get_h();
1065 // Set all previous frames to draw immediately
1066 for(int i = 0; i < frame_buffer.size(); i++)
1067 frame_buffer.get(i)->force = 1;
1069 for(int current_fragment = 0;
1070 current_fragment < header->total_windows;
1073 float *in_frame = header->samples +
1074 current_fragment * header->window_size * CHANNELS;
1075 AudioScopeFrame *out_frame = new AudioScopeFrame(
1076 header->window_size,
1079 // Copy the window to the frame
1080 for(int j = 0; j < CHANNELS; j++)
1082 for(int i = 0; i < header->window_size; i++)
1084 out_frame->data[j][i] = in_frame[header->window_size * j + i];
1088 frame_buffer.append(out_frame);
1093 thread->get_window()->unlock_window();
1104 LOAD_CONFIGURATION_MACRO(AudioScope, AudioScopeConfig)
1106 void AudioScope::read_data(KeyFrame *keyframe)
1109 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
1114 result = input.read_tag();
1118 if(input.tag.title_is("AUDIOSCOPE"))
1122 w = input.tag.get_property("W", w);
1123 h = input.tag.get_property("H", h);
1126 config.history_size = input.tag.get_property("HISTORY_SIZE", config.history_size);
1127 config.window_size = input.tag.get_property("WINDOW_SIZE", config.window_size);
1128 config.mode = input.tag.get_property("MODE", config.mode);
1129 config.trigger_level = input.tag.get_property("TRIGGER_LEVEL", config.trigger_level);
1135 void AudioScope::save_data(KeyFrame *keyframe)
1138 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
1140 //printf("AudioScope::save_data %d %d %d\n", __LINE__, config.w, config.h);
1141 output.tag.set_title("AUDIOSCOPE");
1142 output.tag.set_property("W", w);
1143 output.tag.set_property("H", h);
1144 output.tag.set_property("HISTORY_SIZE", config.history_size);
1145 output.tag.set_property("WINDOW_SIZE", (int)config.window_size);
1146 output.tag.set_property("MODE", (int)config.mode);
1147 output.tag.set_property("TRIGGER_LEVEL", (float)config.trigger_level);
1148 output.append_tag();
1149 output.tag.set_title("/AUDIOSCOPE");
1150 output.append_tag();
1151 output.append_newline();
1152 output.terminate_string();