1 /* in_flac - Winamp2 FLAC input plugin
\r
2 * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
\r
4 * This library is free software; you can redistribute it and/or
\r
5 * modify it under the terms of the GNU Lesser General Public
\r
6 * License as published by the Free Software Foundation; either
\r
7 * version 2.1 of the License, or (at your option) any later version.
\r
9 * This library is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
12 * Lesser General Public License for more details.
\r
14 * You should have received a copy of the GNU Lesser General Public
\r
15 * License along with this library; if not, write to the Free Software
\r
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
\r
20 # include <config.h>
\r
23 #include <windows.h>
\r
24 #include <limits.h> /* for INT_MAX */
\r
27 #include "share/alloc.h"
\r
28 #include "winamp2/in2.h"
\r
29 #include "configure.h"
\r
30 #include "infobox.h"
\r
33 #define PLUGIN_VERSION "1.2.1"
\r
35 static In_Module mod_; /* the input module (declared near the bottom of this file) */
\r
36 static char lastfn_[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
\r
37 flac_config_t flac_cfg;
\r
39 static stream_data_struct stream_data_;
\r
41 static FLAC__StreamDecoder *decoder_;
\r
42 static char sample_buffer_[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8) * 2];
\r
43 /* (24/8) for max bytes per sample, and 2 for DSPs */
\r
45 static HANDLE thread_handle = NULL; /* the handle to the decode thread */
\r
46 static DWORD WINAPI DecodeThread(void *b); /* the decode thread procedure */
\r
54 decoder_ = FLAC__stream_decoder_new();
\r
55 strcpy(lastfn_, "");
\r
66 FLAC_plugin__decoder_delete(decoder_);
\r
74 static int isourfile(char *fn) { return 0; }
\r
76 static int play(char *fn)
\r
82 if (decoder_ == 0) return 1;
\r
83 if (!(filesize = FileSize(fn))) return -1;
\r
85 if (!FLAC_plugin__decoder_init(decoder_, fn, filesize, &stream_data_, &flac_cfg.output))
\r
87 strcpy(lastfn_, fn);
\r
89 maxlatency = mod_.outMod->Open(stream_data_.sample_rate, stream_data_.channels, stream_data_.output_bits_per_sample, -1, -1);
\r
92 FLAC_plugin__decoder_finish(decoder_);
\r
96 mod_.outMod->SetVolume(-666);
\r
97 mod_.outMod->SetPan(0);
\r
98 /* initialize vis stuff */
\r
99 mod_.SAVSAInit(maxlatency, stream_data_.sample_rate);
\r
100 mod_.VSASetInfo(stream_data_.sample_rate, stream_data_.channels);
\r
102 mod_.SetInfo(stream_data_.average_bps, stream_data_.sample_rate/1000, stream_data_.channels, 1);
\r
103 /* start playing thread */
\r
105 thread_handle = CreateThread(NULL, 0, DecodeThread, NULL, 0, &thread_id);
\r
106 if (!thread_handle) return 1;
\r
115 stream_data_.is_playing = false;
\r
116 if (WaitForSingleObject(thread_handle, 2000) == WAIT_TIMEOUT)
\r
118 FLAC_plugin__show_error("Error while stopping decoding thread.");
\r
119 TerminateThread(thread_handle, 0);
\r
121 CloseHandle(thread_handle);
\r
122 thread_handle = NULL;
\r
125 FLAC_plugin__decoder_finish(decoder_);
\r
126 mod_.outMod->Close();
\r
127 mod_.SAVSADeInit();
\r
134 static void pause()
\r
137 mod_.outMod->Pause(1);
\r
140 static void unpause()
\r
143 mod_.outMod->Pause(0);
\r
146 static int ispaused()
\r
151 static int getlength()
\r
153 return stream_data_.length_in_msec;
\r
156 static int getoutputtime()
\r
158 return mod_.outMod->GetOutputTime();
\r
161 static void setoutputtime(int time_in_ms)
\r
163 stream_data_.seek_to = time_in_ms;
\r
166 static void setvolume(int volume)
\r
168 mod_.outMod->SetVolume(volume);
\r
171 static void setpan(int pan)
\r
173 mod_.outMod->SetPan(pan);
\r
176 static void eq_set(int on, char data[10], int preamp) {}
\r
182 static void do_vis(char *data, int nch, int resolution, int position, unsigned samples)
\r
184 static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
\r
189 * Winamp visuals may have problems accepting sample sizes larger than
\r
190 * 16 bits, so we reduce the sample size here if necessary.
\r
193 switch(resolution) {
\r
196 size = resolution / 8;
\r
197 count = samples * nch;
\r
202 *ptr++ = data[0] ^ 0x80;
\r
211 mod_.SAAddPCMData(data, nch, resolution, position);
\r
212 mod_.VSAAddPCMData(data, nch, resolution, position);
\r
216 static DWORD WINAPI DecodeThread(void *unused)
\r
218 const unsigned channels = stream_data_.channels;
\r
219 const unsigned bits_per_sample = stream_data_.bits_per_sample;
\r
220 const unsigned target_bps = stream_data_.output_bits_per_sample;
\r
221 const unsigned sample_rate = stream_data_.sample_rate;
\r
222 const unsigned fact = channels * (target_bps/8);
\r
224 while (stream_data_.is_playing)
\r
227 if (stream_data_.seek_to != -1)
\r
229 const int pos = FLAC_plugin__seek(decoder_, &stream_data_);
\r
230 if (pos != -1) mod_.outMod->Flush(pos);
\r
233 else if (stream_data_.eof)
\r
235 if (!mod_.outMod->IsPlaying())
\r
237 PostMessage(mod_.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
\r
245 /* decode samples */
\r
246 int bytes = FLAC_plugin__decode(decoder_, &stream_data_, sample_buffer_);
\r
247 const int n = bytes / fact;
\r
248 /* visualization */
\r
249 do_vis(sample_buffer_, channels, target_bps, mod_.outMod->GetWrittenTime(), n);
\r
251 if (mod_.dsp_isactive())
\r
252 bytes = mod_.dsp_dosamples((short*)sample_buffer_, n, target_bps, channels, sample_rate) * fact;
\r
254 while (mod_.outMod->CanWrite()<bytes && stream_data_.is_playing && stream_data_.seek_to==-1)
\r
256 if (stream_data_.is_playing && stream_data_.seek_to==-1)
\r
257 mod_.outMod->Write(sample_buffer_, bytes);
\r
259 if (flac_cfg.display.show_bps)
\r
261 const int rate = FLAC_plugin__get_rate(mod_.outMod->GetWrittenTime(), mod_.outMod->GetOutputTime(), &stream_data_);
\r
262 if (rate) mod_.SetInfo(rate/1000, stream_data_.sample_rate/1000, stream_data_.channels, 1);
\r
274 static T_CHAR *get_tag(const T_CHAR *tag, void *param)
\r
276 FLAC__StreamMetadata *tags = (FLAC__StreamMetadata*)param;
\r
282 /* Vorbis comment names must be ASCII, so convert 'tag' first */
\r
283 tagname = safe_malloc_add_2op_(wcslen(tag), /*+*/1);
\r
284 for(p=tagname;*tag;) {
\r
290 *p++ = (char)(*tag++);
\r
294 val = FLAC_plugin__tags_get_tag_ucs2(tags, tagname);
\r
296 /* some "user friendly cheavats" */
\r
299 if (!wcsicmp(tag, L"ARTIST"))
\r
301 val = FLAC_plugin__tags_get_tag_ucs2(tags, "PERFORMER");
\r
302 if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, "COMPOSER");
\r
304 else if (!wcsicmp(tag, L"YEAR") || !wcsicmp(tag, L"DATE"))
\r
306 val = FLAC_plugin__tags_get_tag_ucs2(tags, "YEAR_RECORDED");
\r
307 if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, "YEAR_PERFORMED");
\r
314 static void free_tag(T_CHAR *tag, void *param)
\r
320 static void format_title(const char *filename, WCHAR *title, unsigned max_size)
\r
322 FLAC__StreamMetadata *tags;
\r
324 ReadTags(filename, &tags, /*forDisplay=*/true);
\r
326 tagz_format(flac_cfg.title.tag_format_w, get_tag, free_tag, tags, title, max_size);
\r
328 FLAC_plugin__tags_destroy(&tags);
\r
331 static void getfileinfo(char *filename, char *title, int *length_in_msec)
\r
333 FLAC__StreamMetadata streaminfo;
\r
335 if (!filename || !*filename) {
\r
336 filename = lastfn_;
\r
337 if (length_in_msec) {
\r
338 *length_in_msec = stream_data_.length_in_msec;
\r
339 length_in_msec = 0; /* force skip in following code */
\r
343 if (!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
\r
344 if (length_in_msec)
\r
345 *length_in_msec = -1;
\r
350 static WCHAR buffer[400];
\r
351 format_title(filename, buffer, 400);
\r
352 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, buffer, -1, title, 400, NULL, NULL);
\r
355 if (length_in_msec) {
\r
356 /* with VC++ you have to spoon feed it the casting from uint64->int64->double */
\r
357 FLAC__uint64 l = (FLAC__uint64)((double)(FLAC__int64)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5);
\r
360 *length_in_msec = (int)l;
\r
368 void FLAC_plugin__show_error(const char *message,...)
\r
372 va_start(args, message);
\r
373 vsprintf(foo, message, args);
\r
375 MessageBox(mod_.hMainWindow, foo, "FLAC Plug-in Error", MB_ICONSTOP);
\r
378 static void about(HWND hwndParent)
\r
380 MessageBox(hwndParent, "Winamp2 FLAC Plugin v"PLUGIN_VERSION"\nby Josh Coalson and X-Fixer\n\nuses libFLAC "VERSION"\nSee http://flac.sourceforge.net/\n", "About FLAC Plugin", MB_ICONINFORMATION);
\r
383 static void config(HWND hwndParent)
\r
385 if (DoConfig(mod_.hDllInstance, hwndParent))
\r
389 static int infobox(char *fn, HWND hwnd)
\r
391 DoInfoBox(mod_.hDllInstance, hwnd, fn);
\r
399 static In_Module mod_ =
\r
402 "FLAC Decoder v" PLUGIN_VERSION,
\r
403 0, /* hMainWindow */
\r
404 0, /* hDllInstance */
\r
405 "FLAC\0FLAC Audio File (*.FLAC)\0",
\r
406 1, /* is_seekable */
\r
407 1, /* uses output */
\r
428 0,0,0,0,0,0,0,0,0, /* vis stuff */
\r
431 NULL, /* setinfo */
\r
435 __declspec(dllexport) In_Module *winampGetInModule2()
\r
440 BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
\r