2
* Copyright (C) 2003 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: scopes.cpp 1032 2004-02-15 23:02:12Z adnans $
23
#include "AlsaPlayer.h"
25
#include "AlsaSubscriber.h"
26
#include "alsaplayer_error.h"
27
#include "alsaplayer_fft.h"
32
#include <sys/types.h>
37
static scope_entry *root_scope = NULL;
38
static pthread_mutex_t sl_mutex;
39
static AlsaSubscriber *scopes = NULL;
41
void unregister_scopes(void);
42
bool register_scope(scope_plugin *plugin, bool, void *);
44
void unload_scope_addons()
52
void load_scope_addons()
57
scope_plugin_info_type scope_plugin_info;
59
snprintf(path, sizeof(path)-1, "%s/scopes2", global_pluginroot);
61
DIR *dir = opendir(path);
65
while ((entry = readdir(dir)) != NULL) { // For each file in scopes
66
if (strcmp(entry->d_name, ".") == 0 ||
67
strcmp(entry->d_name, "..") == 0) {
70
sprintf(path, "%s/scopes2/%s", global_pluginroot, entry->d_name);
71
if (stat(path, &buf)) continue;
72
if (S_ISREG(buf.st_mode)) {
75
char *ext = strrchr(path, '.');
79
if (strcasecmp(ext, "so"))
81
if ((handle = dlopen(path, RTLD_NOW |RTLD_GLOBAL))) {
82
scope_plugin_info = (scope_plugin_info_type) dlsym(handle, "scope_plugin_info");
83
if (scope_plugin_info) {
84
alsaplayer_error("Loading scope addon: %s", path);
85
tmp = scope_plugin_info();
88
if (!register_scope(tmp, false, NULL)) {
89
alsaplayer_error("%s is deprecated", path);
96
printf("%s\n", dlerror());
105
void dl_close_scopes()
107
scope_entry *current = root_scope;
111
dlclose(current->sp->handle);
113
current = current->next;
117
void scope_entry_destroy_notify(gpointer)
121
#define SCOPE_BUFFER 2048
123
bool scope_feeder_func(void *arg, void *data, int size)
125
static char buf[32768];
126
static int latency = -1;
127
static int fft_buf[512];
131
static int buf_size = 0;
132
static AlsaNode *the_node = NULL;
138
static double fftmult[FFT_BUFFER_SIZE / 2 + 1];
140
static sound_sample left_actEq[SCOPE_BUFFER];
141
static double left_fftout[FFT_BUFFER_SIZE / 2 + 1];
142
static fft_state *left_fftstate;
144
static sound_sample right_actEq[SCOPE_BUFFER];
145
static double right_fftout[FFT_BUFFER_SIZE / 2 + 1];
146
static fft_state *right_fftstate;
148
sound_sample *left_newset;
149
sound_sample *right_newset;
151
//alsaplayer_error("In scope_feeder_func()");
156
for(i = 0; i <= FFT_BUFFER_SIZE / 2 + 1; i++) {
157
double mult = (double)128 / ((FFT_BUFFER_SIZE * 16384) ^ 2);
158
mult *= log(i + 1) / log(2);
162
right_fftstate = fft_init();
163
left_fftstate = fft_init();
164
if (!left_fftstate || !right_fftstate)
165
alsaplayer_error("WARNING: could not do fft_init()");
166
buf_size = SCOPE_BUFFER <= (FFT_BUFFER_SIZE * 2) ? SCOPE_BUFFER : FFT_BUFFER_SIZE;
168
the_node = (AlsaNode *)arg;
170
latency = the_node->GetLatency();
172
if (latency < SCOPE_BUFFER)
173
latency = SCOPE_BUFFER;
179
scope_entry *se = root_scope;
181
//buffer_effect(data, size);
183
if (fill + size >= SCOPE_BUFFER) {
184
left = SCOPE_BUFFER - fill;
185
memcpy(buf + fill, data, left);
188
left_newset = left_actEq;
189
right_newset = right_actEq;
191
sound = (short *)buf;
192
//sound = (short *)delay_feed(latency, SCOPE_BUFFER);
194
for (i = 0; i < buf_size; i++) {
195
*left_newset++ = (sound_sample)((int)(*sound));
196
*right_newset++ = (sound_sample)((int)(*(sound+1)));
200
fft_perform(right_actEq, right_fftout, right_fftstate);
201
fft_perform(left_actEq, left_fftout, left_fftstate);
203
for (i = 0, left_pos = fft_buf, right_pos = fft_buf + 256; i < 256; i++) {
204
left_pos[i] = (int)(sqrt(left_fftout[i + 1])) >> 8; //* fftmult[i]);
205
right_pos[i] = (int)(sqrt(right_fftout[i + 1])) >> 8; //* fftmult[i]);
207
while (se && se->sp && se->active) {
208
if (se->sp->running()) {
209
if (se->sp->set_data)
210
se->sp->set_data((short *)buf, SCOPE_BUFFER >> 1);
212
se->sp->set_fft((int *)fft_buf, 256, 2);
219
// Copy the remainder
221
memcpy(buf + fill, ((char *)data) + left, size - left);
223
memcpy(buf + fill, data, size);
230
void unregister_scopes(void)
232
scope_entry *current = root_scope;
234
pthread_mutex_lock(&sl_mutex);
235
while (current && current->sp) {
236
//printf("closing and unloading scope plugin %s\n", current->sp->name);
238
current->sp->shutdown();
239
current = current->next;
241
pthread_mutex_unlock(&sl_mutex);
245
bool register_scope(scope_plugin *plugin, bool run, void *arg)
249
se = new scope_entry;
250
se->next = (scope_entry *)NULL;
252
if (se->sp->version != SCOPE_PLUGIN_VERSION) {
253
alsaplayer_error("Wrong version number on scope plugin (v%d, wanted v%d)",
254
se->sp->version - 0x1000,
255
SCOPE_PLUGIN_VERSION - 0x1000);
262
if (!se->sp->init(arg)) {
266
// Add scope to scope list
267
// NOTE: WE CURRENTLY NEVER UNLOAD SCOPES
268
pthread_mutex_lock(&sl_mutex);
269
if (root_scope == NULL) {
270
//alsaplayer_error("registering first scope...");
272
root_scope->next = (scope_entry *)NULL;
273
root_scope->active = 1;
274
} else { // Not root scope, so insert it at the start
275
se->next = root_scope->next;
277
root_scope->next = se;
279
pthread_mutex_unlock(&sl_mutex);
286
void scopes_list_click(GtkWidget *widget, gint row, gint /* column */,
287
GdkEvent *bevent, gpointer /* data */)
289
if (bevent && bevent->type == GDK_2BUTTON_PRESS) {
290
scope_entry *se = (scope_entry *)
291
gtk_clist_get_row_data(GTK_CLIST(widget), row);
298
se->active = 1 - se->active;
300
gtk_clist_set_pixmap(GTK_CLIST(widget),
301
row, 0, active_pix, active_mask);
303
gtk_clist_set_text(GTK_CLIST(widget),
314
bool init_scopes(AlsaNode *node)
317
pthread_mutex_init(&sl_mutex, (pthread_mutexattr_t *)NULL);
322
alsaplayer_error("Huh, no node?");
325
scopes = new AlsaSubscriber();
326
scopes->Subscribe(node, POS_END);
327
scopes->EnterStream(scope_feeder_func, node);