~ubuntu-branches/ubuntu/quantal/banshee/quantal

« back to all changes in this revision

Viewing changes to .pc/0001-libbanshee-Remove-unused-wanted_size-variable.patch/libbanshee/banshee-player-vis.c

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-12 01:40:00 UTC
  • mfrom: (6.3.20 experimental)
  • Revision ID: package-import@ubuntu.com-20111212014000-0q4jsvif0oecyth8
Tags: 2.3.2-1ubuntu1
* Merge from Debian Experimental, remaining changes:
  + Enable and recommend SoundMenu and Disable NotificationArea by default
  + Disable boo and karma extensions
  + Enable and suggest u1ms
  + Move desktop file for Meego UI to /usr/share/une/applications
  + Change the url for the Amazon store redirector
  + [08dea2c] Revert "Fix invalid cast causing ftbfs with libgpod"

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// banshee-player-vis.c
3
 
//
4
 
// Author:
5
 
//   Chris Howie <cdhowie@gmail.com>
6
 
//
7
 
// Copyright (C) 2008 Chris Howie
8
 
//
9
 
// Permission is hereby granted, free of charge, to any person obtaining
10
 
// a copy of this software and associated documentation files (the
11
 
// "Software"), to deal in the Software without restriction, including
12
 
// without limitation the rights to use, copy, modify, merge, publish,
13
 
// distribute, sublicense, and/or sell copies of the Software, and to
14
 
// permit persons to whom the Software is furnished to do so, subject to
15
 
// the following conditions:
16
 
//
17
 
// The above copyright notice and this permission notice shall be
18
 
// included in all copies or substantial portions of the Software.
19
 
//
20
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
 
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
 
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
 
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
 
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
 
//
28
 
 
29
 
#include <math.h>
30
 
 
31
 
#include "banshee-player-vis.h"
32
 
 
33
 
#define SLICE_SIZE 735
34
 
 
35
 
static GstStaticCaps vis_data_sink_caps = GST_STATIC_CAPS (
36
 
    "audio/x-raw-float, "
37
 
    "rate = (int) 44100, "
38
 
    "channels = (int) 2, "
39
 
    "endianness = (int) BYTE_ORDER, "
40
 
    "width = (int) 32"
41
 
);
42
 
 
43
 
// ---------------------------------------------------------------------------
44
 
// Private Functions
45
 
// ---------------------------------------------------------------------------
46
 
 
47
 
static void
48
 
bp_vis_pcm_handoff (GstElement *sink, GstBuffer *buffer, GstPad *pad, gpointer userdata)
49
 
{
50
 
    BansheePlayer *player = (BansheePlayer*)userdata;
51
 
    GstStructure *structure;
52
 
    gint channels, wanted_size;
53
 
    gfloat *data;
54
 
    BansheePlayerVisDataCallback vis_data_cb;
55
 
    
56
 
    g_return_if_fail (IS_BANSHEE_PLAYER (player));
57
 
    
58
 
    vis_data_cb = player->vis_data_cb;
59
 
 
60
 
    if (vis_data_cb == NULL) {
61
 
        return;
62
 
    }
63
 
 
64
 
    if (player->vis_thawing) {
65
 
        // Flush our buffers out.
66
 
        gst_adapter_clear (player->vis_buffer);
67
 
        memset (player->vis_fft_sample_buffer, 0, sizeof(gfloat) * SLICE_SIZE);
68
 
 
69
 
        player->vis_thawing = FALSE;
70
 
    }
71
 
    
72
 
    structure = gst_caps_get_structure (gst_buffer_get_caps (buffer), 0);
73
 
    gst_structure_get_int (structure, "channels", &channels);
74
 
    
75
 
    wanted_size = channels * SLICE_SIZE * sizeof (gfloat);
76
 
 
77
 
    gst_adapter_push (player->vis_buffer, gst_buffer_copy (buffer));
78
 
    
79
 
    while ((data = (gfloat *)gst_adapter_peek (player->vis_buffer, wanted_size)) != NULL) {
80
 
        gfloat *deinterlaced = g_malloc (wanted_size);
81
 
        gfloat *specbuf = g_new (gfloat, SLICE_SIZE * 2);
82
 
 
83
 
        gint i, j;
84
 
 
85
 
        memcpy (specbuf, player->vis_fft_sample_buffer, SLICE_SIZE * sizeof(gfloat));
86
 
        
87
 
        for (i = 0; i < SLICE_SIZE; i++) {
88
 
            gfloat avg = 0.0f;
89
 
 
90
 
            for (j = 0; j < channels; j++) {
91
 
                gfloat sample = data[i * channels + j];
92
 
 
93
 
                deinterlaced[j * SLICE_SIZE + i] = sample;
94
 
                avg += sample;
95
 
            }
96
 
 
97
 
            avg /= channels;
98
 
            specbuf[i + SLICE_SIZE] = avg;
99
 
        }
100
 
 
101
 
        memcpy (player->vis_fft_sample_buffer, &specbuf[SLICE_SIZE], SLICE_SIZE * sizeof(gfloat));
102
 
 
103
 
        gst_fft_f32_window (player->vis_fft, specbuf, GST_FFT_WINDOW_HAMMING);
104
 
        gst_fft_f32_fft (player->vis_fft, specbuf, player->vis_fft_buffer);
105
 
 
106
 
        for (i = 0; i < SLICE_SIZE; i++) {
107
 
            gfloat val;
108
 
 
109
 
            GstFFTF32Complex cplx = player->vis_fft_buffer[i];
110
 
 
111
 
            val = cplx.r * cplx.r + cplx.i * cplx.i;
112
 
            val /= SLICE_SIZE * SLICE_SIZE;
113
 
            val = 10.0f * log10f(val);
114
 
 
115
 
            val = (val + 60.0f) / 60.0f;
116
 
            if (val < 0.0f)
117
 
                val = 0.0f;
118
 
 
119
 
            specbuf[i] = val;
120
 
        }
121
 
 
122
 
        vis_data_cb (player, channels, SLICE_SIZE, deinterlaced, SLICE_SIZE, specbuf);
123
 
        
124
 
        g_free (deinterlaced);
125
 
        g_free (specbuf);
126
 
 
127
 
        gst_adapter_flush (player->vis_buffer, wanted_size);
128
 
    }
129
 
}
130
 
 
131
 
