update copyright date to include 2002
[platform/upstream/flac.git] / src / plugin_winamp2 / in_flac.c
1 /* in_flac - Winamp2 FLAC input plugin
2  * Copyright (C) 2000,2001,2002  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 }