2
* Copyright (C) 1999-2002 Andy Lo A Foe <andy@alsaplayer.org>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
* $Id: ScopesWindow.cpp 954 2003-04-08 15:23:31Z adnans $
21
#include "ScopesWindow.h"
22
#include "CorePlayer.h"
26
#include "gtk_interface.h"
27
#include "pixmaps/note.xpm"
28
#include "alsaplayer_error.h"
29
#include "alsaplayer_fft.h"
35
extern int global_scopes_show;
36
static GtkWidget *scopes_window = (GtkWidget *)NULL;
37
static GdkPixmap *active_pix = (GdkPixmap *)NULL;
38
static GdkBitmap *active_mask = (GdkBitmap *)NULL;
39
static scope_entry *root_scope = NULL;
40
static pthread_mutex_t sl_mutex;
42
void dl_close_scopes()
44
scope_entry *current = root_scope;
48
dlclose(current->sp->handle);
50
current = current->next;
54
void scope_entry_destroy_notify(gpointer)
58
#define SCOPE_BUFFER 2048
60
bool scope_feeder_func(void *arg, void *data, int size)
62
static char buf[32768];
63
static int latency = -1;
64
static int fft_buf[512];
68
static int buf_size = 0;
69
static AlsaNode *the_node = NULL;
75
static double fftmult[FFT_BUFFER_SIZE / 2 + 1];
77
static sound_sample left_actEq[SCOPE_BUFFER];
78
static double left_fftout[FFT_BUFFER_SIZE / 2 + 1];
79
static fft_state *left_fftstate;
81
static sound_sample right_actEq[SCOPE_BUFFER];
82
static double right_fftout[FFT_BUFFER_SIZE / 2 + 1];
83
static fft_state *right_fftstate;
85
sound_sample *left_newset;
86
sound_sample *right_newset;
88
size <<= 1; // To bytes again
93
for(i = 0; i <= FFT_BUFFER_SIZE / 2 + 1; i++) {
94
double mult = (double)128 / ((FFT_BUFFER_SIZE * 16384) ^ 2);
95
mult *= log(i + 1) / log(2);
99
right_fftstate = fft_init();
100
left_fftstate = fft_init();
101
if (!left_fftstate || !right_fftstate)
102
alsaplayer_error("WARNING: could not do fft_init()");
103
buf_size = SCOPE_BUFFER <= (FFT_BUFFER_SIZE * 2) ? SCOPE_BUFFER : FFT_BUFFER_SIZE;
104
CorePlayer *the_coreplayer = (CorePlayer *)arg;
105
if (the_coreplayer) {
106
the_node = the_coreplayer->GetNode();
109
latency = the_node->GetLatency();
111
if (latency < SCOPE_BUFFER)
112
latency = SCOPE_BUFFER;
118
scope_entry *se = root_scope;
120
//buffer_effect(data, size);
122
if (fill + size >= SCOPE_BUFFER) {
123
left = SCOPE_BUFFER - fill;
124
memcpy(buf + fill, data, left);
127
left_newset = left_actEq;
128
right_newset = right_actEq;
130
sound = (short *)buf;
131
//sound = (short *)delay_feed(latency, SCOPE_BUFFER);
133
for (i = 0; i < buf_size; i++) {
134
*left_newset++ = (sound_sample)((int)(*sound));
135
*right_newset++ = (sound_sample)((int)(*(sound+1)));
139
fft_perform(right_actEq, right_fftout, right_fftstate);
140
fft_perform(left_actEq, left_fftout, left_fftstate);
142
for (i = 0, left_pos = fft_buf, right_pos = fft_buf + 256; i < 256; i++) {
143
left_pos[i] = (int)(sqrt(left_fftout[i + 1])) >> 8; //* fftmult[i]);
144
right_pos[i] = (int)(sqrt(right_fftout[i + 1])) >> 8; //* fftmult[i]);
146
while (se && se->sp && se->active) {
147
if (se->sp->running()) {
148
if (se->sp->set_data)
149
se->sp->set_data((short *)buf, SCOPE_BUFFER >> 1);
151
se->sp->set_fft((int *)fft_buf, 256, 2);
158
// Copy the remainder
160
memcpy(buf + fill, ((char *)data) + left, size - left);
162
memcpy(buf + fill, data, size);
169
void apUnregiserScopePlugins()
171
scope_entry *current = root_scope;
173
pthread_mutex_lock(&sl_mutex);
174
while (current && current->sp) {
175
//printf("closing and unloading scope plugin %s\n", current->sp->name);
177
current->sp->shutdown();
178
current = current->next;
180
pthread_mutex_unlock(&sl_mutex);
184
int apRegisterScopePlugin(scope_plugin *plugin)
189
if (!scopes_window) {
190
printf("No scopes_window\n");
193
list = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(scopes_window),
195
se = new scope_entry;
196
se->next = (scope_entry *)NULL;
198
if (se->sp->version != SCOPE_PLUGIN_VERSION) {
199
alsaplayer_error("Wrong version number on scope plugin (v%d, wanted v%d)",
200
se->sp->version - 0x1000,
201
SCOPE_PLUGIN_VERSION - 0x1000);
207
// Add new scope to GtkClist
208
list_item[0] = g_strdup(" ");
209
list_item[1] = g_strdup(se->sp->name);
210
int index = gtk_clist_append(GTK_CLIST(list), list_item);
211
gtk_clist_set_row_data_full(GTK_CLIST(list), index, se, scope_entry_destroy_notify);
215
// Add scope to scope list
216
// NOTE: WE CURRENTLY NEVER UNLOAD SCOPES
217
pthread_mutex_lock(&sl_mutex);
218
if (root_scope == NULL) {
219
//printf("registering first scope...\n");
221
root_scope->next = (scope_entry *)NULL;
222
root_scope->active = 1;
223
} else { // Not root scope, so insert it at the start
224
se->next = root_scope->next;
226
root_scope->next = se;
228
pthread_mutex_unlock(&sl_mutex);
229
//fprintf(stdout, "Loading Scope plugin: %s (%x)\n", se->sp->name, se->sp->handle);
234
static void close_all_cb(GtkWidget *, gpointer data)
236
GtkWidget *list = (GtkWidget *)data;
239
scope_entry *current = root_scope;
243
if (current->sp) current->sp->stop();
245
current = current->next;
251
static void close_scope_cb(GtkWidget *, gpointer data)
253
GtkWidget *list = (GtkWidget *)data;
256
if (!GTK_CLIST(list)->selection)
258
gint row = GPOINTER_TO_INT(GTK_CLIST(list)->selection->data);
260
scope_entry *se = (scope_entry *)
261
gtk_clist_get_row_data(GTK_CLIST(list), row);
271
static void open_scope_cb(GtkWidget *, gpointer data)
273
GtkWidget *list = (GtkWidget *)data;
276
if (!GTK_CLIST(list)->selection)
278
gint row = GPOINTER_TO_INT(GTK_CLIST(list)->selection->data);
280
scope_entry *se = (scope_entry *)
281
gtk_clist_get_row_data(GTK_CLIST(list), row);
291
static void exclusive_open_cb(GtkWidget *widget, gpointer data)
293
GtkWidget *list = (GtkWidget *)data;
296
scope_entry *current = root_scope;
297
scope_entry *exclusive_one = NULL;
299
if (!GTK_CLIST(list)->selection)
302
gint row = GPOINTER_TO_INT(GTK_CLIST(list)->selection->data);
304
scope_entry *se = (scope_entry *)
305
gtk_clist_get_row_data(GTK_CLIST(list), row);
309
exclusive_one = current;
312
//alsaplayer_error("Stopping \"%s\"", current->sp->name);
315
current = current->next;
317
if (exclusive_one && exclusive_one->sp) {
318
//alsaplayer_error("Starting exclusive scope \"%s\"", exclusive_one->sp->name);
319
exclusive_one->sp->start();
326
void scopes_list_button_press(GtkWidget *widget, GdkEvent *bevent, gpointer)
328
GtkWidget *menu_item;
331
//alsaplayer_error("Button pressed! (%.2f, %.2f, %d)", bevent->button.x,
332
// bevent->button.y, bevent->button.button);
333
gtk_clist_get_selection_info(GTK_CLIST(widget),
334
(gint)bevent->button.x, (gint)bevent->button.y,
336
if (bevent->button.button == 3) { // Right mouse
339
gtk_clist_select_row(GTK_CLIST(widget), row, 0);
341
if (!GTK_CLIST(widget)->selection)
347
the_menu = gtk_menu_new();
348
menu_item = gtk_menu_item_new_with_label("Open");
349
gtk_menu_append(GTK_MENU(the_menu), menu_item);
350
gtk_widget_show(menu_item);
351
gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
352
GTK_SIGNAL_FUNC(open_scope_cb), widget);
354
gtk_widget_set_sensitive(menu_item, false);
356
menu_item = gtk_menu_item_new_with_label("Open exclusively");
357
gtk_menu_append(GTK_MENU(the_menu), menu_item);
358
gtk_widget_show(menu_item);
359
gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
360
GTK_SIGNAL_FUNC(exclusive_open_cb), widget);
362
gtk_widget_set_sensitive(menu_item, false);
365
menu_item = gtk_menu_item_new();
366
gtk_menu_append(GTK_MENU(the_menu), menu_item);
367
gtk_widget_show(menu_item);
370
menu_item = gtk_menu_item_new_with_label("Close");
371
gtk_menu_append(GTK_MENU(the_menu), menu_item);
372
gtk_widget_show(menu_item);
373
gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
374
GTK_SIGNAL_FUNC(close_scope_cb), widget);
376
gtk_widget_set_sensitive(menu_item, false);
378
menu_item = gtk_menu_item_new_with_label("Close all");
379
gtk_menu_append(GTK_MENU(the_menu), menu_item);
380
gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
381
GTK_SIGNAL_FUNC(close_all_cb), widget);
382
gtk_widget_show(menu_item);
385
gtk_menu_popup(GTK_MENU(the_menu), NULL, NULL, NULL, NULL,
386
bevent->button.button, bevent->button.time);
389
//alsaplayer_error("Row = %d, Col = %d", row, col);
392
void scopes_list_click(GtkWidget *widget, gint row, gint /* column */,
393
GdkEvent *bevent, gpointer /* data */)
395
if (bevent && bevent->type == GDK_2BUTTON_PRESS) {
396
scope_entry *se = (scope_entry *)
397
gtk_clist_get_row_data(GTK_CLIST(widget), row);
404
se->active = 1 - se->active;
406
gtk_clist_set_pixmap(GTK_CLIST(widget),
407
row, 0, active_pix, active_mask);
409
gtk_clist_set_text(GTK_CLIST(widget),
420
void scopes_window_ok_cb(GtkWidget * /*button_widget*/, gpointer data)
423
static gint s_windows_x_offset = 0;
424
static gint s_windows_y_offset = 0;
426
GtkWidget *widget = (GtkWidget *)data;
428
gdk_window_get_origin(widget->window, &x, &y);
429
if (windows_x_offset >= 0) {
430
x -= s_windows_x_offset;
431
y -= s_windows_y_offset;
433
gtk_widget_hide(widget);
434
gtk_widget_set_uposition(widget, x, y);
435
global_scopes_show = 0;
439
gboolean scopes_window_delete_event(GtkWidget *widget, GdkEvent * /*event*/, gpointer /* data */)
443
gdk_window_get_origin(widget->window, &x, &y);
444
if (windows_x_offset >= 0) {
445
x -= windows_x_offset;
446
y -= windows_y_offset;
448
gtk_widget_hide(widget);
449
gtk_widget_set_uposition(widget, x, y);
450
global_scopes_show = 0;
456
void destroy_scopes_window()
460
prefs_set_bool(ap_prefs, "gtk_interface", "scopeswindow_active",
464
GtkWidget *init_scopes_window()
469
scopes_window = create_scopes_window();
470
gtk_widget_realize(scopes_window);
471
GtkWidget *list = get_widget(scopes_window, "scopes_list");
473
style = gtk_widget_get_style(list);
474
active_pix = gdk_pixmap_create_from_xpm_d(scopes_window->window, &active_mask,
475
&style->bg[GTK_STATE_NORMAL], note_xpm);
478
gtk_object_set_data(GTK_OBJECT(scopes_window), "list", list);
479
gtk_clist_set_column_width(GTK_CLIST(list), 0, 16);
480
gtk_clist_set_row_height(GTK_CLIST(list), 20);
481
gtk_signal_connect(GTK_OBJECT(list), "select_row",
482
GTK_SIGNAL_FUNC(scopes_list_click), NULL);
483
gtk_signal_connect(GTK_OBJECT(list), "button_press_event",
484
GTK_SIGNAL_FUNC(scopes_list_button_press), NULL);
485
working = get_widget(scopes_window, "ok_button");
486
gtk_signal_connect(GTK_OBJECT(working), "clicked",
487
GTK_SIGNAL_FUNC(scopes_window_ok_cb), scopes_window);
489
// Close/delete signals
490
gtk_signal_connect(GTK_OBJECT(scopes_window), "destroy",
491
GTK_SIGNAL_FUNC(scopes_window_delete_event), NULL);
492
gtk_signal_connect(GTK_OBJECT(scopes_window), "delete_event",
493
GTK_SIGNAL_FUNC(scopes_window_delete_event), NULL);
496
pthread_mutex_init(&sl_mutex, (pthread_mutexattr_t *)NULL);
498
if (prefs_get_bool(ap_prefs, "gtk_interface", "scopeswindow_active", 0)) {
499
gtk_widget_show(scopes_window);
500
global_scopes_show = 1;
503
return scopes_window;