~ubuntu-branches/ubuntu/oneiric/cairo-dock-plug-ins/oneiric-updates

« back to all changes in this revision

Viewing changes to Impulse/src/Impulse.c

  • Committer: Kees Cook
  • Date: 2011-08-11 23:17:39 UTC
  • mfrom: (20.1.1 cairo-dock-plug-ins)
  • Revision ID: kees@outflux.net-20110811231739-cteedan51tmdg77v
Tags: 2.4.0~0beta2-0ubuntu1
releasing version 2.4.0~0beta2-0ubuntu1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *+  Copyright (c) 2009 Ian Halpern
 
4
 *@  http://impulse.ian-halpern.com
 
5
 *
 
6
 *   This file is part of Impulse.
 
7
 *
 
8
 *   Impulse 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
 *   Impulse 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 Impulse.  If not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
 
 
22
#include <pulse/pulseaudio.h>
 
23
#include <assert.h>
 
24
#include <string.h>
 
25
#include <stdint.h>
 
26
#include <fftw3.h>
 
27
#include <math.h>
 
28
 
 
29
#include "Impulse.h"
 
30
 
 
31
#define CHUNK 1024
 
32
 
 
33
static const long fft_max[] = { 12317168L, 7693595L, 5863615L, 4082974L, 5836037L, 4550263L, 3377914L, 3085778L, 3636534L, 3751823L, 2660548L, 3313252L, 2698853L, 2186441L, 1697466L, 1960070L, 1286950L, 1252382L, 1313726L, 1140443L, 1345589L, 1269153L, 897605L, 900408L, 892528L, 587972L, 662925L, 668177L, 686784L, 656330L, 1580286L, 785491L, 761213L, 730185L, 851753L, 927848L, 891221L, 634291L, 833909L, 646617L, 804409L, 1015627L, 671714L, 813811L, 689614L, 727079L, 853936L, 819333L, 679111L, 730295L, 836287L, 1602396L, 990827L, 773609L, 733606L, 638993L, 604530L, 573002L, 634570L, 1015040L, 679452L, 672091L, 880370L, 1140558L, 1593324L, 686787L, 781368L, 605261L, 1190262L, 525205L, 393080L, 409546L, 436431L, 723744L, 765299L, 393927L, 322105L, 478074L, 458596L, 512763L, 381303L, 671156L, 1177206L, 476813L, 366285L, 436008L, 361763L, 252316L, 204433L, 291331L, 296950L, 329226L, 319209L, 258334L, 388701L, 543025L, 396709L, 296099L, 190213L, 167976L, 138928L, 116720L, 163538L, 331761L, 133932L, 187456L, 530630L, 131474L, 84888L, 82081L, 122379L, 82914L, 75510L, 62669L, 73492L, 68775L, 57121L, 94098L, 68262L, 68307L, 48801L, 46864L, 61480L, 46607L, 45974L, 45819L, 45306L, 45110L, 45175L, 44969L, 44615L, 44440L, 44066L, 43600L, 57117L, 43332L, 59980L, 55319L, 54385L, 81768L, 51165L, 54785L, 73248L, 52494L, 57252L, 61869L, 65900L, 75893L, 65152L, 108009L, 421578L, 152611L, 135307L, 254745L, 132834L, 169101L, 137571L, 141159L, 142151L, 211389L, 267869L, 367730L, 256726L, 185238L, 251197L, 204304L, 284443L, 258223L, 158730L, 228565L, 375950L, 294535L, 288708L, 351054L, 694353L, 477275L, 270576L, 426544L, 362456L, 441219L, 313264L, 300050L, 421051L, 414769L, 244296L, 292822L, 262203L, 418025L, 579471L, 418584L, 419449L, 405345L, 739170L, 488163L, 376361L, 339649L, 313814L, 430849L, 275287L, 382918L, 297214L, 286238L, 367684L, 303578L, 516246L, 654782L, 353370L, 417745L, 392892L, 418934L, 475608L, 284765L, 260639L, 288961L, 301438L, 301305L, 329190L, 252484L, 272364L, 261562L, 208419L, 203045L, 229716L, 191240L, 328251L, 267655L, 322116L, 509542L, 498288L, 341654L, 346341L, 451042L, 452194L, 467716L, 447635L, 644331L, 1231811L, 1181923L, 1043922L, 681166L, 1078456L, 1088757L, 1221378L, 1358397L, 1817252L, 1255182L, 1410357L, 2264454L, 1880361L, 1630934L, 1147988L, 1919954L, 1624734L, 1373554L, 1865118L, 2431931L };
 
