1 /* in_flac - Winamp2 FLAC input plugin
\r
2 * Copyright (C) 2000,2001,2002,2003,2004,2005 Josh Coalson
\r
4 * This program is free software; you can redistribute it and/or
\r
5 * modify it under the terms of the GNU General Public License
\r
6 * as published by the Free Software Foundation; either version 2
\r
7 * of the License, or (at your option) any later version.
\r
9 * This program 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
\r
12 * GNU General Public License for more details.
\r
14 * You should have received a copy of the GNU General Public License
\r
15 * along with this program; if not, write to the Free Software
\r
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
19 #include <windows.h>
\r
22 #include "winamp2/in2.h"
\r
24 #include "infobox.h"
\r
27 #define PLUGIN_VERSION "1.1.1"
\r
29 static In_Module mod_; /* the input module (declared near the bottom of this file) */
\r
30 static char lastfn_[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
\r
31 flac_config_t flac_cfg;
\r
33 static file_info_struct file_info_;
\r
35 static FLAC__FileDecoder *decoder_;
\r
36 static char sample_buffer_[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8) * 2];
\r
37 /* (24/8) for max bytes per sample, and 2 for DSPs */
\r
39 static HANDLE thread_handle = NULL; /* the handle to the decode thread */
\r
40 static DWORD WINAPI DecodeThread(void *b); /* the decode thread procedure */
\r
48 decoder_ = FLAC__file_decoder_new();
\r
49 strcpy(lastfn_, "");
\r
60 FLAC_plugin__decoder_delete(decoder_);
\r
68 static int isourfile(char *fn) { return 0; }
\r
70 static int play(char *fn)
\r
76 if (decoder_ == 0) return 1;
\r
77 if (!(filesize = FileSize(fn))) return -1;
\r
79 if (!FLAC_plugin__decoder_init(decoder_, fn, filesize, &file_info_, &flac_cfg.output))
\r
81 strcpy(lastfn_, fn);
\r
83 maxlatency = mod_.outMod->Open(file_info_.sample_rate, file_info_.channels, file_info_.output_bits_per_sample, -1, -1);
\r
86 FLAC_plugin__decoder_finish(decoder_);
\r
90 mod_.outMod->SetVolume(-666);
\r
91 mod_.outMod->SetPan(0);
\r
92 /* initialize vis stuff */
\r
93 mod_.SAVSAInit(maxlatency, file_info_.sample_rate);
\r
94 mod_.VSASetInfo(file_info_.sample_rate, file_info_.channels);
\r
96 mod_.SetInfo(file_info_.average_bps, file_info_.sample_rate/1000, file_info_.channels, 1);
\r
97 /* start playing thread */
\r
99 thread_handle = CreateThread(NULL, 0, DecodeThread, NULL, 0, &thread_id);
\r
100 if (!thread_handle) return 1;
\r
109 file_info_.is_playing = false;
\r
110 if (WaitForSingleObject(thread_handle, 2000) == WAIT_TIMEOUT)
\r
112 FLAC_plugin__show_error("Error while stopping decoding thread.");
\r
113 TerminateThread(thread_handle, 0);
\r
115 CloseHandle(thread_handle);
\r
116 thread_handle = NULL;
\r
119 FLAC_plugin__decoder_finish(decoder_);
\r
120 mod_.outMod->Close();
\r
121 mod_.SAVSADeInit();
\r
128 static void pause()
\r
131 mod_.outMod->Pause(1);
\r
134 static void unpause()
\r
137 mod_.outMod->Pause(0);
\r
140 static int ispaused()
\r
145 static int getlength()
\r
147 return file_info_.length_in_msec;
\r
150 static int getoutputtime()
\r
152 return mod_.outMod->GetOutputTime();
\r
155 static void setoutputtime(int time_in_ms)
\r
157 file_info_.seek_to = time_in_ms;
\r
160 static void setvolume(int volume)
\r
162 mod_.outMod->SetVolume(volume);
\r
165 static void setpan(int pan)
\r
167 mod_.outMod->SetPan(pan);
\r
170 static void eq_set(int on, char data[10], int preamp) {}
\r
176 static void do_vis(char *data, int nch, int resolution, int position, unsigned samples)
\r
178 static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
\r
183 * Winamp visuals may have problems accepting sample sizes larger than
\r
184 * 16 bits, so we reduce the sample size here if necessary.
\r
187 switch(resolution) {
\r
190 size = resolution / 8;
\r
191 count = samples * nch;
\r
196 *ptr++ = data[0] ^ 0x80;
\r
205 mod_.SAAddPCMData(data, nch, resolution, position);
\r
206 mod_.VSAAddPCMData(data, nch, resolution, position);
\r
210 static DWORD WINAPI DecodeThread(void *unused)
\r
212 const unsigned channels = file_info_.channels;
\r
213 const unsigned bits_per_sample = file_info_.bits_per_sample;
\r
214 const unsigned target_bps = file_info_.output_bits_per_sample;
\r
215 const unsigned sample_rate = file_info_.sample_rate;
\r
216 const unsigned fact = channels * (target_bps/8);
\r
218 while (file_info_.is_playing)
\r
221 if (file_info_.seek_to != -1)
\r
223 const int pos = FLAC_plugin__seek(decoder_, &file_info_);
\r
224 if (pos != -1) mod_.outMod->Flush(pos);
\r
227 else if (file_info_.eof)
\r
229 if (!mod_.outMod->IsPlaying())
\r
231 PostMessage(mod_.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
\r
239 /* decode samples */
\r
240 int bytes = FLAC_plugin__decode(decoder_, &file_info_, sample_buffer_);
\r
241 const int n = bytes / fact;
\r
242 /* visualization */
\r
243 do_vis(sample_buffer_, channels, target_bps, mod_.outMod->GetWrittenTime(), n);
\r
245 if (mod_.dsp_isactive())
\r
246 bytes = mod_.dsp_dosamples((short*)sample_buffer_, n, target_bps, channels, sample_rate) * fact;
\r
248 while (mod_.outMod->CanWrite()<bytes && file_info_.is_playing && file_info_.seek_to==-1)
\r
250 if (file_info_.is_playing && file_info_.seek_to==-1)
\r
251 mod_.outMod->Write(sample_buffer_, bytes);
\r
253 if (flac_cfg.display.show_bps)
\r
255 const int rate = FLAC_plugin__get_rate(mod_.outMod->GetWrittenTime(), mod_.outMod->GetOutputTime(), &file_info_);
\r
256 if (rate) mod_.SetInfo(rate/1000, file_info_.sample_rate/1000, file_info_.channels, 1);
\r
268 static const T_CHAR *get_tag(const T_CHAR *tag, void *param)
\r
270 FLAC__StreamMetadata *tags = (FLAC__StreamMetadata*)param;
\r
271 const T_CHAR *val = FLAC_plugin__tags_get_tag_ucs2(tags, tag);
\r
272 /* some "user friendly cheavats" */
\r
275 if (!wcsicmp(tag, L"ARTIST"))
\r
277 val = FLAC_plugin__tags_get_tag_ucs2(tags, "PERFORMER");
\r
278 if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, L"COMPOSER");
\r
280 else if (!wcsicmp(tag, L"YEAR") || !wcsicmp(tag, L"DATE"))
\r
282 val = FLAC_plugin__tags_get_tag_ucs2(tags, L"YEAR_RECORDED");
\r
283 if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, L"YEAR_PERFORMED");
\r
290 static void format_title(const char *filename, WCHAR *title, unsigned max_size)
\r
292 FLAC__StreamMetadata *tags;
\r
294 ReadTags(filename, &tags, /*forDisplay=*/true);
\r
296 tagz_format(flac_cfg.title.tag_format_w, get_tag, free, tags, title, max_size);
\r
298 FLAC_plugin__tags_destroy(&tags);
\r
301 static void getfileinfo(char *filename, char *title, int *length_in_msec)
\r
303 FLAC__StreamMetadata streaminfo;
\r
305 if (!filename || !*filename)
\r
307 filename = lastfn_;
\r
308 if (length_in_msec)
\r
310 *length_in_msec = (int)file_info_.length_in_msec;
\r
311 length_in_msec = 0; /* force skip in following code */
\r
315 if (!FLAC__metadata_get_streaminfo(filename, &streaminfo))
\r
317 if (length_in_msec)
\r
318 *length_in_msec = -1;
\r
324 static WCHAR buffer[400];
\r
325 format_title(filename, buffer, 400);
\r
326 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, buffer, -1, title, 400, NULL, NULL);
\r
329 if (length_in_msec)
\r
330 *length_in_msec = (int)((double)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5);
\r
337 void FLAC_plugin__show_error(const char *message,...)
\r
341 va_start(args, message);
\r
342 vsprintf(foo, message, args);
\r
344 MessageBox(mod_.hMainWindow, foo, "FLAC Plug-in Error", MB_ICONSTOP);
\r
347 static void about(HWND hwndParent)
\r
349 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
352 static void config(HWND hwndParent)
\r
354 if (DoConfig(mod_.hDllInstance, hwndParent))
\r
358 static int infobox(char *fn, HWND hwnd)
\r
360 DoInfoBox(mod_.hDllInstance, hwnd, fn);
\r
368 static In_Module mod_ =
\r
371 "Reference FLAC Decoder v" PLUGIN_VERSION,
\r
372 0, /* hMainWindow */
\r
373 0, /* hDllInstance */
\r
374 "FLAC\0FLAC Audio File (*.FLAC)\0",
\r
375 1, /* is_seekable */
\r
376 1, /* uses output */
\r
397 0,0,0,0,0,0,0,0,0, /* vis stuff */
\r
400 NULL, /* setinfo */
\r
404 __declspec(dllexport) In_Module *winampGetInModule2()
\r
409 BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
\r