• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/flac/src/plugin_winamp2/
1/* in_flac - Winamp2 FLAC input plugin
2 * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19#if HAVE_CONFIG_H
20#  include <config.h>
21#endif
22
23#include <windows.h>
24#include <limits.h> /* for INT_MAX */
25#include <stdio.h>
26
27#include "share/alloc.h"
28#include "winamp2/in2.h"
29#include "configure.h"
30#include "infobox.h"
31#include "tagz.h"
32
33#define PLUGIN_VERSION          "1.2.1"
34
35static In_Module mod_;                      /* the input module (declared near the bottom of this file) */
36static char lastfn_[MAX_PATH];              /* currently playing file (used for getting info on the current file) */
37flac_config_t flac_cfg;
38
39static stream_data_struct stream_data_;
40static int paused;
41static FLAC__StreamDecoder *decoder_;
42static char sample_buffer_[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8) * 2];
43/* (24/8) for max bytes per sample, and 2 for DSPs */
44
45static HANDLE thread_handle = NULL;         /* the handle to the decode thread */
46static DWORD WINAPI DecodeThread(void *b);  /* the decode thread procedure */
47
48/*
49 *  init/quit
50 */
51
52static void init()
53{
54	decoder_ = FLAC__stream_decoder_new();
55	strcpy(lastfn_, "");
56
57	InitConfig();
58	ReadConfig();
59	InitInfobox();
60}
61
62static void quit()
63{
64	WriteConfig();
65	DeinitInfobox();
66	FLAC_plugin__decoder_delete(decoder_);
67	decoder_ = 0;
68}
69
70/*
71 *  open/close
72 */
73
74static int isourfile(char *fn) { return 0; }
75
76static int play(char *fn)
77{
78	LONGLONG filesize;
79	DWORD thread_id;
80	int   maxlatency;
81	/* checks */
82	if (decoder_ == 0) return 1;
83	if (!(filesize = FileSize(fn))) return -1;
84	/* init decoder */
85	if (!FLAC_plugin__decoder_init(decoder_, fn, filesize, &stream_data_, &flac_cfg.output))
86		return 1;
87	strcpy(lastfn_, fn);
88	/* open output */
89	maxlatency = mod_.outMod->Open(stream_data_.sample_rate, stream_data_.channels, stream_data_.output_bits_per_sample, -1, -1);
90	if (maxlatency < 0)
91	{
92		FLAC_plugin__decoder_finish(decoder_);
93		return 1;
94	}
95	/* set defaults */
96	mod_.outMod->SetVolume(-666);
97	mod_.outMod->SetPan(0);
98	/* initialize vis stuff */
99	mod_.SAVSAInit(maxlatency, stream_data_.sample_rate);
100	mod_.VSASetInfo(stream_data_.sample_rate, stream_data_.channels);
101	/* set info */
102	mod_.SetInfo(stream_data_.average_bps, stream_data_.sample_rate/1000, stream_data_.channels, 1);
103	/* start playing thread */
104	paused = 0;
105	thread_handle = CreateThread(NULL, 0, DecodeThread, NULL, 0, &thread_id);
106	if (!thread_handle)	return 1;
107
108	return 0;
109}
110
111static void stop()
112{
113	if (thread_handle)
114	{
115		stream_data_.is_playing = false;
116		if (WaitForSingleObject(thread_handle, 2000) == WAIT_TIMEOUT)
117		{
118			FLAC_plugin__show_error("Error while stopping decoding thread.");
119			TerminateThread(thread_handle, 0);
120		}
121		CloseHandle(thread_handle);
122		thread_handle = NULL;
123	}
124
125	FLAC_plugin__decoder_finish(decoder_);
126	mod_.outMod->Close();
127	mod_.SAVSADeInit();
128}
129
130/*
131 *  play control
132 */
133
134static void pause()
135{
136	paused = 1;
137	mod_.outMod->Pause(1);
138}
139
140static void unpause()
141{
142	paused = 0;
143	mod_.outMod->Pause(0);
144}
145
146static int ispaused()
147{
148	return paused;
149}
150
151static int getlength()
152{
153	return stream_data_.length_in_msec;
154}
155
156static int getoutputtime()
157{
158	return mod_.outMod->GetOutputTime();
159}
160
161static void setoutputtime(int time_in_ms)
162{
163	stream_data_.seek_to = time_in_ms;
164}
165
166static void setvolume(int volume)
167{
168	mod_.outMod->SetVolume(volume);
169}
170
171static void setpan(int pan)
172{
173	mod_.outMod->SetPan(pan);
174}
175
176static void eq_set(int on, char data[10], int preamp) {}
177
178/*
179 *  playing loop
180 */
181
182static void do_vis(char *data, int nch, int resolution, int position, unsigned samples)
183{
184	static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
185	char *ptr;
186	int size, count;
187
188	/*
189	 * Winamp visuals may have problems accepting sample sizes larger than
190	 * 16 bits, so we reduce the sample size here if necessary.
191	 */
192
193	switch(resolution) {
194		case 32:
195		case 24:
196			size  = resolution / 8;
197			count = samples * nch;
198			data += size - 1;
199
200			ptr = vis_buffer;
201			while(count--) {
202				*ptr++ = data[0] ^ 0x80;
203				data += size;
204			}
205
206			data = vis_buffer;
207			resolution = 8;
208			/* fall through */
209		case 16:
210		case 8:
211			mod_.SAAddPCMData(data, nch, resolution, position);
212			mod_.VSAAddPCMData(data, nch, resolution, position);
213	}
214}
215
216static DWORD WINAPI DecodeThread(void *unused)
217{
218	const unsigned channels = stream_data_.channels;
219	const unsigned bits_per_sample = stream_data_.bits_per_sample;
220	const unsigned target_bps = stream_data_.output_bits_per_sample;
221	const unsigned sample_rate = stream_data_.sample_rate;
222	const unsigned fact = channels * (target_bps/8);
223
224	while (stream_data_.is_playing)
225	{
226		/* seek needed */
227		if (stream_data_.seek_to != -1)
228		{
229			const int pos = FLAC_plugin__seek(decoder_, &stream_data_);
230			if (pos != -1) mod_.outMod->Flush(pos);
231		}
232		/* stream ended */
233		else if (stream_data_.eof)
234		{
235			if (!mod_.outMod->IsPlaying())
236			{
237				PostMessage(mod_.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
238				return 0;
239			}
240			Sleep(10);
241		}
242		/* decode */
243		else
244		{
245			/* decode samples */
246			int bytes = FLAC_plugin__decode(decoder_, &stream_data_, sample_buffer_);
247			const int n = bytes / fact;
248			/* visualization */
249			do_vis(sample_buffer_, channels, target_bps, mod_.outMod->GetWrittenTime(), n);
250			/* dsp */
251			if (mod_.dsp_isactive())
252				bytes = mod_.dsp_dosamples((short*)sample_buffer_, n, target_bps, channels, sample_rate) * fact;
253			/* output */
254			while (mod_.outMod->CanWrite()<bytes && stream_data_.is_playing && stream_data_.seek_to==-1)
255				Sleep(20);
256			if (stream_data_.is_playing && stream_data_.seek_to==-1)
257				mod_.outMod->Write(sample_buffer_, bytes);
258			/* show bitrate */
259			if (flac_cfg.display.show_bps)
260			{
261				const int rate = FLAC_plugin__get_rate(mod_.outMod->GetWrittenTime(), mod_.outMod->GetOutputTime(), &stream_data_);
262				if (rate) mod_.SetInfo(rate/1000, stream_data_.sample_rate/1000, stream_data_.channels, 1);
263			}
264		}
265	}
266
267	return 0;
268}
269
270/*
271 *  title formatting
272 */
273
274static T_CHAR *get_tag(const T_CHAR *tag, void *param)
275{
276	FLAC__StreamMetadata *tags = (FLAC__StreamMetadata*)param;
277	char *tagname, *p;
278	T_CHAR *val;
279
280	if (!tag)
281		return 0;
282	/* Vorbis comment names must be ASCII, so convert 'tag' first */
283	tagname = safe_malloc_add_2op_(wcslen(tag), /*+*/1);
284	for(p=tagname;*tag;) {
285		if(*tag > 0x7d) {
286			free(tagname);
287			return 0;
288		}
289		else
290			*p++ = (char)(*tag++);
291	}
292	*p++ = '\0';
293	/* now get it */
294	val = FLAC_plugin__tags_get_tag_ucs2(tags, tagname);
295	free(tagname);
296	/* some "user friendly cheavats" */
297	if (!val)
298	{
299		if (!wcsicmp(tag, L"ARTIST"))
300		{
301			val = FLAC_plugin__tags_get_tag_ucs2(tags, "PERFORMER");
302			if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, "COMPOSER");
303		}
304		else if (!wcsicmp(tag, L"YEAR") || !wcsicmp(tag, L"DATE"))
305		{
306			val = FLAC_plugin__tags_get_tag_ucs2(tags, "YEAR_RECORDED");
307			if (!val) val = FLAC_plugin__tags_get_tag_ucs2(tags, "YEAR_PERFORMED");
308		}
309	}
310
311	return val;
312}
313
314static void free_tag(T_CHAR *tag, void *param)
315{
316	(void)param;
317	free(tag);
318}
319
320static void format_title(const char *filename, WCHAR *title, unsigned max_size)
321{
322	FLAC__StreamMetadata *tags;
323
324	ReadTags(filename, &tags, /*forDisplay=*/true);
325
326	tagz_format(flac_cfg.title.tag_format_w, get_tag, free_tag, tags, title, max_size);
327
328	FLAC_plugin__tags_destroy(&tags);
329}
330
331static void getfileinfo(char *filename, char *title, int *length_in_msec)
332{
333	FLAC__StreamMetadata streaminfo;
334
335	if (!filename || !*filename) {
336		filename = lastfn_;
337		if (length_in_msec) {
338			*length_in_msec = stream_data_.length_in_msec;
339			length_in_msec = 0;    /* force skip in following code */
340		}
341	}
342
343	if (!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
344		if (length_in_msec)
345			*length_in_msec = -1;
346		return;
347	}
348
349	if (title) {
350		static WCHAR buffer[400];
351		format_title(filename, buffer, 400);
352		WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, buffer, -1, title, 400, NULL, NULL);
353	}
354
355	if (length_in_msec) {
356		/* with VC++ you have to spoon feed it the casting from uint64->int64->double */
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);
358		if (l > INT_MAX)
359			l = INT_MAX;
360		*length_in_msec = (int)l;
361	}
362}
363
364/*
365 *  interface
366 */
367
368void FLAC_plugin__show_error(const char *message,...)
369{
370	char foo[512];
371	va_list args;
372	va_start(args, message);
373	vsprintf(foo, message, args);
374	va_end(args);
375	MessageBox(mod_.hMainWindow, foo, "FLAC Plug-in Error", MB_ICONSTOP);
376}
377
378static void about(HWND hwndParent)
379{
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);
381}
382
383static void config(HWND hwndParent)
384{
385	if (DoConfig(mod_.hDllInstance, hwndParent))
386		WriteConfig();
387}
388
389static int infobox(char *fn, HWND hwnd)
390{
391	DoInfoBox(mod_.hDllInstance, hwnd, fn);
392	return 0;
393}
394
395/*
396 *  exported stuff
397 */
398
399static In_Module mod_ =
400{
401	IN_VER,
402	"FLAC Decoder v" PLUGIN_VERSION,
403	0,                                    /* hMainWindow */
404	0,                                    /* hDllInstance */
405	"FLAC\0FLAC Audio File (*.FLAC)\0",
406	1,                                    /* is_seekable */
407	1,                                    /* uses output */
408	config,
409	about,
410	init,
411	quit,
412	getfileinfo,
413	infobox,
414	isourfile,
415	play,
416	pause,
417	unpause,
418	ispaused,
419	stop,
420
421	getlength,
422	getoutputtime,
423	setoutputtime,
424
425	setvolume,
426	setpan,
427
428	0,0,0,0,0,0,0,0,0,                    /* vis stuff */
429	0,0,                                  /* dsp */
430	eq_set,
431	NULL,                                 /* setinfo */
432	0                                     /* out_mod */
433};
434
435__declspec(dllexport) In_Module *winampGetInModule2()
436{
437	return &mod_;
438}
439
440BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
441{
442	return TRUE;
443}
444