34
 
 
35
static uint32_t source_index = 0;
 
36
static int context_ready = 0;
 
37
static int16_t buffer[ CHUNK / 2 ], snapshot[ CHUNK / 2 ];
 
38
static size_t buffer_index = 0;
 
39
 
 
40
static pa_context *context = NULL;
 
41
static pa_stream *stream = NULL;
 
42
static pa_threaded_mainloop* mainloop = NULL;
 
43
static pa_io_event* stdio_event = NULL;
 
44
static pa_mainloop_api *mainloop_api = NULL;
 
45
static char *stream_name = NULL, *client_name = NULL, *device = NULL;
 
46
 
 
47
static pa_sample_spec sample_spec = {
 
48
        .format = PA_SAMPLE_S16LE,
 
49
        .rate = 44100,
 
50
        .channels = 2
 
51
};
 
52
 
 
53
static pa_stream_flags_t flags = 0;
 
54
 
 
55
static pa_channel_map channel_map;
 
56
static int channel_map_set = 0;
 
57
 
 
58
/* A shortcut for terminating the application */
 
59
static void quit( int ret ) {
 
60
        assert( mainloop_api );
 
61
        mainloop_api->quit( mainloop_api, ret );
 
62
}
 
63
 
 
64
static void unmute_source_success_cb( pa_context *c, int success, void *userdata ) {
 
65
        // printf("unmute: %d\n", success);
 
66
}
 
67
 
 
68
static void get_source_info_callback( pa_context *c, const pa_source_info *i, int is_last, void *userdata ) {
 
69
 
 
70
        if ( !i )
 
71
                return;
 
72
 
 
73
        // printf("source index: %u\n", i->index );
 
74
 
 
75
        // snprintf(t, sizeof(t), "%u", i->monitor_of_sink);
 
76
 
 
77
//      if ( i->monitor_of_sink != PA_INVALID_INDEX ) {
 
78
                puts( i->name );
 
79
        //      if ( device && strcmp( device, i->name ) == 0 ) return;
 
80
 
 
81
                device = pa_xstrdup( i->name );
 
82
 
 
83
                if ( ( pa_stream_connect_record( stream, device, NULL, flags ) ) < 0 ) {
 
84
                        fprintf(stderr, "pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(c)));
 
85
                        quit(1);
 
86
                }
 
87
//      }
 
88
}
 
89
 
 
90
/* This is called whenever new data is available */
 
91
static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {
 
92
        const void *data;
 
93
        assert(s);
 
94
        assert(length > 0);
 
95
//      printf("stream index: %d\n", pa_stream_get_index( s ) );
 
96
        if (stdio_event)
 
97
                mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);
 
98
 
 
99
        if (pa_stream_peek(s, &data, &length) < 0) {
 
100
                fprintf(stderr, "pa_stream_peek() failed: %s\n", pa_strerror(pa_context_errno(context)));
 
101
                quit(1);
 
102
                return;
 
103
        }
 
104
 
 
105
        assert(data);
 
106
        assert(length > 0);
 
107
 
 
108
        int excess = buffer_index * 2 + length - ( CHUNK );
 
109
 
 
110
        if ( excess < 0 ) excess = 0;
 
111
 
 
112
        memcpy( buffer + buffer_index, data, length - excess );
 
113
        buffer_index += ( length - excess ) / 2;
 
114
 
 
115
        if ( excess ) {
 
116
                memcpy( snapshot, buffer, buffer_index * 2 );
 
117
                buffer_index = 0;
 
118
        }
 
119
 
 
120
        pa_stream_drop(s);
 
121
}
 
