~ubuntu-branches/ubuntu/wily/alsaplayer/wily

« back to all changes in this revision

Viewing changes to scopes2/opengl_spectrum/opengl_spectrum.c

  • Committer: Bazaar Package Importer
  • Author(s): Hubert Chathi
  • Date: 2007-10-10 15:33:10 UTC
  • mto: (9.2.5 sid)
  • mto: This revision was merged to the branch mainline in revision 15.
  • Revision ID: james.westby@ubuntu.com-20071010153310-h3holq75eu2cigb0
Tags: upstream-0.99.80~rc4
ImportĀ upstreamĀ versionĀ 0.99.80~rc4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  opengl_spectrum.c (C) 2002 by Andy Lo A Foe <andy@alsaplayer.org>
 
2
 
 
3
 *  Based on code found in xmms:
 
4
 *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
 
5
 *
 
6
 *  This file is part of AlsaPlayer.
 
7
 *
 
8
 *  AlsaPlayer is free software; you can redistribute it and/or modify
 
9
 *  it under the terms of the GNU General Public License as published by
 
10
 *  the Free Software Foundation; either version 3 of the License, or
 
11
 *  (at your option) any later version.
 
12
 *
 
13
 *  AlsaPlayer is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 *  GNU General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU General Public License
 
19
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 */
 
22
 
 
23
#include <X11/Xlib.h>
 
24
#include <X11/keysym.h>
 
25
#include <math.h>
 
26
 
 
27
#include <GL/gl.h>
 
28
#include <GL/glx.h>
 
29
#include <pthread.h>
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
 
 
33
#include "scope_plugin.h"
 
34
#include "alsaplayer_error.h"
 
35
#include "utilities.h"
 
36
#include "prefs.h"
 
37
 
 
38
#define NUM_BANDS 16
 
39
 
 
40
//#define NVIDIA_SYNC
 
41
 
 
42
#ifndef FALSE
 
43
#define FALSE 0
 
44
#endif
 
45
 
 
46
#ifndef TRUE
 
47
#define TRUE 1
 
48
#endif
 
49
 
 
50
static Display *dpy = NULL;
 
51
static Colormap colormap = 0;
 
52
static GLXContext glxcontext = NULL;
 
53
static Window window = 0;
 
54
static GLfloat y_angle = 45.0, y_speed = 0.5;
 
55
static GLfloat x_angle = 20.0, x_speed = 0.0;
 
56
static GLfloat z_angle = 0.0, z_speed = 0.0;
 
57
static GLfloat heights[16][16], scale;
 
58
static int going = FALSE, grabbed_pointer = FALSE;
 
59
static Atom wm_delete_window_atom;
 
60
static pthread_t draw_thread;
 
61
static pthread_mutex_t scope_mutex;
 
62
 
 
63
static int window_w;
 
64
static int window_h;
 
65
 
 
66
#ifdef NVIDIA_SYNC
 
67
#include <sys/poll.h>
 
68
#include <sys/types.h>
 
69
#include <sys/stat.h>
 
70
#include <fcntl.h>
 
71
#endif
 
72
 
 
73
static void stop_display(int);
 
74
static void oglspectrum_start(void);
 
75
 
 
76
static void wait_for_vsync()
 
77
{
 
78
#ifdef NVIDIA_SYNC      
 
79
        static int init = 0;
 
80
        static int fd = -1;
 
81
        static struct pollfd pollfds;
 
82
        if (!init) {
 
83
                fd = open("/dev/nvidia0", O_RDONLY);
 
84
                if (fd == -1) {
 
85
                        alsaplayer_error("Error opening NVIDIA device /dev/nvidia0");
 
86
                } else {
 
87
                        pollfds.fd = fd;
 
88
                        pollfds.events = 0xffff;
 
89
                        pollfds.revents = 0xffff;
 
90
                        alsaplayer_error("Using NVIDIA poll method for vsync");
 
91
                }        
 
92
                init = 1;       
 
93
        }
 
94
        poll (&pollfds, 1, -1);
 
95
#else
 
96
        dosleep(10000);
 
97
#endif  
 
98
}
 
99
 
 
100
 
 
101
static Window create_window(int width, int height)
 
