fix bug where output resolution was being determined before it was read from the...
[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 #include <stdio.h>
24
25 #include "in2.h"
26 #include "FLAC/all.h"
27 #include "plugin_common/all.h"
28
29 #ifdef max
30 #undef max
31 #endif
32 #define max(a,b) ((a)>(b)?(a):(b))
33
34
35 #define FLAC__DO_DITHER
36
37 BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
38 {
39         return TRUE;
40 }
41
42 /* post this to the main window at end of file (after playback as stopped) */
43 #define WM_WA_MPEG_EOF WM_USER+2
44
45 typedef struct {
46         FLAC__bool abort_flag;
47         unsigned total_samples;
48         unsigned bits_per_sample;
49         unsigned channels;
50         unsigned sample_rate;
51         unsigned length_in_msec;
52 } file_info_struct;
53
54 static FLAC__bool safe_decoder_init_(const char *infilename, FLAC__FileDecoder *decoder);
55 static void safe_decoder_finish_(FLAC__FileDecoder *decoder);
56 static void safe_decoder_delete_(FLAC__FileDecoder *decoder);
57 static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
58 static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
59 static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
60 static void get_description_(const char *filename, char *description, unsigned max_size);
61
62 In_Module mod_; /* the output module (declared near the bottom of this file) */
63 char lastfn_[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
64 int decode_pos_ms_; /* current decoding position, in milliseconds */
65 int paused_; /* are we paused? */
66 int seek_needed_; /* if != -1, it is the point that the decode thread should seek to, in ms. */
67
68 #define SAMPLES_PER_WRITE 576
69 FLAC__int32 reservoir_[FLAC__MAX_BLOCK_SIZE * 2/*for overflow*/ * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
70 char sample_buffer_[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8) * 2]; /* (24/8) for max bytes per sample, and 2 for who knows what */
71 unsigned wide_samples_in_reservoir_;
72 static file_info_struct file_info_;
73 static FLAC__FileDecoder *decoder_;
74
75 int killDecodeThread = 0;                                       /* the kill switch for the decode thread */
76 HANDLE thread_handle = INVALID_HANDLE_VALUE;    /* the handle to the decode thread */
77
78 DWORD WINAPI __stdcall DecodeThread(void *b); /* the decode thread procedure */
79
80
81 static void do_vis(char *data, int nch, int resolution, int position, unsigned samples)
82 {
83         static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
84         char *ptr;
85         int size, count;
86
87         /*
88          * Winamp visuals may have problems accepting sample sizes larger than
89          * 16 bits, so we reduce the sample size here if necessary.
90          */
91
92         switch(resolution) {
93                 case 32:
94                 case 24:
95                         size  = resolution / 8;
96                         count = samples * nch;
97
98                         ptr = vis_buffer;
99                         while(count--) {
100                                 data += size;
101                                 *ptr++ = data[-1] ^ 0x80;
102                         }
103
104                         data = vis_buffer;
105                         resolution = 8;
106
107                         /* fall through */
108                 case 16:
109                 case 8:
110                 default:
111                         mod_.SAAddPCMData(data, nch, resolution, position);
112                         mod_.VSAAddPCMData(data, nch, resolution, position);
113         }
114 }
115
116 void config(HWND hwndParent)
117 {
118         MessageBox(hwndParent, "No configuration.", "Configuration", MB_OK);
119         /* if we had a configuration we'd want to write it here :) */
120 }
121 void about(HWND hwndParent)
122 {
123         MessageBox(hwndParent, "Winamp FLAC Plugin v" FLAC__VERSION_STRING ", by Josh Coalson\nSee http://flac.sourceforge.net/", "About FLAC Plugin", MB_OK);
124 }
125
126 void init()
127 {
128         decoder_ = FLAC__file_decoder_new();
129         strcpy(lastfn_, "");
130 }
131
132 void quit()
133 {
134         safe_decoder_delete_(decoder_);
135         decoder_ = 0;
136 }
137
138 int isourfile(char *fn) { return 0; }
139 /* used for detecting URL streams.. unused here. strncmp(fn, "http://", 7) to detect HTTP streams, etc */
140
141 int play(char *fn)
142 {
143         int maxlatency;
144         int thread_id;
145         HANDLE input_file = INVALID_HANDLE_VALUE;
146         unsigned output_bits_per_sample;
147
148         if(0 == decoder_) {
149                 return 1;
150         }
151
152         input_file = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
153         if(input_file == INVALID_HANDLE_VALUE) {
154                 return -1;
155         }
156         CloseHandle(input_file);
157
158         if(!safe_decoder_init_(fn, decoder_)) {
159                 return 1;
160         }
161
162 #ifdef FLAC__DO_DITHER
163         output_bits_per_sample = min(file_info_.bits_per_sample, 16);
164 #else
165         output_bits_per_sample = file_info_.bits_per_sample;
166 #endif
167
168         strcpy(lastfn_, fn);
169         paused_ = 0;
170         decode_pos_ms_ = 0;
171         seek_needed_ = -1;
172         wide_samples_in_reservoir_ = 0;
173
174         maxlatency = mod_.outMod->Open(file_info_.sample_rate, file_info_.channels, output_bits_per_sample, -1, -1);
175         if(maxlatency < 0) { /* error opening device */
176                 return 1;
177         }
178
179         /* dividing by 1000 for the first parameter of setinfo makes it */
180         /* display 'H'... for hundred.. i.e. 14H Kbps. */
181         mod_.SetInfo((file_info_.sample_rate*file_info_.bits_per_sample*file_info_.channels)/1000, file_info_.sample_rate/1000, file_info_.channels, 1);
182
183         /* initialize vis stuff */
184         mod_.SAVSAInit(maxlatency, file_info_.sample_rate);
185         mod_.VSASetInfo(file_info_.sample_rate, file_info_.channels);
186
187         mod_.outMod->SetVolume(-666); /* set the output plug-ins default volume */
188
189         killDecodeThread = 0;
190         thread_handle = (HANDLE) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DecodeThread, (void *) &killDecodeThread, 0, &thread_id);
191
192         return 0;
193 }
194
195 void pause()
196 {
197         paused_ = 1;
198         mod_.outMod->Pause(1);
199 }
200
201 void unpause()
202 {
203         paused_ = 0;
204         mod_.outMod->Pause(0);
205 }
206 int ispaused()
207 {
208         return paused_;
209 }
210
211 void stop()
212 {
213         if(thread_handle != INVALID_HANDLE_VALUE) {
214                 killDecodeThread = 1;
215                 if(WaitForSingleObject(thread_handle, INFINITE) == WAIT_TIMEOUT) {
216                         MessageBox(mod_.hMainWindow, "error asking thread to die!\n", "error killing decode thread", 0);
217                         TerminateThread(thread_handle, 0);
218                 }
219                 CloseHandle(thread_handle);
220                 thread_handle = INVALID_HANDLE_VALUE;
221         }
222         safe_decoder_finish_(decoder_);
223
224         mod_.outMod->Close();
225
226         mod_.SAVSADeInit();
227 }
228
229 int getlength()
230 {
231         return (int)file_info_.length_in_msec;
232 }
233
234 int getoutputtime()
235 {
236         return decode_pos_ms_ + (mod_.outMod->GetOutputTime() - mod_.outMod->GetWrittenTime());
237 }
238
239 void setoutputtime(int time_in_ms)
240 {
241         seek_needed_ = time_in_ms;
242 }
243
244 void setvolume(int volume) { mod_.outMod->SetVolume(volume); }
245 void setpan(int pan) { mod_.outMod->SetPan(pan); }
246
247 int infoDlg(char *fn, HWND hwnd)
248 {
249         /* @@@TODO: implement info dialog. */
250         return 0;
251 }
252
253 void getfileinfo(char *filename, char *title, int *length_in_msec)
254 {
255         FLAC__StreamMetadata streaminfo;
256
257         if(0 == filename || filename[0] == '\0') {
258                 filename = lastfn_;
259                 if(length_in_msec) {
260                         *length_in_msec = getlength();
261                         length_in_msec = 0; /* force skip in following code */
262                 }
263         }
264
265         if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
266                 MessageBox(mod_.hMainWindow, filename, "ERROR: invalid/missing FLAC metadata", 0);
267                 if(title) {
268                         static const char *errtitle = "Invalid FLAC File: ";
269                         sprintf(title, "%s\"%s\"", errtitle, filename);
270                 }
271                 if(length_in_msec)
272                         *length_in_msec = -1;
273                 return;
274         }
275
276         if(title) {
277                 get_description_(filename, title, MAX_PATH);
278         }
279         if(length_in_msec)
280                 *length_in_msec = (int)(streaminfo.data.stream_info.total_samples * 10 / (streaminfo.data.stream_info.sample_rate / 100));
281 }
282
283 void eq_set(int on, char data[10], int preamp)
284 {
285 }
286
287 DWORD WINAPI __stdcall DecodeThread(void *b)
288 {
289         int done = 0;
290
291         while(! *((int *)b) ) {
292                 const unsigned channels = file_info_.channels;
293                 const unsigned bits_per_sample = file_info_.bits_per_sample;
294 #ifdef FLAC__DO_DITHER
295                 const unsigned target_bps = min(bits_per_sample, 16);
296 #else
297                 const unsigned target_bps = bits_per_sample;
298 #endif
299                 const unsigned sample_rate = file_info_.sample_rate;
300                 if(seek_needed_ != -1) {
301                         const double distance = (double)seek_needed_ / (double)getlength();
302                         const unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples);
303                         if(FLAC__file_decoder_seek_absolute(decoder_, (FLAC__uint64)target_sample)) {
304                                 decode_pos_ms_ = (int)(distance * (double)getlength());
305                                 seek_needed_ = -1;
306                                 done = 0;
307                                 mod_.outMod->Flush(decode_pos_ms_);
308                         }
309                 }
310                 if(done) {
311                         if(!mod_.outMod->IsPlaying()) {
312                                 PostMessage(mod_.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
313                                 return 0;
314                         }
315                         Sleep(10);
316                 }
317                 else if(mod_.outMod->CanWrite() >= ((int)(SAMPLES_PER_WRITE*channels*((target_bps+7)/8)) << (mod_.dsp_isactive()?1:0))) {
318                         while(wide_samples_in_reservoir_ < SAMPLES_PER_WRITE) {
319                                 if(FLAC__file_decoder_get_state(decoder_) == FLAC__FILE_DECODER_END_OF_FILE) {
320                                         done = 1;
321                                         break;
322                                 }
323                                 else if(!FLAC__file_decoder_process_single(decoder_)) {
324                                         MessageBox(mod_.hMainWindow, FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder_)], "READ ERROR processing frame", 0);
325                                         done = 1;
326                                         break;
327                                 }
328                         }
329
330                         if(wide_samples_in_reservoir_ == 0) {
331                                 done = 1;
332                         }
333                         else {
334                                 const unsigned n = min(wide_samples_in_reservoir_, SAMPLES_PER_WRITE);
335                                 const unsigned delta = n * channels;
336                                 int bytes = (int)FLAC__plugin_common__pack_pcm_signed_little_endian(sample_buffer_, reservoir_, n, channels, bits_per_sample, target_bps);
337                                 unsigned i;
338
339                                 for(i = delta; i < wide_samples_in_reservoir_ * channels; i++)
340                                         reservoir_[i-delta] = reservoir_[i];
341                                 wide_samples_in_reservoir_ -= n;
342
343                                 do_vis((char *)sample_buffer_, channels, target_bps, decode_pos_ms_, n);
344                                 decode_pos_ms_ += (n*1000 + sample_rate/2)/sample_rate;
345                                 if(mod_.dsp_isactive())
346                                         bytes = mod_.dsp_dosamples((short *)sample_buffer_, n, target_bps, channels, sample_rate) * (channels*target_bps/8);
347                                 mod_.outMod->Write(sample_buffer_, bytes);
348                         }
349                 }
350                 else Sleep(20);
351         }
352         return 0;
353 }
354
355
356
357 In_Module mod_ =
358 {
359         IN_VER,
360         "Reference FLAC Player v" FLAC__VERSION_STRING,
361         0,      /* hMainWindow */
362         0,  /* hDllInstance */
363         "FLAC\0FLAC Audio File (*.FLAC)\0"
364         ,
365         1,      /* is_seekable */
366         1, /* uses output */
367         config,
368         about,
369         init,
370         quit,
371         getfileinfo,
372         infoDlg,
373         isourfile,
374         play,
375         pause,
376         unpause,
377         ispaused,
378         stop,
379
380         getlength,
381         getoutputtime,
382         setoutputtime,
383
384         setvolume,
385         setpan,
386
387         0,0,0,0,0,0,0,0,0, /* vis stuff */
388
389
390         0,0, /* dsp */
391
392         eq_set,
393
394         NULL,           /* setinfo */
395
396         0 /* out_mod */
397
398 };
399
400 __declspec( dllexport ) In_Module * winampGetInModule2()
401 {
402         return &mod_;
403 }
404
405
406 /***********************************************************************
407  * local routines
408  **********************************************************************/
409 FLAC__bool safe_decoder_init_(const char *filename, FLAC__FileDecoder *decoder)
410 {
411         if(decoder == 0) {
412                 MessageBox(mod_.hMainWindow, "Decoder instance is NULL", "ERROR initializing decoder", 0);
413                 return false;
414         }
415
416         safe_decoder_finish_(decoder);
417
418         FLAC__file_decoder_set_md5_checking(decoder, false);
419         FLAC__file_decoder_set_filename(decoder, filename);
420         FLAC__file_decoder_set_write_callback(decoder, write_callback_);
421         FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
422         FLAC__file_decoder_set_error_callback(decoder, error_callback_);
423         FLAC__file_decoder_set_client_data(decoder, &file_info_);
424         if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
425                 MessageBox(mod_.hMainWindow, FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)], "ERROR initializing decoder", 0);
426                 return false;
427         }
428
429         file_info_.abort_flag = false;
430         if(!FLAC__file_decoder_process_until_end_of_metadata(decoder)) {
431                 MessageBox(mod_.hMainWindow, FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)], "ERROR processing metadata", 0);
432                 return false;
433         }
434
435         if(file_info_.abort_flag) {
436                 /* metadata callback already popped up the error dialog */
437                 return false;
438         }
439
440         return true;
441 }
442
443 void safe_decoder_finish_(FLAC__FileDecoder *decoder)
444 {
445         if(decoder && FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_UNINITIALIZED)
446                 FLAC__file_decoder_finish(decoder);
447 }
448
449 void safe_decoder_delete_(FLAC__FileDecoder *decoder)
450 {
451         if(decoder) {
452                 safe_decoder_finish_(decoder);
453                 FLAC__file_decoder_delete(decoder);
454         }
455 }
456
457 FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
458 {
459         file_info_struct *file_info = (file_info_struct *)client_data;
460         const unsigned channels = file_info->channels, wide_samples = frame->header.blocksize;
461         unsigned wide_sample, offset_sample, channel;
462
463         (void)decoder;
464
465         if(file_info->abort_flag)
466                 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
467
468         for(offset_sample = wide_samples_in_reservoir_ * channels, wide_sample = 0; wide_sample < wide_samples; wide_sample++)
469                 for(channel = 0; channel < channels; channel++, offset_sample++)
470                         reservoir_[offset_sample] = buffer[channel][wide_sample];
471
472         wide_samples_in_reservoir_ += wide_samples;
473
474         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
475 }
476
477 void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
478 {
479         file_info_struct *file_info = (file_info_struct *)client_data;
480         (void)decoder;
481         if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
482                 FLAC__ASSERT(metadata->data.stream_info.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
483                 file_info->total_samples = (unsigned)(metadata->data.stream_info.total_samples&0xffffffff);
484                 file_info->bits_per_sample = metadata->data.stream_info.bits_per_sample;
485                 file_info->channels = metadata->data.stream_info.channels;
486                 file_info->sample_rate = metadata->data.stream_info.sample_rate;
487
488 #ifdef FLAC__DO_DITHER
489                 if(file_info->bits_per_sample != 8 && file_info->bits_per_sample != 16 && file_info->bits_per_sample != 24) {
490                         MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16/24-bit samples\n", "ERROR: plugin can only handle 8/16/24-bit samples", 0);
491                         file_info->abort_flag = true;
492                         return;
493                 }
494 #else
495                 if(file_info->bits_per_sample != 8 && file_info->bits_per_sample != 16 && file_info->bits_per_sample != 24) {
496                         MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16/24-bit samples\n", "ERROR: plugin can only handle 8/16/24-bit samples", 0);
497                         file_info->abort_flag = true;
498                         return;
499                 }
500 #endif
501                 file_info->length_in_msec = file_info->total_samples * 10 / (file_info->sample_rate / 100);
502         }
503 }
504
505 void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
506 {
507         file_info_struct *file_info = (file_info_struct *)client_data;
508         (void)decoder;
509         if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
510                 file_info->abort_flag = true;
511 }
512
513 static FLAC__bool local__is_blank(const char *s)
514 {
515         return 0 == s || *s == '\0';
516 }
517
518 void get_description_(const char *filename, char *description, unsigned max_size)
519 {
520         FLAC_Plugin__CanonicalTag tag;
521
522         FLAC_plugin__canonical_tag_init(&tag);
523         FLAC_plugin__canonical_tag_get_combined(filename, &tag);
524
525         /* @@@ when config window is done, add code here for converting to user charset ala plugin_xmms */
526
527         if(local__is_blank(tag.performer) && local__is_blank(tag.composer) && local__is_blank(tag.title)) {
528                 /* set the description to the filename */
529                 char *p;
530                 const char *temp = strrchr(filename, '\\');
531                 if(0 == temp)
532                         temp = strrchr(filename, '/');
533                 if(0 == temp)
534                         temp = filename;
535                 else
536                         temp++;
537                 strncpy(description, temp, max_size);
538                 description[max_size-1] = '\0';
539                 if(0 != (p = strrchr(description, '.')))
540                         *p = '\0';
541         }
542         else {
543                 char *artist = !local__is_blank(tag.performer)? tag.performer : !local__is_blank(tag.composer)? tag.composer : "Unknown Artist";
544                 char *title = !local__is_blank(tag.title)? tag.title : "Untitled";
545
546                 /* there's no snprintf in VC6 so we get sloppy */
547 #if 0
548                 snprintf(description, max_size, "%s - %s", artist, title);
549 #else
550                 const unsigned needed = strlen(artist) + strlen(title) + 3 + 1;
551                 if(needed <= max_size)
552                         sprintf(description, "%s - %s", artist, title);
553                 else {
554                         char *p = malloc(needed);
555                         if(0 != p) {
556                                 sprintf(p, "%s - %s", artist, title);
557                                 p[max_size-1] = '\0';
558                                 strcpy(description, p);
559                         }
560                 }
561 #endif
562         }
563                 
564         FLAC_plugin__canonical_tag_clear(&tag);
565 }