// ---------------------------------------------------------------------------
132
 
// Internal Functions
133
 
// ---------------------------------------------------------------------------
134
 
 
135
 
static void
136
 
_bp_vis_pipeline_block_callback (GstPad *pad, gboolean blocked, gpointer data)
137
 
{
138
 
    BansheePlayer *player = (BansheePlayer *) data;
139
 
 
140
 
    if (!blocked) {
141
 
        // Set thawing mode (discards buffers that are too old from the queue).
142
 
        player->vis_thawing = TRUE;
143
 
    }
144
 
}
145
 
 
146
 
static void
147
 
_bp_vis_pipeline_set_blocked (BansheePlayer *player, gboolean blocked)
148
 
{
149
 
    GstPad *queue_sink;
150
 
 
151
 
    if (player->vis_resampler == NULL)
152
 
        return;
153
 
 
154
 
    queue_sink = gst_element_get_static_pad (player->vis_resampler, "src");
155
 
 
156
 
    gst_pad_set_blocked_async (queue_sink, blocked, _bp_vis_pipeline_block_callback, (gpointer) player);
157
 
 
158
 
    gst_object_unref (GST_OBJECT (queue_sink));
159
 
}
160
 
 
161
 
static gboolean
162
 
_bp_vis_pipeline_event_probe (GstPad *pad, GstEvent *event, gpointer data)
163
 
{
164
 
    BansheePlayer *player = (BansheePlayer *) data;
165
 
 
166
 
    switch (GST_EVENT_TYPE (event)) {
167
 
        case GST_EVENT_FLUSH_START:
168
 
        case GST_EVENT_FLUSH_STOP:
169
 
        case GST_EVENT_SEEK:
170
 
        case GST_EVENT_NEWSEGMENT:
171
 
        case GST_EVENT_CUSTOM_DOWNSTREAM:
172
 
            player->vis_thawing = TRUE;
173
 
 
174
 
        default: break;
175
 
    }
176
 
 
177
 
    if (player->vis_enabled)
178
 
        return TRUE;
179
 
 
180
 
    switch (GST_EVENT_TYPE (event)) {
181
 
    case GST_EVENT_EOS:
182
 
    case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
183
 
        _bp_vis_pipeline_set_blocked (player, FALSE);
184
 
        break;
185
 
    case GST_EVENT_CUSTOM_DOWNSTREAM:
186
 
    case GST_EVENT_NEWSEGMENT:
187
 
        _bp_vis_pipeline_set_blocked (player, TRUE);
188
 
        break;
189
 
 
190
 
    default: break;
191
 
    }
192
 
 
193
 
    return TRUE;
194
 
}
195
 
 
196
 
void
197
 
_bp_vis_pipeline_setup (BansheePlayer *player)
198
 