102
{
 
103
        int attr_list[] = {
 
104
                GLX_RGBA,
 
105
                GLX_DEPTH_SIZE, 16,
 
106
                GLX_DOUBLEBUFFER,
 
107
                None
 
108
        };
 
109
        int scrnum;
 
110
        XSetWindowAttributes attr;
 
111
        unsigned long mask;
 
112
        Window root, win;
 
113
        XVisualInfo *visinfo;
 
114
        Atom wm_protocols[1];
 
115
 
 
116
        if ((dpy = XOpenDisplay(NULL)) == NULL)
 
117
                return 0;
 
118
 
 
119
        scrnum = DefaultScreen(dpy);
 
120
        root = RootWindow(dpy, scrnum);
 
121
 
 
122
        if ((visinfo = glXChooseVisual(dpy, scrnum, attr_list)) == NULL)
 
123
                return 0;
 
124
 
 
125
        attr.background_pixel = 0;
 
126
        attr.border_pixel = 0;
 
127
        attr.colormap = colormap = XCreateColormap(dpy, root,
 
128
                                                   visinfo->visual, AllocNone);
 
129
        attr.event_mask = StructureNotifyMask | KeyPressMask;
 
130
        mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
 
131
 
 
132
        win = XCreateWindow(dpy, root, 0, 0, width, height,
 
133
                            0, visinfo->depth, InputOutput,
 
134
                            visinfo->visual, mask, &attr);
 
135
        XmbSetWMProperties(dpy, win, "OpenGL Spectrum analyzer",
 
136
                           "OpenGL Spectrum analyzer", NULL, 0, NULL, NULL,
 
137
                           NULL);
 
138
        wm_delete_window_atom = wm_protocols[0] =
 
139
                XInternAtom(dpy, "WM_DELETE_WINDOW", False);
 
140
        XSetWMProtocols(dpy, win, wm_protocols, 1);
 
141
 
 
142
        glxcontext = glXCreateContext(dpy, visinfo, NULL, True);
 
143
 
 
144
        XFree(visinfo);
 
145
 
 
146
        glXMakeCurrent(dpy, win, glxcontext);
 
147
 
 
148
        return win;
 
149
}
 
150
 
 
151
 
 
152
static void draw_rectangle(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2)
 
153
{
 
154
        if(y1 == y2)
 
155
        {
 
156
        
 
157
                glVertex3f(x1, y1, z1);
 
158
                glVertex3f(x2, y1, z1);
 
159
                glVertex3f(x2, y2, z2);
 
160
                
 
161
                glVertex3f(x2, y2, z2);
 
162
                glVertex3f(x1, y2, z2);
 
163
                glVertex3f(x1, y1, z1);
 
164
        }
 
165
        else
 
166
        {
 
167
                glVertex3f(x1, y1, z1);
 
168
                glVertex3f(x2, y1, z2);
 
169
                glVertex3f(x2, y2, z2);
 
170
                
 
171
                glVertex3f(x2, y2, z2);
 
172
                glVertex3f(x1, y2, z1);
 
173
                glVertex3f(x1, y1, z1);
 
174
        }
 
175
}
 
176
 
 
177
static void draw_bar(GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, GLfloat green, GLfloat blue )
 
178
{
 
179
        GLfloat width = 0.1;
 
180
 
 
181
        glColor3f(red,green,blue);
 
182
        draw_rectangle(x_offset, height, z_offset, x_offset + width, height, z_offset + 0.1);
 
183
        draw_rectangle(x_offset, 0, z_offset, x_offset + width, 0, z_offset + 0.1);
 
184
        
 
185
        glColor3f(0.5 * red, 0.5 * green, 0.5 * blue);
 
186
        draw_rectangle(x_offset, 0.0, z_offset + 0.1, x_offset + width, height, z_offset + 0.1);
 
187
        draw_rectangle(x_offset, 0.0, z_offset, x_offset + width, height, z_offset );
 
188
 
 
189
        glColor3f(0.25 * red, 0.25 * green, 0.25 * blue);
 
190
        draw_rectangle(x_offset, 0.0, z_offset , x_offset, height, z_offset + 0.1);     
 
191
        draw_rectangle(x_offset + width, 0.0, z_offset , x_offset + width, height, z_offset + 0.1);
 
192
 
 
193
        
 
194
}
 
