1 /* in_flac - Winamp2 FLAC input plugin
\r
2 * Copyright (C) 2002,2003,2004,2005,2006 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
21 #include "FLAC/all.h"
\r
22 #include "plugin_common/all.h"
\r
23 #include "infobox.h"
\r
25 #include "resource.h"
\r
30 char filename[MAX_PATH];
\r
31 FLAC__StreamMetadata *tags;
\r
34 static char buffer[8192];
\r
35 static char *genres = NULL;
\r
36 static DWORD genresSize = 0, genresCount = 0;
\r
37 static BOOL genresChanged = FALSE, isNT;
\r
39 static const char infoTitle[] = "FLAC File Info";
\r
45 /* TODO: write genres in utf-8 ? */
\r
47 static __inline int GetGenresFileName(char *buffer, int size)
\r
51 if (!GetModuleFileName(NULL, buffer, size))
\r
53 c = strrchr(buffer, '\\');
\r
55 strcpy(c+1, "genres.txt");
\r
60 static void LoadGenres()
\r
66 FLAC__ASSERT(0 != genres);
\r
68 if (!GetGenresFileName(buffer, sizeof(buffer))) return;
\r
70 hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
\r
71 if (hFile == INVALID_HANDLE_VALUE) return;
\r
72 genresSize = GetFileSize(hFile, 0);
\r
73 if (genresSize && (genres = (char*)malloc(genresSize+2)))
\r
75 if (!ReadFile(hFile, genres, genresSize, &spam, NULL) || spam!=genresSize)
\r
82 genres[genresSize] = 0;
\r
83 genres[genresSize+1] = 0;
\r
84 /* replace newlines */
\r
85 genresChanged = FALSE;
\r
88 for (c=genres; *c; c++)
\r
101 CloseHandle(hFile);
\r
104 static void SaveGenres(HWND hlist)
\r
110 if (!GetGenresFileName(buffer, sizeof(buffer))) return;
\r
112 hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
\r
113 if (hFile == INVALID_HANDLE_VALUE) return;
\r
115 count = SendMessage(hlist, CB_GETCOUNT, 0, 0);
\r
116 for (i=0; i<count; i++)
\r
118 SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);
\r
119 len = strlen(buffer);
\r
125 WriteFile(hFile, buffer, len, &spam, NULL);
\r
128 CloseHandle(hFile);
\r
131 static void AddGenre(HWND hwnd, const char *genre)
\r
133 HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
\r
135 if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)genre) == CB_ERR)
\r
137 genresChanged = TRUE;
\r
138 SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)genre);
\r
142 static void InitGenres(HWND hwnd)
\r
144 HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
\r
147 /* set text length limit to 64 chars */
\r
148 SendMessage(hgen, CB_LIMITTEXT, 64, 0);
\r
149 /* try to load genres */
\r
152 /* add the to list */
\r
155 SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);
\r
157 for (c = genres; *c; c += strlen(c)+1)
\r
158 SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);
\r
162 static void DeinitGenres(HWND hwnd, BOOL final)
\r
164 if (genresChanged && hwnd)
\r
166 SaveGenres(GetDlgItem(hwnd, IDC_GENRE));
\r
167 genresChanged = FALSE;
\r
177 static wchar_t *AnsiToWide(const char *src)
\r
182 FLAC__ASSERT(0 != src);
\r
184 len = strlen(src) + 1;
\r
186 dest = (wchar_t*)malloc(len*sizeof(wchar_t));
\r
187 if (dest) mbstowcs(dest, src, len);
\r
195 #define SetText(x,y) ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, y); \
\r
196 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ucs2, -1, buffer, sizeof(buffer), NULL, NULL); \
\r
197 if(ucs2) free(ucs2); \
\r
198 SetDlgItemText(hwnd, x, buffer)
\r
200 #define GetText(x,y) GetDlgItemText(hwnd, x, buffer, sizeof(buffer)); \
\r
201 if (*buffer) { ucs2 = AnsiToWide(buffer); FLAC_plugin__tags_set_tag_ucs2(data->tags, y, ucs2, /*replace_all=*/false); free(ucs2); } \
\r
202 else FLAC_plugin__tags_delete_tag(data->tags, y)
\r
204 #define SetTextW(x,y) ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, y); \
\r
205 SetDlgItemTextW(hwnd, x, ucs2); \
\r
208 #define GetTextW(x,y) GetDlgItemTextW(hwnd, x, (WCHAR*)buffer, sizeof(buffer)/2); \
\r
209 if (*(WCHAR*)buffer) FLAC_plugin__tags_set_tag_ucs2(data->tags, y, (WCHAR*)buffer, /*replace_all=*/false); \
\r
210 else FLAC_plugin__tags_delete_tag(data->tags, y)
\r
213 static BOOL InitInfoboxInfo(HWND hwnd, const char *file)
\r
215 LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
\r
217 FLAC__StreamMetadata streaminfo;
\r
218 DWORD length, bps, ratio, rg;
\r
221 SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
\r
223 strncpy(data->filename, file, sizeof(data->filename));
\r
224 SetDlgItemText(hwnd, IDC_NAME, file);
\r
225 /* stream data and vorbis comment */
\r
226 filesize = FileSize(file);
\r
227 if (!filesize) return FALSE;
\r
228 if (!FLAC__metadata_get_streaminfo(file, &streaminfo))
\r
230 ReadTags(file, &data->tags, false);
\r
232 length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
\r
233 bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));
\r
234 ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);
\r
235 rg = FLAC_plugin__tags_get_tag_utf8(data->tags, "REPLAYGAIN_TRACK_GAIN") ? 1 : 0;
\r
236 rg |= FLAC_plugin__tags_get_tag_utf8(data->tags, "REPLAYGAIN_ALBUM_GAIN") ? 2 : 0;
\r
238 sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"
\r
239 "File size: %I64d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n"
\r
240 "ReplayGain: %s\n",
\r
241 streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,
\r
242 streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,
\r
243 length/60, length%60, bps, ratio/10, ratio%10,
\r
244 rg==3 ? "track gain\nReplayGain: album gain" : rg==2 ? "album gain" : rg==1 ? "track gain" : "not present");
\r
246 SetDlgItemText(hwnd, IDC_INFO, buffer);
\r
250 SetTextW(IDC_TITLE, "TITLE");
\r
251 SetTextW(IDC_ARTIST, "ARTIST");
\r
252 SetTextW(IDC_ALBUM, "ALBUM");
\r
253 SetTextW(IDC_COMMENT, "COMMENT");
\r
254 SetTextW(IDC_YEAR, "DATE");
\r
255 SetTextW(IDC_TRACK, "TRACKNUMBER");
\r
256 SetTextW(IDC_GENRE, "GENRE");
\r
260 SetText(IDC_TITLE, "TITLE");
\r
261 SetText(IDC_ARTIST, "ARTIST");
\r
262 SetText(IDC_ALBUM, "ALBUM");
\r
263 SetText(IDC_COMMENT, "COMMENT");
\r
264 SetText(IDC_YEAR, "DATE");
\r
265 SetText(IDC_TRACK, "TRACKNUMBER");
\r
266 SetText(IDC_GENRE, "GENRE");
\r
272 static void __inline SetTag(HWND hwnd, const char *filename, FLAC__StreamMetadata *tags)
\r
274 strcpy(buffer, infoTitle);
\r
276 if (FLAC_plugin__tags_set(filename, tags))
\r
277 strcat(buffer, " [Updated]");
\r
278 else strcat(buffer, " [Failed]");
\r
280 SetWindowText(hwnd, buffer);
\r
283 static void UpdateTag(HWND hwnd)
\r
285 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
\r
291 GetTextW(IDC_TITLE, "TITLE");
\r
292 GetTextW(IDC_ARTIST, "ARTIST");
\r
293 GetTextW(IDC_ALBUM, "ALBUM");
\r
294 GetTextW(IDC_COMMENT, "COMMENT");
\r
295 GetTextW(IDC_YEAR, "DATE");
\r
296 GetTextW(IDC_TRACK, "TRACKNUMBER");
\r
297 GetTextW(IDC_GENRE, "GENRE");
\r
299 ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, "GENRE");
\r
300 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ucs2, -1, buffer, sizeof(buffer), NULL, NULL);
\r
305 GetText(IDC_TITLE, "TITLE");
\r
306 GetText(IDC_ARTIST, "ARTIST");
\r
307 GetText(IDC_ALBUM, "ALBUM");
\r
308 GetText(IDC_COMMENT, "COMMENT");
\r
309 GetText(IDC_YEAR, "DATE");
\r
310 GetText(IDC_TRACK, "TRACKNUMBER");
\r
311 GetText(IDC_GENRE, "GENRE");
\r
314 /* update genres list (buffer should contain genre) */
\r
315 if (buffer[0]) AddGenre(hwnd, buffer);
\r
318 SetTag(hwnd, data->filename, data->tags);
\r
321 static void RemoveTag(HWND hwnd)
\r
323 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
\r
324 FLAC_plugin__tags_delete_all(data->tags);
\r
326 SetDlgItemText(hwnd, IDC_TITLE, "");
\r
327 SetDlgItemText(hwnd, IDC_ARTIST, "");
\r
328 SetDlgItemText(hwnd, IDC_ALBUM, "");
\r
329 SetDlgItemText(hwnd, IDC_COMMENT, "");
\r
330 SetDlgItemText(hwnd, IDC_YEAR, "");
\r
331 SetDlgItemText(hwnd, IDC_TRACK, "");
\r
332 SetDlgItemText(hwnd, IDC_GENRE, "");
\r
334 SetTag(hwnd, data->filename, data->tags);
\r
338 static INT_PTR CALLBACK InfoProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
\r
343 case WM_INITDIALOG:
\r
344 SetWindowText(hwnd, infoTitle);
\r
347 if (!InitInfoboxInfo(hwnd, (const char*)lParam))
\r
348 PostMessage(hwnd, WM_CLOSE, 0, 0);
\r
353 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
\r
354 FLAC_plugin__tags_destroy(&data->tags);
\r
356 DeinitGenres(hwnd, FALSE);
\r
361 switch (LOWORD(wParam))
\r
366 EndDialog(hwnd, LOWORD(wParam));
\r
387 ULONGLONG FileSize(const char *fileName)
\r
390 HANDLE hFile = CreateFile(fileName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
\r
392 if (hFile == INVALID_HANDLE_VALUE) return 0;
\r
393 res.LowPart = GetFileSize(hFile, &res.HighPart);
\r
394 CloseHandle(hFile);
\r
395 return res.QuadPart;
\r
398 static __inline char *GetFileName(const char *fullname)
\r
400 const char *c = fullname + strlen(fullname) - 1;
\r
402 while (c > fullname)
\r
404 if (*c=='\\' || *c=='/')
\r
415 void ReadTags(const char *fileName, FLAC__StreamMetadata **tags, BOOL forDisplay)
\r
417 if(FLAC_plugin__tags_get(fileName, tags)) {
\r
419 /* add file name */
\r
424 ucs2 = AnsiToWide(fileName);
\r
425 FLAC_plugin__tags_set_tag_ucs2(*tags, "filepath", ucs2, /*replace_all=*/true);
\r
428 strcpy(buffer, GetFileName(fileName));
\r
429 if (c = strrchr(buffer, '.')) *c = 0;
\r
430 ucs2 = AnsiToWide(buffer);
\r
431 FLAC_plugin__tags_set_tag_ucs2(*tags, "filename", ucs2, /*replace_all=*/true);
\r
443 isNT = !(GetVersion() & 0x80000000);
\r
446 void DeinitInfobox()
\r
448 DeinitGenres(NULL, true);
\r
451 void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename)
\r
453 DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);
\r