122
 
 
123
static void stream_state_callback( pa_stream *s, void* userdata );
 
124
 
 
125
static void init_source_stream_for_recording(void) {
 
126
 
 
127
        if (!(stream = pa_stream_new( context, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL))) {
 
128
                fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(context)));
 
129
                quit(1);
 
130
        }
 
131
 
 
132
        pa_stream_set_read_callback(stream, stream_read_callback, NULL);
 
133
        pa_stream_set_state_callback( stream, stream_state_callback, NULL );
 
134
        pa_operation_unref( pa_context_set_source_mute_by_index( context, source_index, 0, unmute_source_success_cb, NULL ) );
 
135
        pa_operation_unref( pa_context_get_source_info_by_index( context, source_index, get_source_info_callback, NULL ) );
 
136
}
 
137
 
 
138
static void stream_state_callback( pa_stream *s, void* userdata ) {
 
139
        if ( pa_stream_get_state( s ) == PA_STREAM_TERMINATED ) {
 
140
                pa_stream_unref( stream );
 
141
                init_source_stream_for_recording();
 
142
        }
 
143
}
 
144
 
 
145
static void context_state_callback( pa_context *c, void *userdata ) {
 
146
 
 
147
        switch (pa_context_get_state(c)) {
 
148
                case PA_CONTEXT_CONNECTING:
 
149
                case PA_CONTEXT_AUTHORIZING:
 
150
                case PA_CONTEXT_SETTING_NAME:
 
151
                        break;
 
152
                case PA_CONTEXT_READY:
 
153
                        assert(c);
 
154
                        assert(!stream);
 
155
 
 
156
                        /*if (!(stream = pa_stream_new(c, stream_name, &sample_spec, channel_map_set ? &channel_map : NULL))) {
 
157
                                fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c)));
 
158
                                quit(1);
 
159
                        }
 
160
 
 
161
                        pa_stream_set_read_callback(stream, stream_read_callback, NULL);*/
 
162
                        init_source_stream_for_recording();
 
163
 
 
164
                        break;
 
165
                case PA_CONTEXT_TERMINATED:
 
166
                        quit(0);
 
167
                        break;
 
168
 
 
169
                case PA_CONTEXT_FAILED:
 
170
                default:
 
171
                        fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c)));
 
172
                        quit(1);
 
173
        }
 
174
}
 
175
 
 
176
int im_context_state (void)
 
177
{
 
178
        if (context == NULL)
 
179
        return IM_FAILED;
 
180
 
 
181
        switch (pa_context_get_state (context))
 
182
        {
 
183
                case PA_CONTEXT_CONNECTING:
 
184
                case PA_CONTEXT_AUTHORIZING:
 
185
                case PA_CONTEXT_SETTING_NAME:
 
186
                        return IM_SUCCESS;
 
187
                case PA_CONTEXT_TERMINATED:
 
188
                case PA_CONTEXT_FAILED:
 
189
                default:
 
190
                        return IM_FAILED;
 
191
        }
 
192
}
 
193
 
 
194
void im_stop (void) {
 
195
 
 
196
        pa_threaded_mainloop_stop( mainloop );
 
197
 
 
198
        printf( "exit\n" );
 
199
}
 
200
 
 
201
void im_setSourceIndex( uint32_t index ) {
 
202
        source_index = index;
 
203
        if ( !stream ) return;
 
204
 
 
205
        if ( pa_stream_get_state( stream ) != PA_STREAM_UNCONNECTED )
 
206
                pa_stream_disconnect( stream );
 
207
        else
 
208
                init_source_stream_for_recording();
 
209
}
 