195
 
 
196
static void draw_bars(void)
 
197
{
 
198
        int x,y;
 
199
        GLfloat x_offset, z_offset, r_base, b_base;
 
200
 
 
201
        
 
202
 
 
203
        glClearColor(0,0,0,0);
 
204
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
205
 
 
206
        glPushMatrix();
 
207
        glTranslatef(0.0,-0.5,-5.0);          
 
208
        glRotatef(x_angle,1.0,0.0,0.0);
 
209
        glRotatef(y_angle,0.0,1.0,0.0);
 
210
        glRotatef(z_angle,0.0,0.0,1.0);
 
211
 
 
212
        glBegin(GL_TRIANGLES);
 
213
        for(y = 0; y < 16; y++)
 
214
        {
 
215
                z_offset = -1.6 + ((15 - y) * 0.2);
 
216
 
 
217
                b_base = y * (1.0 / 15);
 
218
                r_base = 1.0 - b_base;
 
219
                        
 
220
                for(x = 0; x < 16; x++)
 
221
                {
 
222
                        x_offset = -1.6 + (x * 0.2);                    
 
223
                                
 
224
                        draw_bar(x_offset, z_offset, heights[y][x], r_base - (x * (r_base / 15.0)), x * (1.0 / 15), b_base);
 
225
                }
 
226
        }
 
227
        glEnd();
 
228
 
 
229
        glPopMatrix();
 
230
        wait_for_vsync();
 
231
        glXSwapBuffers(dpy,window);
 
232
}
 
233
 
 
234
#define DEFAULT_W       640
 
235
#define DEFAULT_H 480
 
236
 
 
237
void *draw_thread_func(void *arg)
 
