~ubuntu-branches/ubuntu/saucy/flac/saucy

« back to all changes in this revision

Viewing changes to src/plugin_winamp2/in_flac.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Zimmerman
  • Date: 2001-12-10 03:09:22 UTC
  • Revision ID: james.westby@ubuntu.com-20011210030922-0vdtpz6a7mfwefo5
Tags: upstream-1.0.2
ImportĀ upstreamĀ versionĀ 1.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* in_flac - Winamp2 FLAC input plugin
 
2
 * Copyright (C) 2000,2001  Josh Coalson
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version 2
 
7
 * of the License, or (at your option) any later version.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 */
 
18
 
 
19
#include <windows.h>
 
20
#include <mmreg.h>
 
21
#include <msacm.h>
 
22
#include <math.h>
 
23
 
 
24
#include "in2.h"
 
25
#include "FLAC/all.h"
 
26
 
 
27
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
 
28
{
 
29
        return TRUE;
 
30
}
 
31
 
 
32
/* post this to the main window at end of file (after playback as stopped) */
 
33
#define WM_WA_MPEG_EOF WM_USER+2
 
34
 
 
35
typedef struct {
 
36
        FLAC__bool abort_flag;
 
37
        unsigned total_samples;
 
38
        unsigned bits_per_sample;
 
39
        unsigned channels;
 
40
        unsigned sample_rate;
 
41
        unsigned length_in_ms;
 
42
} stream_info_struct;
 
43
 
 
44
static FLAC__bool stream_init(const char *infilename);
 
45
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
 
46
static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
 
47
static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 
48
 
 
49
In_Module mod; /* the output module (declared near the bottom of this file) */
 
50
char lastfn[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
 
51
int decode_pos_ms; /* current decoding position, in milliseconds */
 
52
int paused; /* are we paused? */
 
53
int seek_needed; /* if != -1, it is the point that the decode thread should seek to, in ms. */
 
54
FLAC__int16 reservoir[FLAC__MAX_BLOCK_SIZE * 2 * 2]; /* *2 for max channels, another *2 for overflow */
 
55
char sample_buffer[576 * 2 * (16/8) * 2]; /* 2 for max channels, (16/8) for max bytes per sample, and 2 for who knows what */
 
56
unsigned samples_in_reservoir;
 
57
static stream_info_struct stream_info;
 
58
static FLAC__FileDecoder *decoder;
 
59
 
 
60
int killDecodeThread = 0;                                       /* the kill switch for the decode thread */
 
61
HANDLE thread_handle = INVALID_HANDLE_VALUE;    /* the handle to the decode thread */
 
62
 
 
63
DWORD WINAPI __stdcall DecodeThread(void *b); /* the decode thread procedure */
 
64
 
 
65
void config(HWND hwndParent)
 
66
{
 
67
        MessageBox(hwndParent, "No configuration.", "Configuration", MB_OK);
 
68
        /* if we had a configuration we'd want to write it here :) */
 
69
}
 
70
void about(HWND hwndParent)
 
71
{
 
72
        MessageBox(hwndParent, "Winamp FLAC Plugin v" FLAC__VERSION_STRING ", by Josh Coalson\nSee http://flac.sourceforge.net/", "About FLAC Plugin", MB_OK);
 
73
}
 
74
 
 
75
void init()
 
76
{
 
77
        decoder = FLAC__file_decoder_new();
 
78
}
 
79
 
 
80
void quit()
 
81
{
 
82
        if(decoder) {
 
83
                FLAC__file_decoder_delete(decoder);
 
84
                decoder = 0;
 
85
        }
 
86
}
 
87
 
 
88
int isourfile(char *fn) { return 0; }
 
89
/* used for detecting URL streams.. unused here. strncmp(fn, "http://", 7) to detect HTTP streams, etc */
 
90
 
 
91
int play(char *fn)
 
92
{
 
93
        int maxlatency;
 
94
        int thread_id;
 
95
        HANDLE input_file = INVALID_HANDLE_VALUE;
 
96
 
 
97
        if(0 == decoder) {
 
98
                return 1;
 
99
        }
 
100
 
 
101
        input_file = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
102
        if (input_file == INVALID_HANDLE_VALUE) {
 
103
                return 1;
 
104
        }
 
105
        CloseHandle(input_file);
 
106
 
 
107
        if(!stream_init(fn)) {
 
108
                return 1;
 
109
        }
 
110
 
 
111
        strcpy(lastfn, fn);
 
112
        paused = 0;
 
113
        decode_pos_ms = 0;
 
114
        seek_needed = -1;
 
115
        samples_in_reservoir = 0;
 
116
 
 
117
        maxlatency = mod.outMod->Open(stream_info.sample_rate, stream_info.channels, stream_info.bits_per_sample, -1, -1);
 
118
        if (maxlatency < 0) { /* error opening device */
 
119
                return 1;
 
120
        }
 
121
 
 
122
        /* dividing by 1000 for the first parameter of setinfo makes it */
 
123
        /* display 'H'... for hundred.. i.e. 14H Kbps. */
 
124
        mod.SetInfo((stream_info.sample_rate*stream_info.bits_per_sample*stream_info.channels)/1000, stream_info.sample_rate/1000, stream_info.channels, 1);
 
125
 
 
126
        /* initialize vis stuff */
 
127
        mod.SAVSAInit(maxlatency, stream_info.sample_rate);
 
128
        mod.VSASetInfo(stream_info.sample_rate, stream_info.channels);
 
129
 
 
130
        mod.outMod->SetVolume(-666); /* set the output plug-ins default volume */
 
131
 
 
132
        killDecodeThread = 0;
 
133
        thread_handle = (HANDLE) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DecodeThread, (void *) &killDecodeThread, 0, &thread_id);
 
134
 
 
135
        return 0;
 
136
}
 
