Commit 4563fa26 authored by Josh Coalson's avatar Josh Coalson
Browse files

Second patch from X-Fixer: file info dialog, tag editor, tag formatting in plugin config

parent ecf57b75
......@@ -23,5 +23,7 @@ EXTRA_DIST = \
config.c \
in_flac.c \
in_flac.dsp \
infobox.c \
infobox.h \
resource.h \
resource.rc
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "winamp2/in2.h"
#include "winamp2/frontend.h"
#include "config.h"
#include "tagz.h"
#include "resource.h"
static char buffer[256];
//
// read/write
// Read/write config
//
#define RI(x, def) (x = GetPrivateProfileInt("FLAC", #x, def, ini_name))
#define WI(x) WritePrivateProfileString("FLAC", #x, itoa(x, buffer, 10), ini_name)
#define RS(x, n, def) GetPrivateProfileString("FLAC", #x, def, x, n, ini_name)
#define WS(x) WritePrivateProfileString("FLAC", #x, x, ini_name)
static const char default_format[] = "[%artist% - ]$if2(%title%,%filename%)";
void ReadConfig()
{
RS(flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format), default_format);
RI(flac_cfg.output.replaygain.enable, 1);
RI(flac_cfg.output.replaygain.album_mode, 0);
RI(flac_cfg.output.replaygain.hard_limit, 0);
......@@ -31,6 +35,8 @@ void ReadConfig()
void WriteConfig()
{
WS(flac_cfg.title.tag_format);
WI(flac_cfg.output.replaygain.enable);
WI(flac_cfg.output.replaygain.album_mode);
WI(flac_cfg.output.replaygain.hard_limit);
......@@ -42,15 +48,48 @@ void WriteConfig()
}
//
// dialog
// Dialog
//
#define PREAMP_RANGE 24
#define Check(x,y) CheckDlgButton(hwnd, x, y ? BST_CHECKED : BST_UNCHECKED)
#define GetCheck(x) (IsDlgButtonChecked(hwnd, x)==BST_CHECKED)
#define GetSel(x) SendDlgItemMessage(hwnd, x, CB_GETCURSEL, 0, 0)
#define GetPos(x) SendDlgItemMessage(hwnd, x, TBM_GETPOS, 0, 0)
#define Enable(x,y) EnableWindow(GetDlgItem(hwnd, x), y)
#define PREAMP_RANGE 24
static INT_PTR CALLBACK GeneralProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// init
case WM_INITDIALOG:
SetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format);
return TRUE;
// commands
case WM_COMMAND:
switch (LOWORD(wParam))
{
// ok
case IDOK:
GetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format));
break;
// reset
case IDC_RESET:
SetDlgItemText(hwnd, IDC_TITLE, default_format);
break;
// help
case IDC_TAGZ_HELP:
MessageBox(hwnd, tagz_manual, "Help", 0);
break;
}
break;
}
return 0;
}
static void UpdatePreamp(HWND hwnd, HWND hamp)
......@@ -60,7 +99,22 @@ static void UpdatePreamp(HWND hwnd, HWND hamp)
SetDlgItemText(hwnd, IDC_PA, buffer);
}
static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
static void UpdateRG(HWND hwnd)
{
int on = GetCheck(IDC_ENABLE);
Enable(IDC_ALBUM, on);
Enable(IDC_LIMITER, on);
Enable(IDC_PREAMP, on);
Enable(IDC_PA, on);
}
static void UpdateDither(HWND hwnd)
{
int on = GetCheck(IDC_DITHERRG);
Enable(IDC_SHAPE, on);
}
static INT_PTR CALLBACK OutputProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
......@@ -71,12 +125,14 @@ static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
Check(IDC_LIMITER, flac_cfg.output.replaygain.hard_limit);
Check(IDC_DITHER, flac_cfg.output.resolution.normal.dither_24_to_16);
Check(IDC_DITHERRG, flac_cfg.output.resolution.replaygain.dither);
// prepare preamp slider
{
HWND hamp = GetDlgItem(hwnd, IDC_PREAMP);
SendMessage(hamp, TBM_SETRANGE, 1, MAKELONG(0, PREAMP_RANGE*2));
SendMessage(hamp, TBM_SETPOS, 1, flac_cfg.output.replaygain.preamp+PREAMP_RANGE);
UpdatePreamp(hwnd, hamp);
}
// fill comboboxes
{
HWND hlist = GetDlgItem(hwnd, IDC_TO);
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"16 bps");
......@@ -90,16 +146,15 @@ static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"High");
SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.noise_shaping, 0);
}
UpdateRG(hwnd);
UpdateDither(hwnd);
return TRUE;
// commands
case WM_COMMAND:
switch (LOWORD(wParam))
{
// ok/cancel
// ok
case IDOK:
if (thread_handle != INVALID_HANDLE_VALUE)
SendMessage(mod_.hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0);
flac_cfg.output.replaygain.enable = GetCheck(IDC_ENABLE);
flac_cfg.output.replaygain.album_mode = GetCheck(IDC_ALBUM);
flac_cfg.output.replaygain.hard_limit = GetCheck(IDC_LIMITER);
......@@ -108,10 +163,8 @@ static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
flac_cfg.output.resolution.replaygain.dither = GetCheck(IDC_DITHERRG);
flac_cfg.output.resolution.replaygain.noise_shaping = GetSel(IDC_SHAPE);
flac_cfg.output.resolution.replaygain.bps_out = (GetSel(IDC_TO)+2)*8;
/* fall through */
case IDCANCEL:
EndDialog(hwnd, LOWORD(wParam));
return TRUE;
break;
// reset
case IDC_RESET:
Check(IDC_ENABLE, 1);
Check(IDC_ALBUM, 0);
......@@ -120,10 +173,19 @@ static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
Check(IDC_DITHERRG, 0);
SendDlgItemMessage(hwnd, IDC_PREAMP, TBM_SETPOS, 1, PREAMP_RANGE);
UpdatePreamp(hwnd, GetDlgItem(hwnd, IDC_PREAMP));
SendDlgItemMessage(hwnd, IDC_TO, CB_SETCURSEL, 0, 0);
SendDlgItemMessage(hwnd, IDC_SHAPE, CB_SETCURSEL, 1, 0);
UpdatePreamp(hwnd, GetDlgItem(hwnd, IDC_PREAMP));
UpdateRG(hwnd);
UpdateDither(hwnd);
break;
// active check-boxes
case IDC_ENABLE:
UpdateRG(hwnd);
break;
case IDC_DITHERRG:
UpdateDither(hwnd);
break;
}
break;
......@@ -137,8 +199,144 @@ static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
return 0;
}
#define NUM_PAGES 2
typedef struct
{
HWND htab;
HWND hdlg;
RECT r;
HWND all[NUM_PAGES];
} LOCALDATA;
static void ScreenToClientRect(HWND hwnd, RECT *rect)
{
POINT pt = { rect->left, rect->top };
ScreenToClient(hwnd, &pt);
rect->left = pt.x;
rect->top = pt.y;
pt.x = rect->right;
pt.y = rect->bottom;
ScreenToClient(hwnd, &pt);
rect->right = pt.x;
rect->bottom = pt.y;
}
static void SendCommand(HWND hwnd, int command)
{
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
SendMessage(data->hdlg, WM_COMMAND, command, 0);
}
static void BroadcastCommand(HWND hwnd, int command)
{
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
int i;
for (i=0; i<NUM_PAGES; i++)
SendMessage(data->all[i], WM_COMMAND, command, 0);
}
static void OnSelChange(HWND hwnd)
{
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
int index = TabCtrl_GetCurSel(data->htab);
if (index < 0) return;
// hide previous
if (data->hdlg)
ShowWindow(data->hdlg, SW_HIDE);
// display
data->hdlg = data->all[index];
SetWindowPos(data->hdlg, HWND_TOP, data->r.left, data->r.top, data->r.right-data->r.left, data->r.bottom-data->r.top, SWP_SHOWWINDOW);
}
static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static activePage = 0;
switch (msg)
{
// init
case WM_INITDIALOG:
{
LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
HINSTANCE inst = (HINSTANCE)lParam;
TCITEM item;
// init
SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
data->htab = GetDlgItem(hwnd, IDC_TABS);
data->hdlg = NULL;
// add pages
item.mask = TCIF_TEXT;
data->all[0] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_GENERAL), hwnd, GeneralProc);
item.pszText = "General";
TabCtrl_InsertItem(data->htab, 0, &item);
data->all[1] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_OUTPUT), hwnd, OutputProc);
item.pszText = "Output";
TabCtrl_InsertItem(data->htab, 1, &item);
// get rect (after adding pages)
GetWindowRect(data->htab, &data->r);
ScreenToClientRect(hwnd, &data->r);
TabCtrl_AdjustRect(data->htab, 0, &data->r);
// simulate item change
TabCtrl_SetCurSel(data->htab, activePage);
OnSelChange(hwnd);
}
return TRUE;
// destory
case WM_DESTROY:
{
LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
int i;
activePage = TabCtrl_GetCurSel(data->htab);
for (i=0; i<NUM_PAGES; i++)
DestroyWindow(data->all[i]);
LocalFree(data);
}
break;
// commands
case WM_COMMAND:
switch (LOWORD(wParam))
{
// ok/cancel
case IDOK:
BroadcastCommand(hwnd, IDOK);
/* fall through */
case IDCANCEL:
EndDialog(hwnd, LOWORD(wParam));
return TRUE;
case IDC_RESET:
SendCommand(hwnd, IDC_RESET);
break;
}
break;
// notification
case WM_NOTIFY:
if (LOWORD(wParam) == IDC_TABS)
{
NMHDR *hdr = (NMHDR*)lParam;
switch (hdr->code)
{
case TCN_SELCHANGE:
OnSelChange(hwnd);
break;
}
}
break;
}
return 0;
}
int DoConfig(HWND parent)
int DoConfig(HINSTANCE inst, HWND parent)
{
return DialogBox(mod_.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG), parent, DialogProc) == IDOK;
return DialogBoxParam(inst, MAKEINTRESOURCE(IDD_CONFIG), parent, DialogProc, (LONG)inst) == IDOK;
}
......@@ -4,41 +4,33 @@
//
typedef struct {
//!
/*
struct {
gboolean tag_override;
gchar *tag_format;
gboolean convert_char_set;
gchar *file_char_set;
gchar *user_char_set;
} title;
*/
BOOL enable;
BOOL album_mode;
INT preamp;
BOOL hard_limit;
} replaygain;
struct {
struct {
BOOL enable;
BOOL album_mode;
INT preamp;
BOOL hard_limit;
} replaygain;
BOOL dither_24_to_16;
} normal;
struct {
struct {
BOOL dither_24_to_16;
} normal;
struct {
BOOL dither;
INT noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */
INT bps_out;
} replaygain;
} resolution;
} output;
BOOL dither;
INT noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */
INT bps_out;
} replaygain;
} resolution;
} output_config_t;
typedef struct {
struct {
char tag_format[256];
} title;
output_config_t output;
} flac_config_t;
extern flac_config_t flac_cfg;
extern char ini_name[MAX_PATH];
extern HANDLE thread_handle;
extern In_Module mod_;
//
// prototypes
......@@ -46,4 +38,4 @@ extern In_Module mod_;
void ReadConfig();
void WriteConfig();
int DoConfig(HWND parent);
int DoConfig(HINSTANCE inst, HWND parent);
......@@ -27,27 +27,23 @@
#include "plugin_common/all.h"
#include "share/grabbag.h"
#include "config.h"
#include "infobox.h"
#include "tagz.h"
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
/* post this to the main window at end of file (after playback as stopped) */
#define WM_WA_MPEG_EOF WM_USER+2
typedef struct {
FLAC__bool abort_flag;
int seek_to;
int paused;
unsigned total_samples;
unsigned bits_per_sample;
unsigned output_bits_per_sample;
unsigned channels;
unsigned sample_rate;
unsigned length_in_msec;
DitherContext dither_context;
FLAC__bool has_replaygain;
double replay_scale;
DitherContext dither_context;
} file_info_struct;
......@@ -59,14 +55,13 @@ static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__Str
static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
static void get_description_(const char *filename, char *description, unsigned max_size);
In_Module mod_; /* the input module (declared near the bottom of this file) */
char ini_name[MAX_PATH];
flac_config_t flac_cfg;
static output_config_t cfg; /* local copy */
static In_Module mod_; /* the input module (declared near the bottom of this file) */
static char lastfn_[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
static int decode_pos_ms_; /* current decoding position, in milliseconds */
static int paused_; /* are we paused? */
static int seek_needed_; /* if != -1, it is the point that the decode thread should seek to, in ms. */
#define SAMPLES_PER_WRITE 576
static FLAC__int32 reservoir_[FLAC__MAX_BLOCK_SIZE * 2/*for overflow*/ * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
......@@ -76,14 +71,24 @@ static file_info_struct file_info_;
static FLAC__FileDecoder *decoder_;
static volatile int killDecodeThread = 0; /* the kill switch for the decode thread */
HANDLE thread_handle = INVALID_HANDLE_VALUE; /* the handle to the decode thread */
static HANDLE thread_handle = NULL; /* the handle to the decode thread */
static DWORD WINAPI DecodeThread(void *b); /* the decode thread procedure */
static void show_error(const char *message,...)
{
char foo[512];
va_list args;
va_start(args, message);
vsprintf(foo, message, args);
va_end(args);
MessageBox(mod_.hMainWindow, foo, "FLAC Plug-in Error", MB_ICONSTOP);
}
void config(HWND hwndParent)
{
if (DoConfig(hwndParent))
if (DoConfig(mod_.hDllInstance, hwndParent))
WriteConfig();
}
......@@ -98,7 +103,7 @@ void init()
decoder_ = FLAC__file_decoder_new();
strcpy(lastfn_, "");
// read config
/* read config */
GetModuleFileName(NULL, ini_name, sizeof(ini_name));
p = strrchr(ini_name, '.');
if (!p) p = ini_name + strlen(ini_name);
......@@ -115,85 +120,91 @@ void quit()
}
int isourfile(char *fn) { return 0; }
/* used for detecting URL streams.. unused here. strncmp(fn, "http://", 7) to detect HTTP streams, etc */
int play(char *fn)
{
int maxlatency;
int thread_id;
HANDLE input_file;
DWORD file_size; /*@@@ fixme 64-bit */
if(0 == decoder_)
if (decoder_ == 0)
return 1;
input_file = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(input_file == INVALID_HANDLE_VALUE)
return -1;
file_size = GetFileSize(input_file, NULL);
CloseHandle(input_file);
file_info_.abort_flag = false;
file_info_.has_replaygain = false;
if(!safe_decoder_init_(fn, decoder_))
if (!safe_decoder_init_(fn, decoder_))
return 1;
cfg = flac_cfg.output;
strcpy(lastfn_, fn);
wide_samples_in_reservoir_ = 0;
file_info_.output_bits_per_sample = file_info_.has_replaygain && flac_cfg.output.replaygain.enable ?
flac_cfg.output.resolution.replaygain.dither ? flac_cfg.output.resolution.replaygain.bps_out : file_info_.bits_per_sample :
flac_cfg.output.resolution.normal.dither_24_to_16 ? min(file_info_.bits_per_sample, 16) : file_info_.bits_per_sample;
file_info_.output_bits_per_sample = file_info_.has_replaygain && cfg.replaygain.enable ?
cfg.resolution.replaygain.bps_out :
cfg.resolution.normal.dither_24_to_16 ? min(file_info_.bits_per_sample, 16) : file_info_.bits_per_sample;
if (file_info_.has_replaygain && flac_cfg.output.replaygain.enable && flac_cfg.output.resolution.replaygain.dither)
FLAC__plugin_common__init_dither_context(&file_info_.dither_context, file_info_.bits_per_sample, flac_cfg.output.resolution.replaygain.noise_shaping);
if (file_info_.has_replaygain && cfg.replaygain.enable && cfg.resolution.replaygain.dither)
FLAC__plugin_common__init_dither_context(&file_info_.dither_context, file_info_.bits_per_sample, cfg.resolution.replaygain.noise_shaping);
maxlatency = mod_.outMod->Open(file_info_.sample_rate, file_info_.channels, file_info_.output_bits_per_sample, -1, -1);
if(maxlatency < 0) /* error opening device */
if (maxlatency < 0) /* error opening device */
return 1;
/* dividing by 1000 for the first parameter of setinfo makes it */
/* display 'H'... for hundred.. i.e. 14H Kbps. */
mod_.SetInfo((file_info_.sample_rate*file_info_.bits_per_sample*file_info_.channels)/1000, file_info_.sample_rate/1000, file_info_.channels, 1);
mod_.SetInfo((int)(file_size/(125.*file_info_.total_samples/file_info_.sample_rate)), file_info_.sample_rate/1000, file_info_.channels, 1);
/* initialize vis stuff */
mod_.SAVSAInit(maxlatency, file_info_.sample_rate);
mod_.VSASetInfo(file_info_.sample_rate, file_info_.channels);
/* set the output plug-ins default volume */
mod_.outMod->SetVolume(-666);
paused_ = 0;
file_info_.paused = 0;
file_info_.seek_to = -1;
decode_pos_ms_ = 0;
seek_needed_ = -1;
killDecodeThread = 0;
thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DecodeThread, NULL, 0, &thread_id);
thread_handle = CreateThread(NULL, 0, DecodeThread, NULL, 0, &thread_id);
if (!thread_handle)
return 1;
return 0;
}
void pause()
{
paused_ = 1;
file_info_.paused = 1;
mod_.outMod->Pause(1);
}
void unpause()
{
paused_ = 0;
file_info_.paused = 0;
mod_.outMod->Pause(0);
}
int ispaused()
{
return paused_;
return file_info_.paused;
}
void stop()
{
if(thread_handle != INVALID_HANDLE_VALUE) {
if (thread_handle) {
killDecodeThread = 1;
if(WaitForSingleObject(thread_handle, 2000) == WAIT_TIMEOUT) {
MessageBox(mod_.hMainWindow, "error asking thread to die!\n", "error killing decode thread", 0);
show_error("Error while stopping decoding thread.");
TerminateThread(thread_handle, 0);
}
CloseHandle(thread_handle);
thread_handle = INVALID_HANDLE_VALUE;
thread_handle = NULL;
}
safe_decoder_finish_(decoder_);
......@@ -214,7 +225,7 @@ int getoutputtime()
void setoutputtime(int time_in_ms)
{
seek_needed_ = time_in_ms;
file_info_.seek_to = time_in_ms;
}
void setvolume(int volume) { mod_.outMod->SetVolume(volume); }
......@@ -222,15 +233,7 @@ void setpan(int pan) { mod_.outMod->SetPan(pan); }
int infoDlg(char *fn, HWND hwnd)
{
/* @@@TODO: implement info dialog. */
if (!stricmp(fn, lastfn_)) {
char buffer[512];
sprintf(buffer, "%s\nLength: %d:%02d, ReplayGain: %spresent\n%dHz, %d channel(s), %dbps (%dbps on output)",