238
{
 
239
        Bool configured = FALSE;
 
240
 
 
241
        window_w = prefs_get_int(ap_prefs, "opengl_spectrum", "width", DEFAULT_W);      
 
242
        window_h = prefs_get_int(ap_prefs, "opengl_spectrum", "height", DEFAULT_H);
 
243
        
 
244
        if ((window = create_window(window_w, window_h)) == 0)
 
245
        {
 
246
                alsaplayer_error("unable to create window");
 
247
                pthread_exit(NULL);
 
248
        }
 
249
        
 
250
        XMapWindow(dpy, window);
 
251
 
 
252
        glMatrixMode(GL_PROJECTION);
 
253
        glLoadIdentity();
 
254
        glFrustum(-1, 1, -1, 1, 1.5, 10);
 
255
        glMatrixMode(GL_MODELVIEW);
 
256
        glLoadIdentity();
 
257
        glEnable(GL_DEPTH_TEST);
 
258
        glDepthFunc(GL_LESS);
 
259
 
 
260
        while(going)
 
261
        {
 
262
                while(XPending(dpy))
 
263
                {
 
264
                        XEvent event;
 
265
                        KeySym keysym;
 
266
                        char buf[16];
 
267
                        
 
268
                        XNextEvent(dpy, &event);
 
269
                        switch(event.type)
 
270
                        {
 
271
                        case ConfigureNotify:
 
272
                                glViewport(0,0,event.xconfigure.width, event.xconfigure.height);
 
273
                                window_w = event.xconfigure.width;
 
274
                                window_h = event.xconfigure.height;
 
275
                                prefs_set_int(ap_prefs, "opengl_spectrum", "width", window_w);
 
276
                                prefs_set_int(ap_prefs, "opengl_spectrum", "height", window_h);
 
277
                                configured = TRUE;
 
278
                                break;
 
279
                        case KeyPress:
 
280
 
 
281
                                
 
282
                                XLookupString (&event.xkey, buf, 16, &keysym, NULL);
 
283
                                switch(keysym)
 
284
                                {
 
285
                                case XK_Escape:
 
286
                                        
 
287
                                        going = FALSE;
 
288
                                        break;
 
289
                                case XK_z:
 
290
                                        /*xmms_remote_playlist_prev(oglspectrum_vp.xmms_session); */
 
291
                                        break;
 
292
                                case XK_x:
 
293
                                        /*xmms_remote_play(oglspectrum_vp.xmms_session); */
 
294
                                        break;
 
295
                                case XK_c:
 
296
                                        /*xmms_remote_pause(oglspectrum_vp.xmms_session); */
 
297
                                        break;
 
298
                                case XK_v:
 
299
                                        /*xmms_remote_stop(oglspectrum_vp.xmms_session); */
 
300
                                        break;
 
301
                                case XK_b:
 
302
                                        /* xmms_remote_playlist_next(oglspectrum_vp.xmms_session); */
 
303
                                        break;
 
304
                                case XK_Up:                                     
 
305
                                        x_speed -= 0.1;
 
306
                                        if(x_speed < -3.0)
 
307
                                                x_speed = -3.0;
 
308
                                        break;
 
309
                                case XK_Down:                                   
 
310
                                        x_speed += 0.1;
 
311
                                        if(x_speed > 3.0)
 
312
                                                x_speed = 3.0;
 
313
                                        break;
 
314
                                case XK_Left:
 
315
                                        y_speed -= 0.1;
 
316
                                        if(y_speed < -3.0)
 
317
                                                y_speed = -3.0;
 
318
                                        
 
319
                                        break;
 
320
                                case XK_Right:
 
321
                                        y_speed += 0.1;
 
322
                                        if(y_speed > 3.0)
 
323
                                                y_speed = 3.0;
 
324
                                        break;
 
325
                                case XK_w:
 
326
                                        z_speed -= 0.1;
 
327
                                        if(z_speed < -3.0)
 
328
                                                z_speed = -3.0;
 
329
                                        break;
 
330
                                case XK_q:
 
331
                                        z_speed += 0.1;
 
332
                                        if(z_speed > 3.0)
 
333
                                                z_speed = 3.0;
 
334
                                        break;
 
335
                                case XK_Return:
 
336
                                        x_speed = 0.0;
 
337
                                        y_speed = 0.5;
 
338
                                        z_speed = 0.0;
 
339
                                        x_angle = 20.0;
 
340
                                        y_angle = 45.0;
 
341
                                        z_angle = 0.0;
 
342
                                        break;                                  
 
343
                                }
 
344
                                
 
345
                                break;
 
346
                        case ClientMessage:
 
347
                                if ((Atom)event.xclient.data.l[0] == wm_delete_window_atom)
 
348
                                {
 
349
                                        going = FALSE;
 
350
                                }
 
351
                                break;
 
352
                        }
 
353
                }
 
354
                if(configured)
 
355
                {
 
356
                        x_angle += x_speed;
 
357
                        if(x_angle >= 360.0)
 
358
                                x_angle -= 360.0;
 
359
                        
 
360
                        y_angle += y_speed;
 
361
                        if(y_angle >= 360.0)
 
362
                                y_angle -= 360.0;
 
363
 
 
364
                        z_angle += z_speed;
 
365
                        if(z_angle >= 360.0)
 
366
                                z_angle -= 360.0;
 
367
 
 
368
                        draw_bars();
 
369
                }
 
370
        }
 
371
 
 
372
        if (glxcontext)
 
373
        {
 
374
                glXMakeCurrent(dpy, 0, NULL);
 
375
                glXDestroyContext(dpy, glxcontext);
 
376
                glxcontext = NULL;
 
377
        }
 
378
        if (window)
 
379
        {
 
380
                if (grabbed_pointer)
 
381
                {
 
382
                        XUngrabPointer(dpy, CurrentTime);
 
383
                        grabbed_pointer = FALSE;
 
384
                }
 
385
 
 
386
                XDestroyWindow(dpy, window);
 
387
                window = 0;
 
388
        }
 
389
        pthread_mutex_unlock(&scope_mutex);
 
390
        stop_display(0); /* Close down display */
 
391
        pthread_exit(NULL);
 
392
}
 
393
 
 
394
static void start_display(void)
 
395
{
 
396
        int x, y;
 
397
 
 
398
        for(x = 0; x < 16; x++)
 
399
        {
 
400
                for(y = 0; y < 16; y++)
 
401
                {
 
402
                        heights[y][x] = 0.0;
 
403
                }
 
404
        }
 
405
        scale = 1.0 / log(256.0);
 
406
 
 
407
        x_speed = 0.0;
 
408
        y_speed = 0.5;
 
409
        z_speed = 0.0;
 
410
        x_angle = 20.0;
 
411
        y_angle = 45.0;
 
412
        z_angle = 0.0;
 
413
 
 
414
        going = TRUE;
 
415
        pthread_create(&draw_thread, NULL, draw_thread_func, NULL);
 
416
}
 
