new configuration dialog and replay gain code; thanks to X-Fixer
authorJosh Coalson <jcoalson@users.sourceforce.net>
Wed, 8 Jan 2003 07:59:48 +0000 (07:59 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Wed, 8 Jan 2003 07:59:48 +0000 (07:59 +0000)
src/plugin_winamp2/config.c [new file with mode: 0644]
src/plugin_winamp2/config.h [new file with mode: 0644]
src/plugin_winamp2/in_flac.c
src/plugin_winamp2/in_flac.dsp
src/plugin_winamp2/resource.h [new file with mode: 0644]
src/plugin_winamp2/resource.rc [new file with mode: 0644]

diff --git a/src/plugin_winamp2/config.c b/src/plugin_winamp2/config.c
new file mode 100644 (file)
index 0000000..a794a31
--- /dev/null
@@ -0,0 +1,144 @@
+#include <windows.h>\r
+#include <commctrl.h>\r
+#include <stdio.h>\r
+#include "winamp2/in2.h"\r
+#include "winamp2/frontend.h"\r
+#include "config.h"\r
+#include "resource.h"\r
+\r
+\r
+static char buffer[256];\r
+\r
+//\r
+//  read/write\r
+//\r
+\r
+#define RI(x, def)          (x = GetPrivateProfileInt("FLAC", #x, def, ini_name))\r
+#define WI(x)               WritePrivateProfileString("FLAC", #x, itoa(x, buffer, 10), ini_name)\r
+\r
+\r
+void ReadConfig()\r
+{\r
+    RI(flac_cfg.output.replaygain.enable, 1);\r
+    RI(flac_cfg.output.replaygain.album_mode, 0);\r
+    RI(flac_cfg.output.replaygain.hard_limit, 0);\r
+    RI(flac_cfg.output.replaygain.preamp, 0);\r
+    RI(flac_cfg.output.resolution.normal.dither_24_to_16, 0);\r
+    RI(flac_cfg.output.resolution.replaygain.dither, 0);\r
+    RI(flac_cfg.output.resolution.replaygain.noise_shaping, 1);\r
+    RI(flac_cfg.output.resolution.replaygain.bps_out, 16);\r
+}\r
+\r
+void WriteConfig()\r
+{\r
+    WI(flac_cfg.output.replaygain.enable);\r
+    WI(flac_cfg.output.replaygain.album_mode);\r
+    WI(flac_cfg.output.replaygain.hard_limit);\r
+    WI(flac_cfg.output.replaygain.preamp);\r
+    WI(flac_cfg.output.resolution.normal.dither_24_to_16);\r
+    WI(flac_cfg.output.resolution.replaygain.dither);\r
+    WI(flac_cfg.output.resolution.replaygain.noise_shaping);\r
+    WI(flac_cfg.output.resolution.replaygain.bps_out);\r
+}\r
+\r
+//\r
+//  dialog\r
+//\r
+\r
+#define Check(x,y)              CheckDlgButton(hwnd, x, y ? BST_CHECKED : BST_UNCHECKED)\r
+#define GetCheck(x)             (IsDlgButtonChecked(hwnd, x)==BST_CHECKED)\r
+#define GetSel(x)               SendDlgItemMessage(hwnd, x, CB_GETCURSEL, 0, 0)\r
+#define GetPos(x)               SendDlgItemMessage(hwnd, x, TBM_GETPOS, 0, 0)\r
+\r
+#define PREAMP_RANGE            24\r
+\r
+\r
+static void UpdatePreamp(HWND hwnd, HWND hamp)\r
+{\r
+    int pos = SendMessage(hamp, TBM_GETPOS, 0, 0) - PREAMP_RANGE;\r
+    sprintf(buffer, "%d dB", pos);\r
+    SetDlgItemText(hwnd, IDC_PA, buffer);\r
+}\r
+\r
+static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
+{\r
+    switch (msg)\r
+    {\r
+    // init\r
+    case WM_INITDIALOG:\r
+        Check(IDC_ENABLE, flac_cfg.output.replaygain.enable);\r
+        Check(IDC_ALBUM, flac_cfg.output.replaygain.album_mode);\r
+        Check(IDC_LIMITER, flac_cfg.output.replaygain.hard_limit);\r
+        Check(IDC_DITHER, flac_cfg.output.resolution.normal.dither_24_to_16);\r
+        Check(IDC_DITHERRG, flac_cfg.output.resolution.replaygain.dither);\r
+        {\r
+            HWND hamp = GetDlgItem(hwnd, IDC_PREAMP);\r
+            SendMessage(hamp, TBM_SETRANGE, 1, MAKELONG(0, PREAMP_RANGE*2));\r
+            SendMessage(hamp, TBM_SETPOS, 1, flac_cfg.output.replaygain.preamp+PREAMP_RANGE);\r
+            UpdatePreamp(hwnd, hamp);\r
+        }\r
+        {\r
+            HWND hlist = GetDlgItem(hwnd, IDC_TO);\r
+            SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"16 bps");\r
+            SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"24 bps");\r
+            SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.bps_out/8 - 2, 0);\r
+  \r
+            hlist = GetDlgItem(hwnd, IDC_SHAPE);\r
+            SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"None");\r
+            SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Low");\r
+            SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Medium");\r
+            SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"High");\r
+            SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.noise_shaping, 0);\r
+        }\r
+        return TRUE;\r
+    // commands\r
+    case WM_COMMAND:\r
+        switch (LOWORD(wParam))\r
+        {\r
+        // ok/cancel\r
+        case IDOK:\r
+            if (thread_handle != INVALID_HANDLE_VALUE)\r
+                SendMessage(mod_.hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0);\r
+\r
+            flac_cfg.output.replaygain.enable = GetCheck(IDC_ENABLE);\r
+            flac_cfg.output.replaygain.album_mode = GetCheck(IDC_ALBUM);\r
+            flac_cfg.output.replaygain.hard_limit = GetCheck(IDC_LIMITER);\r
+            flac_cfg.output.replaygain.preamp = GetPos(IDC_PREAMP) - PREAMP_RANGE;\r
+            flac_cfg.output.resolution.normal.dither_24_to_16 = GetCheck(IDC_DITHER);\r
+            flac_cfg.output.resolution.replaygain.dither = GetCheck(IDC_DITHERRG);\r
+            flac_cfg.output.resolution.replaygain.noise_shaping = GetSel(IDC_SHAPE);\r
+            flac_cfg.output.resolution.replaygain.bps_out = (GetSel(IDC_TO)+2)*8;\r
+            /* fall through */\r
+        case IDCANCEL:\r
+            EndDialog(hwnd, LOWORD(wParam));\r
+            return TRUE;\r
+        case IDC_RESET:\r
+            Check(IDC_ENABLE, 1);\r
+            Check(IDC_ALBUM, 0);\r
+            Check(IDC_LIMITER, 0);\r
+            Check(IDC_DITHER, 0);\r
+            Check(IDC_DITHERRG, 0);\r
+\r
+            SendDlgItemMessage(hwnd, IDC_PREAMP, TBM_SETPOS, 1, PREAMP_RANGE);\r
+            UpdatePreamp(hwnd, GetDlgItem(hwnd, IDC_PREAMP));\r
+\r
+            SendDlgItemMessage(hwnd, IDC_TO, CB_SETCURSEL, 0, 0);\r
+            SendDlgItemMessage(hwnd, IDC_SHAPE, CB_SETCURSEL, 1, 0);\r
+            break;\r
+        }\r
+        break;\r
+    // scroller\r
+    case WM_HSCROLL:\r
+        if (GetDlgCtrlID((HWND)lParam)==IDC_PREAMP)\r
+            UpdatePreamp(hwnd, (HWND)lParam);\r
+        return 0;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+int DoConfig(HWND parent)\r
+{\r
+    return DialogBox(mod_.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG), parent, DialogProc) == IDOK;\r
+}\r
diff --git a/src/plugin_winamp2/config.h b/src/plugin_winamp2/config.h
new file mode 100644 (file)
index 0000000..c805efe
--- /dev/null
@@ -0,0 +1,49 @@
+\r
+//\r
+//  common stuff\r
+//\r
+\r
+typedef struct {\r
+    //!\r
+    /*\r
+       struct {\r
+               gboolean tag_override;\r
+               gchar *tag_format;\r
+               gboolean convert_char_set;\r
+               gchar *file_char_set;\r
+               gchar *user_char_set;\r
+       } title;\r
+    */\r
+\r
+       struct {\r
+               struct {\r
+                       BOOL enable;\r
+                       BOOL album_mode;\r
+                       INT  preamp;\r
+                       BOOL hard_limit;\r
+               } replaygain;\r
+               struct {\r
+                       struct {\r
+                               BOOL dither_24_to_16;\r
+                       } normal;\r
+                       struct {\r
+                               BOOL dither;\r
+                               INT  noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */\r
+                               INT  bps_out;\r
+                       } replaygain;\r
+               } resolution;\r
+       } output;\r
+} flac_config_t;\r
+\r
+extern flac_config_t flac_cfg;\r
+extern char ini_name[MAX_PATH];\r
+extern HANDLE thread_handle;\r
+extern In_Module mod_;\r
+\r
+//\r
+//  prototypes\r
+//\r
+\r
+void ReadConfig();\r
+void WriteConfig();\r
+int DoConfig(HWND parent);\r
index c8a8493..adf6a3d 100644 (file)
 #include <math.h>
 #include <stdio.h>
 