137
 
 
138
void pause()
 
139
{
 
140
        paused = 1;
 
141
        mod.outMod->Pause(1);
 
142
}
 
143
 
 
144
void unpause()
 
145
{
 
146
        paused = 0;
 
147
        mod.outMod->Pause(0);
 
148
}
 
149
int ispaused()
 
150
{
 
151
        return paused;
 
152
}
 
153
 
 
154
void stop()
 
155
{
 
156
        if (thread_handle != INVALID_HANDLE_VALUE) {
 
157
                killDecodeThread = 1;
 
158
                if (WaitForSingleObject(thread_handle, INFINITE) == WAIT_TIMEOUT) {
 
159
                        MessageBox(mod.hMainWindow, "error asking thread to die!\n", "error killing decode thread", 0);
 
160
                        TerminateThread(thread_handle, 0);
 
161
                }
 
162
                CloseHandle(thread_handle);
 
163
                thread_handle = INVALID_HANDLE_VALUE;
 
164
        }
 
165
        if(decoder)
 
166
                FLAC__file_decoder_finish(decoder);
 
167
 
 
168
        mod.outMod->Close();
 
169
 
 
170
        mod.SAVSADeInit();
 
171
}
 
172
 
 
173
int getlength()
 
174
{
 
175
        return (int)stream_info.length_in_ms;
 
176
}
 
177
 
 
178
int getoutputtime()
 
179
{
 
180
        return decode_pos_ms+(mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime());
 
181
}
 
182
 
 
183
void setoutputtime(int time_in_ms)
 
184
{
 
185
        seek_needed = time_in_ms;
 
186
}
 
187
 
 
188
void setvolume(int volume) { mod.outMod->SetVolume(volume); }
 
189
void setpan(int pan) { mod.outMod->SetPan(pan); }
 
190
 
 
191
int infoDlg(char *fn, HWND hwnd)
 
192
{
 
193
        /* TODO: implement info dialog. */
 
194
        return 0;
 
195
}
 
196
 
 
197
void getfileinfo(char *filename, char *title, int *length_in_ms)
 
198
{
 
199
        if (!filename || !*filename) { /* currently playing file */
 
200
                if (length_in_ms)
 
201
                        *length_in_ms = getlength();
 
202
                if (title) {
 
203
                        char *p = lastfn+strlen(lastfn);
 
204
                        while (*p != '\\' && p >= lastfn) p--;
 
205
                        strcpy(title, ++p);
 
206
                }
 
207
        }
 
208
        else { /* some other file */
 
209
                if (length_in_ms) {
 
210
                        FLAC__FileDecoder *tmp_decoder = FLAC__file_decoder_new();
 
211
                        stream_info_struct tmp_stream_info;
 
212
                        tmp_stream_info.abort_flag = false;
 
213
                        FLAC__file_decoder_set_md5_checking(tmp_decoder, false);
 
214
                        FLAC__file_decoder_set_filename(tmp_decoder, filename);
 
215
                        FLAC__file_decoder_set_write_callback(tmp_decoder, write_callback);
 
216
                        FLAC__file_decoder_set_metadata_callback(tmp_decoder, metadata_callback);
 
217
                        FLAC__file_decoder_set_error_callback(tmp_decoder, error_callback);
 
218
                        FLAC__file_decoder_set_client_data(tmp_decoder, &tmp_stream_info);
 
219
                        if(FLAC__file_decoder_init(tmp_decoder) != FLAC__FILE_DECODER_OK)
 
220
                                return;
 
221
                        if(!FLAC__file_decoder_process_metadata(tmp_decoder))
 
222
                                return;
 
223
 
 
224
                        *length_in_ms = (int)tmp_stream_info.length_in_ms;
 
225
 
 
226
                        FLAC__file_decoder_finish(tmp_decoder);
 
227
                        FLAC__file_decoder_delete(tmp_decoder);
 
228
                }
 
229
                if (title) {
 
230
                        char *p = filename+strlen(filename);
 
231
                        while (*p != '\\' && p >= filename) p--;
 
232
                        strcpy(title, ++p);
 
233
                }
 
234
        }
 
235
}
 