{
199
 
    // The basic pipeline we're constructing is:
200
 
    // .audiotee ! queue ! audioresample ! audioconvert ! fakesink
201
 
 
202
 
    GstElement *fakesink, *converter, *resampler, *audiosinkqueue;
203
 
    GstCaps *caps;
204
 
    GstPad *teepad;
205
 
    GstPad *pad;
206
 
    gint wanted_size;
207
 
    
208
 
    player->vis_buffer = NULL;
209
 
    player->vis_fft = gst_fft_f32_new (SLICE_SIZE * 2, FALSE);
210
 
    player->vis_fft_buffer = g_new (GstFFTF32Complex, SLICE_SIZE + 1);
211
 
    player->vis_fft_sample_buffer = g_new0 (gfloat, SLICE_SIZE);
212
 
    
213
 
    // Core elements, if something fails here, it's the end of the world
214
 
    audiosinkqueue = gst_element_factory_make ("queue", "vis-queue");
215
 
 
216
 
    pad = gst_element_get_static_pad (audiosinkqueue, "sink");
217
 
    gst_pad_add_event_probe (pad, G_CALLBACK (_bp_vis_pipeline_event_probe), player);
218
 
    gst_object_unref (GST_OBJECT (pad));
219
 
 
220
 
    resampler = gst_element_factory_make ("audioresample", "vis-resample");
221
 
    converter = gst_element_factory_make ("audioconvert", "vis-convert");
222
 
    fakesink = gst_element_factory_make ("fakesink", "vis-sink");
223
 
 
224
 
    // channels * slice size * float size = size of chunks we want
225
 
    wanted_size = 2 * SLICE_SIZE * sizeof(gfloat);
226
 
 
227
 
    if (audiosinkqueue == NULL || resampler == NULL || converter == NULL || fakesink == NULL) {
228
 
        bp_debug ("Could not construct visualization pipeline, a fundamental element could not be created");
229
 
        return;
230
 
    }
231
 
 
232
 
    // Keep around the 5 most recent seconds of audio so that when resuming
233
 
    // visualization we have something to show right away.
234
 
    g_object_set (G_OBJECT (audiosinkqueue),
235
 
            "leaky", 2,
236
 
            "max-size-buffers", 0,
237
 
            "max-size-bytes", 0,
238
 
            "max-size-time", GST_SECOND * 5,
239
 
            NULL);
240
 
    
241
 
    g_signal_connect (G_OBJECT (fakesink), "handoff", G_CALLBACK (bp_vis_pcm_handoff), player);
242
 
 
243
 
    g_object_set (G_OBJECT (fakesink),
244
 
            // This enables the handoff signal.
245
 
            "signal-handoffs", TRUE,
246
 
            // Synchronize so we see vis at the same time as we hear it.
247
 
            "sync", TRUE,
248
 
            // Drop buffers if they come in too late.  This is mainly used when
249
 
            // thawing the vis pipeline.
250
 
            "max-lateness", GST_SECOND / 120,
251
 
            // Deliver buffers one frame early.  This allows for rendering
252
 
            // time.  (TODO: It would be great to calculate this on-the-fly so
253
 
            // we match the rendering time.
254
 
            "ts-offset", -GST_SECOND / 60,
255
 
            // Don't go to PAUSED when we freeze the pipeline.
256
 
            "async", FALSE, NULL);
257
 
    
258
 
    gst_bin_add_many (GST_BIN (player->audiobin), audiosinkqueue, resampler,
259
 
                      converter, fakesink, NULL);
260
 
    
261
 
    pad = gst_element_get_static_pad (audiosinkqueue, "sink");
262
 
    teepad = gst_element_get_request_pad (player->audiotee, "src%d");
263
 
    gst_pad_link (teepad, pad);
264
 
    gst_object_unref (GST_OBJECT (teepad));
265
 
    gst_object_unref (GST_OBJECT (pad));
266
 
    
267
 
    gst_element_link_many (audiosinkqueue, resampler, converter, NULL);
268
 
    
269
 
    caps = gst_static_caps_get (&vis_data_sink_caps);
270
 
    gst_element_link_filtered (converter, fakesink, caps);
271
 
    gst_caps_unref (caps);
272
 
    
273
 
    player->vis_buffer = gst_adapter_new ();
274
 
    player->vis_resampler = resampler;
275
 
    player->vis_thawing = FALSE;
276
 
    player->vis_enabled = FALSE;
277
 
 
278
 
    // Disable the pipeline till we hear otherwise from managed land.
279
 
    _bp_vis_pipeline_set_blocked (player, TRUE);
280
 
}
281
 
 
282
 
void
283
 
_bp_vis_pipeline_destroy (BansheePlayer *player)
284
 
{
285
 
    if (player->vis_buffer != NULL) {
286
 
        gst_object_unref (player->vis_buffer);
287
 
        player->vis_buffer = NULL;
288
 
    }
289
 
 
290
 
    if (player->vis_fft != NULL) {
291
 
        gst_fft_f32_free (player->vis_fft);
292
 
        player->vis_fft = NULL;
293
 
    }
294
 
 
295
 
    if (player->vis_fft_buffer != NULL) {
296
 
        g_free (player->vis_fft_buffer);
297
 
        player->vis_fft_buffer = NULL;
298
 
    }
299
 
 
300
 
    if (player->vis_fft_sample_buffer != NULL) {
301
 
        g_free (player->vis_fft_sample_buffer);
302
 
        player->vis_fft_sample_buffer = NULL;
303
 
    }
304
 
 
305
 
    player->vis_resampler = NULL;
306
 
    player->vis_enabled = FALSE;
307
 
    player->vis_thawing = FALSE;
308
 
}
309
 
 
310
 
// ---------------------------------------------------------------------------
311
 
// Public Functions
312
 
// ---------------------------------------------------------------------------
313
 
 
314
 
P_INVOKE void
315
 
bp_set_vis_data_callback (BansheePlayer *player, BansheePlayerVisDataCallback cb)
316
 
{
317
 
    if (player == NULL)
318
 
        return;
319
 
 
320
 
    player->vis_data_cb = cb;
321
 
 
322
 
    _bp_vis_pipeline_set_blocked (player, cb == NULL);
323
 
    player->vis_enabled = cb != NULL;
324
 
}