-#include "in2.h"
+#include "winamp2/in2.h"
 #include "FLAC/all.h"
 #include "plugin_common/all.h"
+#include "share/grabbag.h"
+#include "config.h"
 
 
-#define FLAC__DO_DITHER
-
 BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
 {
        return TRUE;
@@ -41,11 +41,16 @@ typedef struct {
        FLAC__bool abort_flag;
        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;
 } file_info_struct;
 
+
 static FLAC__bool safe_decoder_init_(const char *infilename, FLAC__FileDecoder *decoder);
 static void safe_decoder_finish_(FLAC__FileDecoder *decoder);
 static void safe_decoder_delete_(FLAC__FileDecoder *decoder);
@@ -54,65 +59,34 @@ 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 output module (declared near the bottom of this file) */
-char lastfn_[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
-int decode_pos_ms_; /* current decoding position, in milliseconds */
-int paused_; /* are we paused? */
-int seek_needed_; /* if != -1, it is the point that the decode thread should seek to, in ms. */
+In_Module mod_; /* the input module (declared near the bottom of this file) */
+char ini_name[MAX_PATH];
+flac_config_t flac_cfg;
+
+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
-FLAC__int32 reservoir_[FLAC__MAX_BLOCK_SIZE * 2/*for overflow*/ * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
-char sample_buffer_[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8) * 2]; /* (24/8) for max bytes per sample, and 2 for who knows what */
-unsigned wide_samples_in_reservoir_;
+static FLAC__int32 reservoir_[FLAC__MAX_BLOCK_SIZE * 2/*for overflow*/ * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
+static char sample_buffer_[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8) * 2]; /* (24/8) for max bytes per sample, and 2 for who knows what */
+static unsigned wide_samples_in_reservoir_;
 static file_info_struct file_info_;
 static FLAC__FileDecoder *decoder_;
 
-int killDecodeThread = 0;                                      /* the kill switch for the decode thread */
-HANDLE thread_handle = INVALID_HANDLE_VALUE;   /* the handle to the decode thread */
+static volatile int killDecodeThread = 0; /* the kill switch for the decode thread */
+HANDLE thread_handle = INVALID_HANDLE_VALUE; /* the handle to the decode thread */
 
-DWORD WINAPI __stdcall DecodeThread(void *b); /* the decode thread procedure */
-
-
-static void do_vis(char *data, int nch, int resolution, int position, unsigned samples)
-{
-       static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
-       char *ptr;
-       int size, count;
-
-       /*
-        * Winamp visuals may have problems accepting sample sizes larger than
-        * 16 bits, so we reduce the sample size here if necessary.
-        */
-
-       switch(resolution) {
-               case 32:
-               case 24:
-                       size  = resolution / 8;
-                       count = samples * nch;
-
-                       ptr = vis_buffer;
-                       while(count--) {
-                               data += size;
-                               *ptr++ = data[-1] ^ 0x80;
-                       }
-
-                       data = vis_buffer;
-                       resolution = 8;
+static DWORD WINAPI DecodeThread(void *b); /* the decode thread procedure */
 
-                       /* fall through */
-               case 16:
-               case 8:
-               default:
-                       mod_.SAAddPCMData(data, nch, resolution, position);
-                       mod_.VSAAddPCMData(data, nch, resolution, position);
-       }
-}
 
 void config(HWND hwndParent)
 {
-       MessageBox(hwndParent, "No configuration.", "Configuration", MB_OK);
-       /* if we had a configuration we'd want to write it here :) */
+       if (DoConfig(hwndParent))
+               WriteConfig();
 }
+
 void about(HWND hwndParent)
 {
        MessageBox(hwndParent, "Winamp FLAC Plugin v" VERSION ", by Josh Coalson\nSee http://flac.sourceforge.net/", "About FLAC Plugin", MB_OK);
@@ -120,12 +94,22 @@ void about(HWND hwndParent)
 
 void init()
 {
+       char *p;
+
        decoder_ = FLAC__file_decoder_new();
        strcpy(lastfn_, "");
+       // read config
+       GetModuleFileName(NULL, ini_name, sizeof(ini_name));
+       p = strrchr(ini_name, '.');
+       if (!p) p = ini_name + strlen(ini_name);
+       strcpy(p, ".ini");
+
+       ReadConfig();
 }
 
 void quit()
 {
+       WriteConfig();
        safe_decoder_delete_(decoder_);
        decoder_ = 0;
 }
@@ -137,52 +121,48 @@ int play(char *fn)
 {
        int maxlatency;
        int thread_id;
-       HANDLE input_file = INVALID_HANDLE_VALUE;
-       unsigned output_bits_per_sample;
+       HANDLE input_file;
 
-       if(0 == decoder_) {
+       if(0 == decoder_)
                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) {
+       if(input_file == INVALID_HANDLE_VALUE)
                return -1;
-       }
        CloseHandle(input_file);
 
-       if(!safe_decoder_init_(fn, decoder_)) {
+       file_info_.abort_flag = false;
+       file_info_.has_replaygain = false;
+       if(!safe_decoder_init_(fn, decoder_))
                return 1;
-       }
-
-#ifdef FLAC__DO_DITHER
-       output_bits_per_sample = min(file_info_.bits_per_sample, 16);
-#else
-       output_bits_per_sample = file_info_.bits_per_sample;
-#endif
 
        strcpy(lastfn_, fn);
-       paused_ = 0;
-       decode_pos_ms_ = 0;
-       seek_needed_ = -1;
        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;
+
+       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);
 
-       maxlatency = mod_.outMod->Open(file_info_.sample_rate, file_info_.channels, output_bits_per_sample, -1, -1);
-       if(maxlatency < 0) /* error opening device */
+       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 */
                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);
-
        /* 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);
 
-       mod_.outMod->SetVolume(-666); /* set the output plug-ins default volume */
-
+       paused_ = 0;
+       decode_pos_ms_ = 0;
+       seek_needed_ = -1;
        killDecodeThread = 0;
-       thread_handle = (HANDLE) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DecodeThread, (void *) &killDecodeThread, 0, &thread_id);
+       thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DecodeThread, NULL, 0, &thread_id);
 
        return 0;
 }