236
 
 
237
void eq_set(int on, char data[10], int preamp)
 
238
{
 
239
}
 
240
 
 
241
DWORD WINAPI __stdcall DecodeThread(void *b)
 
242
{
 
243
        int done = 0;
 
244
 
 
245
        while (! *((int *)b) ) {
 
246
                unsigned channels = stream_info.channels;
 
247
                unsigned bits_per_sample = stream_info.bits_per_sample;
 
248
                unsigned bytes_per_sample = (bits_per_sample+7)/8;
 
249
                unsigned sample_rate = stream_info.sample_rate;
 
250
                if (seek_needed != -1) {
 
251
                        const double distance = (double)seek_needed / (double)getlength();
 
252
                        unsigned target_sample = (unsigned)(distance * (double)stream_info.total_samples);
 
253
                        if(FLAC__file_decoder_seek_absolute(decoder, (FLAC__uint64)target_sample)) {
 
254
                                decode_pos_ms = (int)(distance * (double)getlength());
 
255
                                seek_needed = -1;
 
256
                                done = 0;
 
257
                                mod.outMod->Flush(decode_pos_ms);
 
258
                        }
 
259
                }
 
260
                if (done) {
 
261
                        if (!mod.outMod->IsPlaying()) {
 
262
                                PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
 
263
                                return 0;
 
264
                        }
 
265
                        Sleep(10);
 
266
                }
 
267
                else if (mod.outMod->CanWrite() >= ((int)(576*channels*bytes_per_sample) << (mod.dsp_isactive()?1:0))) {
 
268
                        while(samples_in_reservoir < 576) {
 
269
                                if(FLAC__file_decoder_get_state(decoder) == FLAC__FILE_DECODER_END_OF_FILE) {
 
270
                                        done = 1;
 
271
                                        break;
 
272
                                }
 
273
                                else if(!FLAC__file_decoder_process_one_frame(decoder))
 
274
                                        break;
 
275
                        }
 
276
 
 
277
                        if (samples_in_reservoir == 0) {
 
278
                                done = 1;
 
279
                        }
 
280
                        else {
 
281
                                unsigned i, n = min(samples_in_reservoir, 576), delta;
 
282
                                int bytes;
 
283
                                signed short *ssbuffer = (signed short *)sample_buffer;
 
284
 
 
285
                                for(i = 0; i < n*channels; i++)
 
286
                                        ssbuffer[i] = reservoir[i];
 
287
                                delta = i;
 
288
                                for( ; i < samples_in_reservoir*channels; i++)
 
289
                                        reservoir[i-delta] = reservoir[i];
 
290
                                samples_in_reservoir -= n;
 
291
 
 
292
                                mod.SAAddPCMData((char *)sample_buffer, channels, bits_per_sample, decode_pos_ms);
 
293
                                mod.VSAAddPCMData((char *)sample_buffer, channels, bits_per_sample, decode_pos_ms);
 
294
                                decode_pos_ms += (n*1000 + sample_rate/2)/sample_rate;
 
295
                                if (mod.dsp_isactive())
 
296
                                        bytes = mod.dsp_dosamples((short *)sample_buffer, n, bits_per_sample, channels, sample_rate) * (channels*bytes_per_sample);
 
297
                                else
 
298
                                        bytes = n * channels * bytes_per_sample;
 
299
                                mod.outMod->Write(sample_buffer, bytes);
 
300
                        }
 
301
                }
 
302
                else Sleep(20);
 
303
        }
 
304
        return 0;
 
305
}
 
306
 
 
307
 
 
308
 
 
309
In_Module mod =
 