417
 
 
418
static void stop_display(int join_thread)
 
419
{
 
420
        if (going && join_thread)
 
421
        {
 
422
                going = FALSE;
 
423
                pthread_join(draw_thread, NULL);
 
424
        }
 
425
 
 
426
        if (colormap)
 
427
        {
 
428
                XFreeColormap(dpy, colormap);
 
429
                colormap = 0;
 
430
        }
 
431
        if (dpy)
 
432
        {
 
433
                XCloseDisplay(dpy);
 
434
                dpy = NULL;
 
435
        }
 
436
}
 
437
 
 
438
static int oglspectrum_init(void *arg)
 
439
{
 
440
        pthread_mutex_init(&scope_mutex, NULL);
 
441
 
 
442
        if (prefs_get_bool(ap_prefs, "opengl_spectrum", "active", 0)) {
 
443
                oglspectrum_start();
 
444
        }
 
445
        return 1;               
 
446
}       
 
447
 
 
448
static void oglspectrum_cleanup(void)
 
449
{
 
450
        stop_display(1);
 
451
}
 
452
 
 
453
static void oglspectrum_start(void)
 
454
{
 
455
        if (pthread_mutex_trylock(&scope_mutex) != 0) {
 
456
                alsaplayer_error("spectrum already running");
 
457
                return;
 
458
        }       
 
459
        start_display();
 
460
}
 
461
 
 
462
static void oglspectrum_stop(void)
 
463
{
 
464
        stop_display(1);
 
465
}
 
466
 
 
467
static void oglspectrum_set_fft(void *fft_buffer, int samples, int channels)
 
468
{
 
469
        int i,c;
 
470
        int y;
 
471
        GLfloat val;
 
472
        int *buf = (int *)fft_buffer;
 
473
 
 
474
        
 
475
        int xscale[] = {0, 1, 2, 3, 5, 7, 10, 14, 20, 28, 40, 54, 74, 101, 137, 187, 255};
 
476
 
 
477
        for(y = 15; y > 0; y--) {
 
478
                for(i = 0; i < 16; i++) {
 
479
                        heights[y][i] = heights[y - 1][i];
 
480
                }
 
481
        }
 
482
        
 
483
        for(i = 0; i < NUM_BANDS; i++) {
 
484
                for(c = xscale[i], y = 0; c < xscale[i + 1]; c++) {
 
485
                        if((buf[c]+buf[samples+c]) > y)
 
486
                                y = buf[c]+buf[samples+c];
 
487
                }
 
488
                y >>= 7;
 
489
                if(y > 0)
 
490
                        val = (log(y) * scale);
 
491
                else
 
492
                        val = 0;
 
493
                heights[0][i] = val;
 
494
        }
 
495
}
 
496
 
 
497
static int oglspectrum_running(void)
 
498
{
 
499
        return going;
 
500
}
 
501
 
 
502
static void oglspectrum_shutdown(void)
 
503
{
 
504
        prefs_set_bool(ap_prefs, "opengl_spectrum", "active", oglspectrum_running());
 
505
        if (oglspectrum_running()) {
 
506
                oglspectrum_stop();
 
507
        }
 
508
}
 
509
 
 
510
 
 
511
scope_plugin oglspectrum_plugin = {
 
512
        SCOPE_PLUGIN_VERSION,
 
513
        "Spectrum GL",
 
514
        "Andy Lo A Foe",
 
515
        NULL,
 
516
        oglspectrum_init,
 
517
        oglspectrum_start,
 
518
        oglspectrum_running,
 
519
        oglspectrum_stop,
 
520
        oglspectrum_shutdown,
 
521
        NULL,
 
522
        oglspectrum_set_fft
 
523
};
 
524
 
 
525
 
 
526
scope_plugin *scope_plugin_info(void)
 
527
{
 
528
        return &oglspectrum_plugin;
 
529
}
 
530