210
 
 
211
double *im_getSnapshot( int fft ) {
 
212
 
 
213
        static double magnitude[ CHUNK / 4 ];
 
214
 
 
215
        if ( ! fft ) {
 
216
                int i;
 
217
                for ( i = 0; i < CHUNK / 2; i += sample_spec.channels ) {
 
218
                        magnitude[ i / sample_spec.channels ] = 0;
 
219
                        int j;
 
220
                        for ( j = 0; j < sample_spec.channels; j++ )
 
221
                                magnitude[ i / sample_spec.channels ] += fabs( ( (double) snapshot[ i + j ] / ( pow( 2, 16 ) / 2 ) ) / sample_spec.channels );
 
222
                }
 
223
        } else {
 
224
 
 
225
                double *in;
 
226
                fftw_complex *out;
 
227
                fftw_plan p;
 
228
 
 
229
                in = (double*) malloc( sizeof( double ) * ( CHUNK / 2 ) );
 
230
                out = (fftw_complex*) fftw_malloc( sizeof( fftw_complex ) * ( CHUNK / 2 ) );
 
231
 
 
232
                if ( snapshot != NULL ) {
 
233
                        int i;
 
234
                        for ( i = 0; i < CHUNK / 2; i++ ) {
 
235
                                in[ i ] = (double) snapshot[ i ];
 
236
                        }
 
237
                }
 
238
 
 
239
                p = fftw_plan_dft_r2c_1d( CHUNK / 2, in, out, 0 );
 
240
 
 
241
                fftw_execute( p );
 
242
 
 
243
                fftw_destroy_plan( p );
 
244
 
 
245
                if ( out != NULL ) {
 
246
                        int i;
 
247
                        for ( i = 0; i < CHUNK / 2 / sample_spec.channels; i++ ) {
 
248
                                magnitude[ i ] = (double) sqrt( pow( out[ i ][ 0 ], 2 ) + pow( out[ i ][ 1 ], 2 ) ) / (double) fft_max[ i ];
 
249
                                if ( magnitude[ i ] > 1.0 ) magnitude[ i ] = 1.0;
 
250
                        }
 
251
                }
 
252
 
 
253
                free( in );
 
254
                fftw_free(out);
 
255
        }
 
256
 
 
257
        return magnitude; // PyString_FromStringAndSize( (char *) snapshot, CHUNK );
 
258
}
 
259
 
 
260
 
 
261
void im_start ( void ) {
 
262
 
 
263
        // Pulseaudio
 
264
        int r;
 
265
        char *server = NULL;
 
266
 
 
267
        client_name = pa_xstrdup( "impulse" );
 
268
        stream_name = pa_xstrdup( "impulse" );
 
269
 
 
270
        // Set up a new main loop
 
271
 
 
272
        if ( ! ( mainloop = pa_threaded_mainloop_new( ) ) ) {
 
273
                fprintf( stderr, "pa_mainloop_new() failed.\n" );
 
274
                return; // IM_FAILED;
 
275
        }
 
276
 
 
277
        mainloop_api = pa_threaded_mainloop_get_api( mainloop );
 
278
 
 
279
        r = pa_signal_init( mainloop_api );
 
280
        assert( r == 0 );
 
281
 
 
282
        /*if (!(stdio_event = mainloop_api->io_new(mainloop_api,
 
283
                                                                                         STDOUT_FILENO,
 
284
                                                                                         PA_IO_EVENT_OUTPUT,
 
285
                                                                                         stdout_callback, NULL))) {
 
286
                fprintf(stderr, "io_new() failed.\n");
 
287
                goto quit;
 
288
        }*/
 
289
 
 
290
        // create a new connection context
 
291
        if ( ! ( context = pa_context_new( mainloop_api, client_name ) ) ) {
 
292
                fprintf( stderr, "pa_context_new() failed.\n" );
 
293
                return; // IM_FAILED;
 
294
        }
 
295
 
 
296
        pa_context_set_state_callback( context, context_state_callback, NULL );
 
297
 
 
298
        /* Connect the context */
 
299
        pa_context_connect( context, server, 0, NULL );
 
300
 
 
301
        // pulseaudio thread
 
302
        pa_threaded_mainloop_start( mainloop );
 
303
 
 
304
        return; // context_state (context);
 
305
}