310
{
 
311
        IN_VER,
 
312
        "Reference FLAC Player v" FLAC__VERSION_STRING,
 
313
        0,      /* hMainWindow */
 
314
        0,  /* hDllInstance */
 
315
        "FLAC\0FLAC Audio File (*.FLAC)\0"
 
316
        ,
 
317
        1,      /* is_seekable */
 
318
        1, /* uses output */
 
319
        config,
 
320
        about,
 
321
        init,
 
322
        quit,
 
323
        getfileinfo,
 
324
        infoDlg,
 
325
        isourfile,
 
326
        play,
 
327
        pause,
 
328
        unpause,
 
329
        ispaused,
 
330
        stop,
 
331
 
 
332
        getlength,
 
333
        getoutputtime,
 
334
        setoutputtime,
 
335
 
 
336
        setvolume,
 
337
        setpan,
 
338
 
 
339
        0,0,0,0,0,0,0,0,0, /* vis stuff */
 
340
 
 
341
 
 
342
        0,0, /* dsp */
 
343
 
 
344
        eq_set,
 
345
 
 
346
        NULL,           /* setinfo */
 
347
 
 
348
        0 /* out_mod */
 
349
 
 
350
};
 
351
 
 
352
__declspec( dllexport ) In_Module * winampGetInModule2()
 
353
{
 
354
        return &mod;
 
355
}
 
356
 
 
357
 
 
358
/***********************************************************************
 
359
 * local routines
 
360
 **********************************************************************/
 
361
FLAC__bool stream_init(const char *infilename)
 
362
{
 
363
        FLAC__file_decoder_set_md5_checking(decoder, false);
 
364
        FLAC__file_decoder_set_filename(decoder, infilename);
 
365
        FLAC__file_decoder_set_write_callback(decoder, write_callback);
 
366
        FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback);
 
367
        FLAC__file_decoder_set_error_callback(decoder, error_callback);
 
368
        FLAC__file_decoder_set_client_data(decoder, &stream_info);
 
369
        if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
 
370
                MessageBox(mod.hMainWindow, "ERROR initializing decoder, state = %d\n", "ERROR initializing decoder", 0);
 
371
                return false;
 
372
        }
 
373
 
 
374
        stream_info.abort_flag = false;
 
375
        if(!FLAC__file_decoder_process_metadata(decoder)) {
 
376
                return false;
 
377
        }
 
378
 
 
379
        return true;
 
380
}
 
381
 
 
382
FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
 
383
{
 
384
        stream_info_struct *stream_info = (stream_info_struct *)client_data;
 
385
        const unsigned bps = stream_info->bits_per_sample, channels = stream_info->channels, wide_samples = frame->header.blocksize;
 
386
        unsigned wide_sample, sample, channel;
 
387
 
 
388
        (void)decoder;
 
389
 
 
390
        if(stream_info->abort_flag)
 
391
                return FLAC__STREAM_DECODER_WRITE_ABORT;
 
392
 
 
393
        for(sample = samples_in_reservoir*channels, wide_sample = 0; wide_sample < wide_samples; wide_sample++)
 
394
                for(channel = 0; channel < channels; channel++, sample++)
 
395
                        reservoir[sample] = (FLAC__int16)buffer[channel][wide_sample];
 
396
 
 
397
        samples_in_reservoir += wide_samples;
 
398
 
 
399
        return FLAC__STREAM_DECODER_WRITE_CONTINUE;
 
400
}
 
401
 
 
402
void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
 
403
{
 
404
        stream_info_struct *stream_info = (stream_info_struct *)client_data;
 
405
        (void)decoder;
 
406
        if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
 
407
                FLAC__ASSERT(metadata->data.stream_info.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
 
408
                stream_info->total_samples = (unsigned)(metadata->data.stream_info.total_samples&0xffffffff);
 
409
                stream_info->bits_per_sample = metadata->data.stream_info.bits_per_sample;
 
410
                stream_info->channels = metadata->data.stream_info.channels;
 
411
                stream_info->sample_rate = metadata->data.stream_info.sample_rate;
 
412
 
 
413
                if(stream_info->bits_per_sample != 16) {
 
414
                        MessageBox(mod.hMainWindow, "ERROR: plugin can only handle 16-bit samples\n", "ERROR: plugin can only handle 16-bit samples", 0);
 
415
                        stream_info->abort_flag = true;
 
416
                        return;
 
417
                }
 
418
                stream_info->length_in_ms = stream_info->total_samples * 10 / (stream_info->sample_rate / 100);
 
419
        }
 
420
}
 
421
 
 
422
void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
 
423
{
 
424
        stream_info_struct *stream_info = (stream_info_struct *)client_data;
 
425
        (void)decoder;
 
426
        if(status != FLAC__STREAM_DECODER_ERROR_LOST_SYNC)
 
427
                stream_info->abort_flag = true;
 
428
}