@@ -208,7 +188,7 @@ void stop()
 {
        if(thread_handle != INVALID_HANDLE_VALUE) {
                killDecodeThread = 1;
-               if(WaitForSingleObject(thread_handle, INFINITE) == WAIT_TIMEOUT) {
+               if(WaitForSingleObject(thread_handle, 2000) == WAIT_TIMEOUT) {
                        MessageBox(mod_.hMainWindow, "error asking thread to die!\n", "error killing decode thread", 0);
                        TerminateThread(thread_handle, 0);
                }
@@ -243,6 +223,14 @@ 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)",
+                       lastfn_, file_info_.length_in_msec/60000, (file_info_.length_in_msec/1000)%60, file_info_.has_replaygain ? "" : "not ",
+                       file_info_.sample_rate, file_info_.channels, file_info_.bits_per_sample, file_info_.output_bits_per_sample);
+               MessageBox(hwnd, buffer, "FLAC Info", 0);
+       }
+
        return 0;
 }
 
@@ -250,7 +238,7 @@ void getfileinfo(char *filename, char *title, int *length_in_msec)
 {
        FLAC__StreamMetadata streaminfo;
 
-       if(0 == filename || filename[0] == '\0') {
+       if (!filename || !*filename) {
                filename = lastfn_;
                if(length_in_msec) {
                        *length_in_msec = getlength();
@@ -276,23 +264,56 @@ void getfileinfo(char *filename, char *title, int *length_in_msec)
                *length_in_msec = (int)(streaminfo.data.stream_info.total_samples * 10 / (streaminfo.data.stream_info.sample_rate / 100));
 }
 
-void eq_set(int on, char data[10], int preamp)
+void eq_set(int on, char data[10], int preamp) {}
+
+static void do_vis(char *data, int nch, int resolution, int position, unsigned samples)
 {
+       static char vis_buffer[SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
+       char *ptr;
+       int size, count;
+
+       /*
+        * Winamp visuals may have problems accepting sample sizes larger than
+        * 16 bits, so we reduce the sample size here if necessary.
+        */
+
+       switch(resolution) {
+               case 32:
+               case 24:
+                       size  = resolution / 8;
+                       count = samples * nch;
+                       data += size - 1;
+
+                       ptr = vis_buffer;
+                       while(count--) {
+                               *ptr++ = data[0] ^ 0x80;
+                               data += size;
+                       }
+
+                       data = vis_buffer;
+                       resolution = 8;
+
+                       /* fall through */
+               case 16:
+               case 8:
+               default:
+                       mod_.SAAddPCMData(data, nch, resolution, position);
+                       mod_.VSAAddPCMData(data, nch, resolution, position);
+       }
 }
 
-DWORD WINAPI __stdcall DecodeThread(void *b)
+static DWORD WINAPI DecodeThread(void *unused)
 {
        int done = 0;
 
-       while(! *((int *)b) ) {
+       (void)unused;
+
+       while(!killDecodeThread) {
                const unsigned channels = file_info_.channels;
                const unsigned bits_per_sample = file_info_.bits_per_sample;
-#ifdef FLAC__DO_DITHER
-               const unsigned target_bps = min(bits_per_sample, 16);
-#else
-               const unsigned target_bps = bits_per_sample;
-#endif
+               const unsigned target_bps = file_info_.output_bits_per_sample;
                const unsigned sample_rate = file_info_.sample_rate;
+
                if(seek_needed_ != -1) {
                        const double distance = (double)seek_needed_ / (double)getlength();
                        const unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples);
@@ -329,14 +350,40 @@ DWORD WINAPI __stdcall DecodeThread(void *b)
                        else {
                                const unsigned n = min(wide_samples_in_reservoir_, SAMPLES_PER_WRITE);
                                const unsigned delta = n * channels;
-                               int bytes = (int)FLAC__plugin_common__pack_pcm_signed_little_endian(sample_buffer_, reservoir_, n, channels, bits_per_sample, target_bps);
+                               int bytes;
                                unsigned i;
 
+                               if(flac_cfg.output.replaygain.enable && file_info_.has_replaygain) {
+                                       bytes = (int)FLAC__plugin_common__apply_gain(
+                                               sample_buffer_,
+                                               reservoir_,
+                                               n,
+                                               channels,
+                                               bits_per_sample,
+                                               target_bps,
+                                               (float)file_info_.replay_scale,
+                                               flac_cfg.output.replaygain.hard_limit,
+                                               flac_cfg.output.resolution.replaygain.dither,
+                                               (NoiseShaping)flac_cfg.output.resolution.replaygain.noise_shaping,
+                                               &file_info_.dither_context
+                                       );
+                               }
+                               else {
+                                       bytes = (int)FLAC__plugin_common__pack_pcm_signed_little_endian(
+                                               sample_buffer_,
+                                               reservoir_,
+                                               n,
+                                               channels,
+                                               bits_per_sample,
+                                               target_bps
+                                       );
+                               }
+
                                for(i = delta; i < wide_samples_in_reservoir_ * channels; i++)
                                        reservoir_[i-delta] = reservoir_[i];
                                wide_samples_in_reservoir_ -= n;
 
-                               do_vis((char *)sample_buffer_, channels, target_bps, decode_pos_ms_, n);
+                               do_vis(sample_buffer_, channels, target_bps, decode_pos_ms_, n);
                                decode_pos_ms_ += (n*1000 + sample_rate/2)/sample_rate;
                                if(mod_.dsp_isactive())
                                        bytes = mod_.dsp_dosamples((short *)sample_buffer_, n, target_bps, channels, sample_rate) * (channels*target_bps/8);
@@ -413,8 +460,11 @@ FLAC__bool safe_decoder_init_(const char *filename, FLAC__FileDecoder *decoder)
 
        FLAC__file_decoder_set_md5_checking(decoder, false);
        FLAC__file_decoder_set_filename(decoder, filename);
-       FLAC__file_decoder_set_write_callback(decoder, write_callback_);
+       FLAC__file_decoder_set_metadata_ignore_all(decoder);
+       FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+       FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
        FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
+       FLAC__file_decoder_set_write_callback(decoder, write_callback_);
        FLAC__file_decoder_set_error_callback(decoder, error_callback_);
        FLAC__file_decoder_set_client_data(decoder, &file_info_);
        if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
@@ -422,16 +472,13 @@ FLAC__bool safe_decoder_init_(const char *filename, FLAC__FileDecoder *decoder)
                return false;
        }
 
-       file_info_.abort_flag = false;
        if(!FLAC__file_decoder_process_until_end_of_metadata(decoder)) {
                MessageBox(mod_.hMainWindow, FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)], "ERROR processing metadata", 0);
                return false;
        }
 
-       if(file_info_.abort_flag) {
-               /* metadata callback already popped up the error dialog */
-               return false;
-       }
+       if(file_info_.abort_flag)
+               return false;                                       /* metadata callback already popped up the error dialog */
 
        return true;
 }
@@ -474,6 +521,7 @@ void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMeta
 {
        file_info_struct *file_info = (file_info_struct *)client_data;
        (void)decoder;
+
        if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
                FLAC__ASSERT(metadata->data.stream_info.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
                file_info->total_samples = (unsigned)(metadata->data.stream_info.total_samples&0xffffffff);
@@ -481,21 +529,20 @@ void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMeta
                file_info->channels = metadata->data.stream_info.channels;
                file_info->sample_rate = metadata->data.stream_info.sample_rate;
 
-#ifdef FLAC__DO_DITHER
-               if(file_info->bits_per_sample != 8 && file_info->bits_per_sample != 16 && file_info->bits_per_sample != 24) {
-                       MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16/24-bit samples\n", "ERROR: plugin can only handle 8/16/24-bit samples", 0);
-                       file_info->abort_flag = true;
-                       return;
-               }
-#else
                if(file_info->bits_per_sample != 8 && file_info->bits_per_sample != 16 && file_info->bits_per_sample != 24) {
                        MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16/24-bit samples\n", "ERROR: plugin can only handle 8/16/24-bit samples", 0);
                        file_info->abort_flag = true;
                        return;
                }
-#endif
                file_info->length_in_msec = file_info->total_samples * 10 / (file_info->sample_rate / 100);
        }
+       else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+               double gain, peak;
+               if(grabbag__replaygain_load_from_vorbiscomment(metadata, flac_cfg.output.replaygain.album_mode, &gain, &peak)) {
+                       file_info_.has_replaygain = true;
+                       file_info_.replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)flac_cfg.output.replaygain.preamp, /*prevent_clipping=*/!flac_cfg.output.replaygain.hard_limit);
+               }
+       }
 }
 
 void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
index c1285e3..c77c34b 100644 (file)
@@ -43,7 +43,7 @@ RSC=rc.exe
 # PROP Ignore_Export_Lib 0\r
 # PROP Target_Dir ""\r
 # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "in_flac_EXPORTS" /YX /FD /c\r
-# ADD CPP /nologo /MD /W3 /GX /O2 /I ".." /I "..\..\include" /D "NDEBUG" /D VERSION=\"1.0.5-beta1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c\r
+# ADD CPP /nologo /MD /W3 /GX /Ox /Og /Oi /Os /Op /Ob1 /I "include" /I ".." /I "..\..\include" /D "NDEBUG" /D VERSION=\"1.0.5-beta1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c\r
 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
 # ADD BASE RSC /l 0x409 /d "NDEBUG"\r
@@ -53,7 +53,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo\r
 LINK32=link.exe\r
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
-# ADD LINK32 ..\..\obj\release\lib\plugin_common_static.lib ..\..\obj\release\lib\grabbag_static.lib ..\..\obj\release\lib\libFLAC_static.lib kernel32.lib user32.lib /nologo /dll /machine:I386 /nodefaultlib:"libc.lib" /out:"../../obj/release/bin/in_flac.dll" /libpath:"../../obj/release/lib"\r
+# ADD LINK32 plugin_common_static.lib grabbag_static.lib libFLAC_static.lib gain_analysis_static.lib kernel32.lib user32.lib /nologo /dll /machine:I386 /nodefaultlib:"libc.lib" /out:"../../obj/release/bin/in_flac.dll" /libpath:"../../obj/release/lib" /opt:nowin98\r
 # SUBTRACT LINK32 /pdb:none\r
 \r
 !ELSEIF  "$(CFG)" == "in_flac - Win32 Debug"\r
@@ -70,7 +70,7 @@ LINK32=link.exe
 # PROP Ignore_Export_Lib 0\r
 # PROP Target_Dir ""\r
 # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "in_flac_EXPORTS" /YX /FD /GZ /c\r
-# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".." /I "..\..\include" /D "_DEBUG" /D "REAL_STDIO" /D VERSION=\"1.0.5-beta1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "include" /I ".." /I "..\..\include" /D "_DEBUG" /D "REAL_STDIO" /D VERSION=\"1.0.5-beta1\" /D "in_flac_EXPORTS" /D "FLAC__NO_DLL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c\r
 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
 # ADD BASE RSC /l 0x409 /d "_DEBUG"\r
@@ -106,8 +106,20 @@ SOURCE="out.h"
 # End Group\r
 # Begin Source File\r
 \r
+SOURCE=.\config.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\config.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\in_flac.c\r
 # End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\resource.rc\r
+# End Source File\r
 # End Group\r
 # End Target\r
 # End Project\r
diff --git a/src/plugin_winamp2/resource.h b/src/plugin_winamp2/resource.h
new file mode 100644 (file)
index 0000000..fc6a6c9
--- /dev/null
@@ -0,0 +1,26 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Developer Studio generated include file.\r
+// Used by resource.rc\r
+//\r
+#define IDC_RESET                       3\r
+#define IDD_CONFIG                      101\r
+#define IDC_ENABLE                      1000\r
+#define IDC_ALBUM                       1001\r
+#define IDC_LIMITER                     1002\r
+#define IDC_PREAMP                      1003\r
+#define IDC_PA                          1004\r
+#define IDC_DITHER                      1005\r
+#define IDC_DITHERRG                    1006\r
+#define IDC_TO                          1008\r
+#define IDC_SHAPE                       1009\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        102\r
+#define _APS_NEXT_COMMAND_VALUE         40001\r
+#define _APS_NEXT_CONTROL_VALUE         1009\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
diff --git a/src/plugin_winamp2/resource.rc b/src/plugin_winamp2/resource.rc
new file mode 100644 (file)
index 0000000..48c9cda
--- /dev/null
@@ -0,0 +1,124 @@
+//Microsoft Developer Studio generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Russian resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT\r
+#pragma code_page(1251)\r
+#endif //_WIN32\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDD_CONFIG DIALOG DISCARDABLE  0, 0, 227, 193\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+CAPTION "FLAC Configuration"\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    GROUPBOX        " ReplayGain  ",IDC_STATIC,4,2,220,57\r
+    CONTROL         "&Enable ReplayGain",IDC_ENABLE,"Button",BS_AUTOCHECKBOX | \r
+                    WS_TABSTOP,10,15,77,10\r
+    CONTROL         "&Album mode",IDC_ALBUM,"Button",BS_AUTOCHECKBOX | \r
+                    WS_TABSTOP,10,27,55,10\r
+    CONTROL         "6dB &hard limiter",IDC_LIMITER,"Button",BS_AUTOCHECKBOX | \r
+                    WS_TABSTOP,125,27,64,10\r
+    LTEXT           "&Preamp",IDC_STATIC,10,44,25,8\r
+    CONTROL         "Slider1",IDC_PREAMP,"msctls_trackbar32",TBS_NOTICKS | \r
+                    WS_TABSTOP,38,43,154,12\r
+    RTEXT           "",IDC_PA,196,44,21,8\r
+    GROUPBOX        " Resolution  ",IDC_STATIC,3,62,220,96\r
+    GROUPBOX        " Without ReplayGain ",IDC_STATIC,9,71,209,30\r
+    CONTROL         "&Dither 24bps to 16bps",IDC_DITHER,"Button",\r
+                    BS_AUTOCHECKBOX | WS_TABSTOP,18,84,85,10\r
+    GROUPBOX        " With ReplayGain ",IDC_STATIC,9,104,209,48\r
+    CONTROL         "E&nable dithering",IDC_DITHERRG,"Button",\r
+                    BS_AUTOCHECKBOX | WS_TABSTOP,18,116,67,10\r
+    LTEXT           "Dither &to",IDC_STATIC,18,135,28,8\r
+    COMBOBOX        IDC_TO,52,132,39,43,CBS_DROPDOWNLIST | WS_VSCROLL | \r
+                    WS_TABSTOP\r
+    LTEXT           "Noise &shaping",IDC_STATIC,115,135,46,8\r
+    COMBOBOX        IDC_SHAPE,166,132,46,48,CBS_DROPDOWNLIST | WS_VSCROLL | \r
+                    WS_TABSTOP\r
+    DEFPUSHBUTTON   "OK",IDOK,65,176,50,14\r
+    PUSHBUTTON      "Cancel",IDCANCEL,119,176,50,14\r
+    PUSHBUTTON      "Reset",IDC_RESET,173,176,50,14\r
+    LTEXT           "Note: pressing OK will stop FLAC playback",IDC_STATIC,4,\r
+                    162,135,8\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO DISCARDABLE \r
+BEGIN\r
+    IDD_CONFIG, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 220\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 186\r
+    END\r
+END\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#endif    // Russian resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r