1
/* in_flac - Winamp2 FLAC input plugin
2
* Copyright (C) 2002,2003,2004 Josh Coalson
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.
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.
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.
1
19
#include <windows.h>
3
21
#include "FLAC/all.h"
4
22
#include "plugin_common/all.h"
5
23
#include "infobox.h"
6
25
#include "resource.h"
11
char filename[MAX_PATH];
30
char filename[MAX_PATH];
31
FLAC_Plugin__CanonicalTag tag;
14
static char buffer[256];
34
static char buffer[1024];
15
35
static char *genres = NULL;
16
static int genresSize = 0, genresCount = 0, genresChanged = 0;
36
static DWORD genresSize = 0, genresCount = 0;
37
static BOOL genresChanged = FALSE, isNT;
18
39
static const char infoTitle[] = "FLAC File Info";
21
static __inline DWORD FileSize(const char *file)
23
HANDLE hFile = CreateFile(file, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
26
if (hFile == INVALID_HANDLE_VALUE) return 0;
27
res = GetFileSize(hFile, 0);
45
/* TODO: write genres in utf-8 ? */
32
47
static __inline int GetGenresFileName(char *buffer, int size)
36
if (!GetModuleFileName(NULL, buffer, size))
38
c = strrchr(buffer, '\\');
40
strcpy(c+1, "genres.txt");
51
if (!GetModuleFileName(NULL, buffer, size))
53
c = strrchr(buffer, '\\');
55
strcpy(c+1, "genres.txt");
45
60
static void LoadGenres()
51
if (!GetGenresFileName(buffer, sizeof(buffer))) return;
53
hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
54
if (hFile == INVALID_HANDLE_VALUE) return;
55
genresSize = GetFileSize(hFile, 0);
56
if (!genresSize) return;
57
genres = (char*)malloc(genresSize+2);
59
if (!ReadFile(hFile, genres, genresSize, &spam, NULL))
65
genres[genresSize] = 0;
66
genres[genresSize+1] = 0;
71
for (c=genres; *c; c++)
66
FLAC__ASSERT(0 != genres);
68
if (!GetGenresFileName(buffer, sizeof(buffer))) return;
70
hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
71
if (hFile == INVALID_HANDLE_VALUE) return;
72
genresSize = GetFileSize(hFile, 0);
73
if (genresSize && (genres = (char*)malloc(genresSize+2)))
75
if (!ReadFile(hFile, genres, genresSize, &spam, NULL) || spam!=genresSize)
82
genres[genresSize] = 0;
83
genres[genresSize+1] = 0;
84
/* replace newlines */
85
genresChanged = FALSE;
88
for (c=genres; *c; c++)
85
104
static void SaveGenres(HWND hlist)
91
if (!GetGenresFileName(buffer, sizeof(buffer))) return;
93
hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
94
if (hFile == INVALID_HANDLE_VALUE) return;
96
count = SendMessage(hlist, CB_GETCOUNT, 0, 0);
97
for (i=0; i<count; i++)
99
SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);
100
len = strlen(buffer);
106
WriteFile(hFile, buffer, len, &spam, NULL);
113
#define SetText(x,y) SetDlgItemText(hwnd, x, y)
114
#define GetText(x,y) (GetDlgItemText(hwnd, x, buffer, sizeof(buffer)), y = buffer[0] ? strdup(buffer) : 0)
116
static BOOL InitInfobox(HWND hwnd, const char *file)
118
LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
110
if (!GetGenresFileName(buffer, sizeof(buffer))) return;
112
hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
113
if (hFile == INVALID_HANDLE_VALUE) return;
115
count = SendMessage(hlist, CB_GETCOUNT, 0, 0);
116
for (i=0; i<count; i++)
118
SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);
119
len = strlen(buffer);
125
WriteFile(hFile, buffer, len, &spam, NULL);
131
static void AddGenre(HWND hwnd, const char *genre)
133
HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
135
if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)genre) == CB_ERR)
137
genresChanged = TRUE;
138
SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)genre);
142
static void InitGenres(HWND hwnd)
144
HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
147
/* set text length limit to 64 chars */
148
SendMessage(hgen, CB_LIMITTEXT, 64, 0);
149
/* try to load genres */
152
/* add the to list */
155
SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);
157
for (c = genres; *c; c += strlen(c)+1)
158
SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);
162
static void DeinitGenres(HWND hwnd, BOOL final)
164
if (genresChanged && hwnd)
166
SaveGenres(GetDlgItem(hwnd, IDC_GENRE));
167
genresChanged = FALSE;
181
#define SetText(x,y) WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, FLAC_plugin__canonical_get(&data->tag, y), -1, buffer, sizeof(buffer), NULL, NULL); \
182
SetDlgItemText(hwnd, x, buffer)
184
#define GetText(x,y) GetDlgItemText(hwnd, x, buffer, sizeof(buffer)); \
185
if (*buffer) FLAC_plugin__canonical_set_ansi(&data->tag, y, buffer); \
186
else FLAC_plugin__canonical_remove_all(&data->tag, y)
188
#define SetTextW(x,y) SetDlgItemTextW(hwnd, x, FLAC_plugin__canonical_get(&data->tag, y))
190
#define GetTextW(x,y) GetDlgItemTextW(hwnd, x, (WCHAR*)buffer, sizeof(buffer)/2); \
191
if (*(WCHAR*)buffer) FLAC_plugin__canonical_set(&data->tag, y, (WCHAR*)buffer); \
192
else FLAC_plugin__canonical_remove_all(&data->tag, y)
195
static BOOL InitInfoboxInfo(HWND hwnd, const char *file)
197
LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
119
198
FLAC__StreamMetadata streaminfo;
120
FLAC_Plugin__CanonicalTag tag;
121
DWORD filesize, length, bps, ratio;
199
DWORD length, bps, ratio, rg;
123
SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
125
strncpy(data->filename, file, sizeof(data->filename));
126
SetDlgItemText(hwnd, IDC_NAME, file);
128
filesize = FileSize(file);
129
if (!filesize) return FALSE;
202
SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
204
strncpy(data->filename, file, sizeof(data->filename));
205
SetDlgItemText(hwnd, IDC_NAME, file);
206
/* stream data and vorbis comment */
207
filesize = FileSize(file);
208
if (!filesize) return FALSE;
130
209
if (!FLAC__metadata_get_streaminfo(file, &streaminfo))
133
length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
134
bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));
135
ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);
137
sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"
138
"File size: %d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n",
139
streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,
140
streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,
141
length/60, length%60, bps, ratio/10, ratio%10);
144
SetDlgItemText(hwnd, IDC_INFO, buffer);
146
FLAC_plugin__canonical_tag_init(&tag);
147
FLAC_plugin__canonical_tag_get_combined(file, &tag);
149
SetText(IDC_TITLE, tag.title);
150
SetText(IDC_ARTIST, tag.performer ? tag.performer : tag.composer);
151
SetText(IDC_ALBUM, tag.album);
152
SetText(IDC_COMMENT, tag.comment);
153
SetText(IDC_YEAR, tag.year_recorded ? tag.year_recorded : tag.year_performed);
154
SetText(IDC_TRACK, tag.track_number);
155
SetText(IDC_GENRE, tag.genre);
157
FLAC_plugin__canonical_tag_clear(&tag);
211
ReadTags(file, &data->tag, false);
213
length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
214
bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));
215
ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);
216
rg = FLAC_plugin__canonical_get(&data->tag, L"REPLAYGAIN_TRACK_GAIN") ? 1 : 0;
217
rg |= FLAC_plugin__canonical_get(&data->tag, L"REPLAYGAIN_ALBUM_GAIN") ? 2 : 0;
219
sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"
220
"File size: %I64d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n"
222
streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,
223
streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,
224
length/60, length%60, bps, ratio/10, ratio%10,
225
rg==3 ? "track gain\nReplayGain: album gain" : rg==2 ? "album gain" : rg==1 ? "track gain" : "not present");
227
SetDlgItemText(hwnd, IDC_INFO, buffer);
231
SetTextW(IDC_TITLE, L"TITLE");
232
SetTextW(IDC_ARTIST, L"ARTIST");
233
SetTextW(IDC_ALBUM, L"ALBUM");
234
SetTextW(IDC_COMMENT, L"COMMENT");
235
SetTextW(IDC_YEAR, L"DATE");
236
SetTextW(IDC_TRACK, L"TRACKNUMBER");
237
SetTextW(IDC_GENRE, L"GENRE");
241
SetText(IDC_TITLE, L"TITLE");
242
SetText(IDC_ARTIST, L"ARTIST");
243
SetText(IDC_ALBUM, L"ALBUM");
244
SetText(IDC_COMMENT, L"COMMENT");
245
SetText(IDC_YEAR, L"DATE");
246
SetText(IDC_TRACK, L"TRACKNUMBER");
247
SetText(IDC_GENRE, L"GENRE");
162
253
static void __inline SetTag(HWND hwnd, const char *filename, FLAC_Plugin__CanonicalTag *tag)
164
strcpy(buffer, infoTitle);
255
strcpy(buffer, infoTitle);
166
257
if (FLAC_plugin__vorbiscomment_set(filename, tag))
167
strcat(buffer, " [Updated]");
168
else strcat(buffer, " [Failed]");
258
strcat(buffer, " [Updated]");
259
else strcat(buffer, " [Failed]");
170
SetWindowText(hwnd, buffer);
261
SetWindowText(hwnd, buffer);
173
264
static void UpdateTag(HWND hwnd)
175
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
176
FLAC_Plugin__CanonicalTag tag;
177
FLAC_plugin__canonical_tag_init(&tag);
180
GetText(IDC_TITLE, tag.title);
181
GetText(IDC_ARTIST, tag.composer);
182
GetText(IDC_ALBUM, tag.album);
183
GetText(IDC_COMMENT, tag.comment);
184
GetText(IDC_YEAR, tag.year_recorded);
185
GetText(IDC_TRACK, tag.track_number);
186
GetText(IDC_GENRE, tag.genre);
188
// update genres list
191
HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
193
if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)tag.genre) == CB_ERR)
196
SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)tag.genre);
201
SetTag(hwnd, data->filename, &tag);
202
FLAC_plugin__canonical_tag_clear(&tag);
266
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
271
GetTextW(IDC_TITLE, L"TITLE");
272
GetTextW(IDC_ARTIST, L"ARTIST");
273
GetTextW(IDC_ALBUM, L"ALBUM");
274
GetTextW(IDC_COMMENT, L"COMMENT");
275
GetTextW(IDC_YEAR, L"DATE");
276
GetTextW(IDC_TRACK, L"TRACKNUMBER");
277
GetTextW(IDC_GENRE, L"GENRE");
279
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, FLAC_plugin__canonical_get(&data->tag, L"GENRE"), -1, buffer, sizeof(buffer), NULL, NULL);
283
GetText(IDC_TITLE, L"TITLE");
284
GetText(IDC_ARTIST, L"ARTIST");
285
GetText(IDC_ALBUM, L"ALBUM");
286
GetText(IDC_COMMENT, L"COMMENT");
287
GetText(IDC_YEAR, L"DATE");
288
GetText(IDC_TRACK, L"TRACKNUMBER");
289
GetText(IDC_GENRE, L"GENRE");
292
/* update genres list (buffer should contain genre) */
293
if (buffer[0]) AddGenre(hwnd, buffer);
296
SetTag(hwnd, data->filename, &data->tag);
205
299
static void RemoveTag(HWND hwnd)
207
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
208
FLAC_Plugin__CanonicalTag tag;
209
FLAC_plugin__canonical_tag_init(&tag);
211
SetText(IDC_TITLE, "");
212
SetText(IDC_ARTIST, "");
213
SetText(IDC_ALBUM, "");
214
SetText(IDC_COMMENT, "");
215
SetText(IDC_YEAR, "");
216
SetText(IDC_TRACK, "");
217
SetText(IDC_GENRE, "");
219
SetTag(hwnd, data->filename, &tag);
301
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
302
FLAC_plugin__canonical_tag_clear(&data->tag);
304
SetDlgItemText(hwnd, IDC_TITLE, "");
305
SetDlgItemText(hwnd, IDC_ARTIST, "");
306
SetDlgItemText(hwnd, IDC_ALBUM, "");
307
SetDlgItemText(hwnd, IDC_COMMENT, "");
308
SetDlgItemText(hwnd, IDC_YEAR, "");
309
SetDlgItemText(hwnd, IDC_TRACK, "");
310
SetDlgItemText(hwnd, IDC_GENRE, "");
312
SetTag(hwnd, data->filename, &data->tag);
223
316
static INT_PTR CALLBACK InfoProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
229
SetWindowText(hwnd, infoTitle);
232
HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
235
// set text length limit to 64 chars
236
SendMessage(hgen, CB_LIMITTEXT, 64, 0);
237
// try to load genres
238
if (!genres) LoadGenres(hgen);
242
SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);
244
for (c = genres; *c; c += strlen(c)+1)
245
SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);
249
if (!InitInfobox(hwnd, (const char*)lParam))
250
PostMessage(hwnd, WM_CLOSE, 0, 0);
256
SaveGenres(GetDlgItem(hwnd, IDC_GENRE));
260
LocalFree((LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA));
264
switch (LOWORD(wParam))
269
EndDialog(hwnd, LOWORD(wParam));
322
SetWindowText(hwnd, infoTitle);
325
if (!InitInfoboxInfo(hwnd, (const char*)lParam))
326
PostMessage(hwnd, WM_CLOSE, 0, 0);
331
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
332
FLAC_plugin__canonical_tag_clear(&data->tag);
334
DeinitGenres(hwnd, FALSE);
339
switch (LOWORD(wParam))
344
EndDialog(hwnd, LOWORD(wParam));
365
ULONGLONG FileSize(const char *fileName)
368
HANDLE hFile = CreateFile(fileName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
370
if (hFile == INVALID_HANDLE_VALUE) return 0;
371
res.LowPart = GetFileSize(hFile, &res.HighPart);
376
static __inline char *GetFileName(const char *fullname)
378
const char *c = fullname + strlen(fullname) - 1;
382
if (*c=='\\' || *c=='/')
393
void ReadTags(const char *fileName, FLAC_Plugin__CanonicalTag *tag, BOOL forDisplay)
395
FLAC_plugin__canonical_tag_init(tag);
396
FLAC_plugin__vorbiscomment_get(fileName, tag, forDisplay ? flac_cfg.title.sep : NULL);
402
FLAC_plugin__canonical_set_ansi(tag, L"filepath", fileName);
404
strcpy(buffer, GetFileName(fileName));
405
if (c = strrchr(buffer, '.')) *c = 0;
406
FLAC_plugin__canonical_set_ansi(tag, L"filename", buffer);
416
isNT = !(GetVersion() & 0x80000000);
421
DeinitGenres(NULL, true);
287
424
void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename)
289
DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);
426
DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);