1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062 |
- /*
- ** .WV input plug-in for WavPack
- ** Copyright (c) 2000 - 2006, Conifer Software, All Rights Reserved
- */
- #include <windows.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <mmreg.h>
- #include <msacm.h>
- #include <math.h>
- #include <sys/stat.h>
- #include <io.h>
- #include <strsafe.h>
- #include "in2.h"
- #include "wavpack.h"
- #include "resource.h"
- #include "wasabi/winamp/wa_ipc.h"
- #include "wasabi/wasabi.h"
- #include "wasabi/nu/autochar.h"
- #include "wasabi/nu/autowide.h"
- #define fileno _fileno
- static float calculate_gain(WavpackContext *wpc, bool allowDefault=true);
- #define PLUGIN_VERSION "2.8.1"
- //#define DEBUG_CONSOLE
- //#define ANSI_METADATA
- #define UNICODE_METADATA
- //#define OLD_INFO_DIALOG
- // post this to the main window at end of file (after playback as stopped)
- #define WM_WA_MPEG_EOF WM_USER+2
- #define MAX_NCH 8
- static struct wpcnxt {
- WavpackContext *wpc; // WavPack context provided by library
- float play_gain; // playback gain (for replaygain support)
- //int soft_clipping; // soft clipping active for playback
- int output_bits; // 16, 24, or 32 bits / sample
- long sample_buffer[576*MAX_NCH*2]; // sample buffer
- float error [MAX_NCH]; // error term for noise shaping
- char lastfn[MAX_PATH]; // filename stored for comparisons only
- wchar_t w_lastfn[MAX_PATH]; // w_filename stored for comparisons only
- FILE *wv_id, *wvc_id; // file pointer when we use reader callbacks
- } curr, edit, info;
- 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.
- #define ALLOW_WVC 0x1
- #define REPLAYGAIN_TRACK 0x2
- #define REPLAYGAIN_ALBUM 0x4
- #define SOFTEN_CLIPPING 0x8
- #define PREVENT_CLIPPING 0x10
- #define ALWAYS_16BIT 0x20 // new flags added for version 2.5
- #define ALLOW_MULTICHANNEL 0x40
- #define REPLAYGAIN_24BIT 0x80
- int config_bits = ALLOW_WVC | ALLOW_MULTICHANNEL; // all configuration goes here
- 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 api_service* WASABI_API_SVC;
- static api_language* WASABI_API_LNG;
- static api_config *AGAVE_API_CONFIG;
- static api_memmgr *WASABI_API_MEMMGR;
- HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
- static char file_extensions[128] = {"WV\0WavPack Files (*.WV)\0"};
- // function definitions for the In_Module stucture
- void about (HWND hwndParent);
- void init();
- void quit();
- void getfileinfo(const char *filename, char *title, int *length_in_ms);
- int infoDlg(const char *fn, HWND hwnd);
- int isourfile(const char *fn);
- int play(const char *fn);
- void pause();
- void unpause();
- int ispaused();
- void stop();
- int getlength();
- int getoutputtime();
- void setoutputtime(int time_in_ms);
- void setvolume(int volume);
- void setpan(int pan);
- void eq_set(int on, char data [10], int preamp);
- In_Module mod = // the output module
- {
- IN_VER,
- "WavPack Decoder v"PLUGIN_VERSION,
- 0, // hMainWindow
- 0, // hDllInstance
- file_extensions,
- 1, // is_seekable
- 1, // uses output
- about,
- about,
- init,
- quit,
- getfileinfo,
- infoDlg,
- isourfile,
- play,
- pause,
- unpause,
- ispaused,
- stop,
- getlength,
- getoutputtime,
- setoutputtime,
- setvolume,
- setpan,
- 0,0,0,0,0,0,0,0,0, // vis stuff
- 0,0, // dsp
- eq_set,
- NULL, // setinfo
- 0 // out_mod
- };
- static BOOL CALLBACK WavPackDlgProc(HWND, UINT, WPARAM, LPARAM);
- extern long dump_alloc (void);
- int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
- {
- MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
- msgbx.lpszText = message;
- msgbx.lpszCaption = title;
- msgbx.lpszIcon = MAKEINTRESOURCEW(102);
- msgbx.hInstance = GetModuleHandle(0);
- msgbx.dwStyle = MB_USERICON;
- msgbx.hwndOwner = parent;
- return MessageBoxIndirectW(&msgbx);
- }
- void about(HWND hwndParent)
- {
- wchar_t about_string[512];
- #ifdef DEBUG_ALLOC
- sprintf (about_string, "alloc_count = %d", dump_alloc ());
- #else
- StringCchPrintfW(about_string, 512, WASABI_API_LNGSTRINGW(IDS_ABOUT_MESSAGE), PLUGIN_VERSION, "1998-2010", __DATE__);
- #endif
- DoAboutMessageBox(hwndParent, WASABI_API_LNGSTRINGW(IDS_ABOUT), about_string);
- }
- void init() /* any one-time initialization goes here (configuration reading, etc) */
- {
- if (mod.hMainWindow)
- {
- // load all of the required wasabi services from the winamp client
- WASABI_API_SVC = (api_service *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
- if (WASABI_API_SVC == (api_service *)1)
- WASABI_API_SVC=0;
- WASABI_API_SVC->service_register(&albumArtFactory);
- }
- ServiceBuild(AGAVE_API_CONFIG, AgaveConfigGUID);
- ServiceBuild(WASABI_API_LNG, languageApiGUID);
- ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
- // need to have this initialised before we try to do anything with localisation features
- WASABI_API_START_LANG(mod.hDllInstance,InWvLangGuid);
- static char szDescription[256];
- StringCchPrintfA(szDescription,256,WASABI_API_LNGSTRING(IDS_DESCRIPTION),PLUGIN_VERSION);
- mod.description = szDescription;
- // set the file extension to the localised version
- char tmp [64], *tmp_ptr = tmp, *fex_ptr = file_extensions;
- WASABI_API_LNGSTRING_BUF(IDS_FILETYPE, tmp, sizeof (tmp));
- *fex_ptr++ = 'W';
- *fex_ptr++ = 'V';
- *fex_ptr++ = 0;
- while (*tmp_ptr)
- *fex_ptr++ = *tmp_ptr++;
- *fex_ptr++ = 0;
- *fex_ptr++ = 0;
- }
- #ifdef DEBUG_CONSOLE
- HANDLE debug_console=INVALID_HANDLE_VALUE; // debug console
- void debug_write (char *str)
- {
- static int cant_debug;
- if (cant_debug)
- return;
- if (debug_console == INVALID_HANDLE_VALUE) {
- AllocConsole ();
- #if 1
- debug_console = GetStdHandle (STD_OUTPUT_HANDLE);
- #else
- debug_console = CreateConsoleScreenBuffer (GENERIC_WRITE, FILE_SHARE_WRITE,
- NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
- #endif
- if (debug_console == INVALID_HANDLE_VALUE) {
- MessageBox(NULL, "Can't get a console handle", "WavPack",MB_OK);
- cant_debug = 1;
- return;
- }
- else if (!SetConsoleActiveScreenBuffer (debug_console)) {
- MessageBox(NULL, "Can't activate console buffer", "WavPack",MB_OK);
- cant_debug = 1;
- return;
- }
- }
- WriteConsole (debug_console, str, strlen (str), NULL, NULL);
- }
- #endif
- void quit() /* one-time deinit, such as memory freeing */
- {
- #ifdef DEBUG_CONSOLE
- if (debug_console != INVALID_HANDLE_VALUE) {
- FreeConsole ();
- if (debug_console != GetStdHandle (STD_OUTPUT_HANDLE))
- CloseHandle (debug_console);
- debug_console = INVALID_HANDLE_VALUE;
- }
- #endif
- ServiceRelease(AGAVE_API_CONFIG, AgaveConfigGUID);
- ServiceRelease(WASABI_API_LNG, languageApiGUID);
- ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
- WASABI_API_SVC->service_deregister(&albumArtFactory);
- }
- // used for detecting URL streams.. unused here. strncmp(fn,"http://",7) to detect HTTP streams, etc
- int isourfile(const char *fn)
- {
- return 0;
- }
- int play(const char *fn)
- {
- int num_chans, sample_rate;
- char error[128];
- int maxlatency;
- int thread_id;
- int open_flags;
- #ifdef DEBUG_CONSOLE
- sprintf (error, "play (%s)\n", fn);
- debug_write (error);
- #endif
- open_flags = OPEN_TAGS | OPEN_NORMALIZE;
- if (config_bits & ALLOW_WVC)
- open_flags |= OPEN_WVC;
- if (!(config_bits & ALLOW_MULTICHANNEL))
- open_flags |= OPEN_2CH_MAX;
- curr.wpc = WavpackOpenFileInput(fn, error, open_flags, 0);
- if (!curr.wpc) // error opening file, just return error
- return -1;
- num_chans = WavpackGetReducedChannels(curr.wpc);
- sample_rate = WavpackGetSampleRate(curr.wpc);
- curr.output_bits = WavpackGetBitsPerSample(curr.wpc) > 16 ? 24 : 16;
- if (config_bits & ALWAYS_16BIT)
- curr.output_bits = 16;
- else if ((config_bits & (REPLAYGAIN_TRACK | REPLAYGAIN_ALBUM)) &&
- (config_bits & REPLAYGAIN_24BIT))
- curr.output_bits = 24;
-
- if (num_chans > MAX_NCH) // don't allow too many channels!
- {
- WavpackCloseFile(curr.wpc);
- return -1;
- }
- curr.play_gain = calculate_gain(curr.wpc);
- lstrcpyn(curr.lastfn, fn, MAX_PATH);
- paused = 0;
- decode_pos_ms = 0;
- seek_needed = -1;
- maxlatency = mod.outMod->Open(sample_rate, num_chans, curr.output_bits, -1, -1);
- if (maxlatency < 0) // error opening device
- {
- curr.wpc = WavpackCloseFile(curr.wpc);
- return -1;
- }
- // dividing by 1000 for the first parameter of setinfo makes it
- // display 'H'... for hundred.. i.e. 14H Kbps.
- mod.SetInfo(0, (sample_rate + 500) / 1000, num_chans, 1);
- // initialize vis stuff
- mod.SAVSAInit(maxlatency, sample_rate);
- mod.VSASetInfo(sample_rate, num_chans);
- mod.outMod->SetVolume(-666); // set the output plug-ins default volume
- killDecodeThread=0;
- thread_handle = (HANDLE)CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) DecodeThread, (void *) &killDecodeThread, 0, (LPDWORD)&thread_id);
- if (SetThreadPriority(thread_handle, THREAD_PRIORITY_HIGHEST) == 0) {
- curr.wpc = WavpackCloseFile(curr.wpc);
- return -1;
- }
- return 0;
- }
- void pause()
- {
- #ifdef DEBUG_CONSOLE
- debug_write ("pause ()\n");
- #endif
- paused = 1;
- mod.outMod->Pause(1);
- }
- void unpause()
- {
- #ifdef DEBUG_CONSOLE
- debug_write ("unpause ()\n");
- #endif
- paused = 0;
- mod.outMod->Pause(0);
- }
- int ispaused()
- {
- return paused;
- }
- void stop()
- {
- #ifdef DEBUG_CONSOLE
- debug_write ("stop ()\n");
- #endif
- if (thread_handle != INVALID_HANDLE_VALUE)
- {
- killDecodeThread = 1;
- if (WaitForSingleObject(thread_handle, INFINITE) == WAIT_TIMEOUT)
- {
- MessageBox(mod.hMainWindow,"error asking thread to die!\n", "error killing decode thread", 0);
- TerminateThread(thread_handle,0);
- }
- CloseHandle(thread_handle);
- thread_handle = INVALID_HANDLE_VALUE;
- }
- if (curr.wpc)
- curr.wpc = WavpackCloseFile(curr.wpc);
- mod.outMod->Close();
- mod.SAVSADeInit();
- }
- int getlength()
- {
- return (int)(WavpackGetNumSamples (curr.wpc) * 1000.0 / WavpackGetSampleRate (curr.wpc));
- }
- int getoutputtime()
- {
- if (seek_needed == -1)
- return decode_pos_ms + (mod.outMod->GetOutputTime () - mod.outMod->GetWrittenTime ());
- else
- return seek_needed;
- }
- void setoutputtime (int time_in_ms)
- {
- #ifdef DEBUG_CONSOLE
- char str [40];
- sprintf (str, "setoutputtime (%d)\n", time_in_ms);
- debug_write (str);
- #endif
- seek_needed = time_in_ms;
- }
- void setvolume (int volume)
- {
- mod.outMod->SetVolume(volume);
- }
- void setpan (int pan)
- {
- mod.outMod->SetPan(pan);
- }
- static void generate_format_string(WavpackContext *wpc, wchar_t *string, int maxlen, int wide);
- static void AnsiToUTF8(char *string, int len);
- static int UTF8ToWideChar(const char *pUTF8, wchar_t *pWide);
- static void UTF8ToAnsi(char *string, int len);
- int infoDlg(const char *fn, HWND hwnd)
- {
- #ifdef OLD_INFO_DIALOG
- char string[2048];
- wchar_t w_string[2048];
- WavpackContext *wpc;
- int open_flags;
- open_flags = OPEN_TAGS | OPEN_NORMALIZE;
- if (config_bits & ALLOW_WVC)
- open_flags |= OPEN_WVC;
- if (!(config_bits & ALLOW_MULTICHANNEL))
- open_flags |= OPEN_2CH_MAX;
- wpc = WavpackOpenFileInput(fn, string, open_flags, 0);
- if (wpc)
- {
- int mode = WavpackGetMode(wpc);
- //generate_format_string(wpc, string, sizeof (string), 1);
- wchar_t *temp = (wchar_t *)malloc(sizeof(string) * sizeof(wchar_t));
- generate_format_string(wpc, temp, sizeof(string), 0);
- lstrcpyn(string, AutoChar(temp, CP_UTF8), sizeof(string));
- free(temp);
- if (WavpackGetMode(wpc) & MODE_VALID_TAG)
- {
- char value [128];
- if (config_bits & (REPLAYGAIN_TRACK | REPLAYGAIN_ALBUM))
- {
- int local_clipping = 0;
- float local_gain;
- local_gain = calculate_gain(wpc);
- if (local_gain != 1.0)
- StringCchPrintf(string + strlen (string), 2048, "Gain: %+.2f dB %s\n",
- log10 (local_gain) * 20.0, local_clipping ? "(w/soft clipping)" : "");
- }
- if (WavpackGetTagItem(wpc, "title", value, sizeof (value)))
- {
- if (!(mode & MODE_APETAG))
- AnsiToUTF8(value, sizeof (value));
- StringCchPrintf(string + strlen (string), 2048, "\nTitle: %s", value);
- }
- if (WavpackGetTagItem(wpc, "artist", value, sizeof (value)))
- {
- if (!(mode & MODE_APETAG))
- AnsiToUTF8(value, sizeof (value));
- StringCchPrintf(string + strlen (string), 2048, "\nArtist: %s", value);
- }
- if (WavpackGetTagItem (wpc, "album", value, sizeof (value)))
- {
- if (!(mode & MODE_APETAG))
- AnsiToUTF8(value, sizeof (value));
- StringCchPrintf (string + strlen (string), 2048, "\nAlbum: %s", value);
- }
- if (WavpackGetTagItem (wpc, "genre", value, sizeof (value)))
- {
- if (!(mode & MODE_APETAG))
- AnsiToUTF8(value, sizeof (value));
- StringCchPrintf(string + strlen (string), 2048, "\nGenre: %s", value);
- }
- if (WavpackGetTagItem (wpc, "comment", value, sizeof (value)))
- {
- if (!(mode & MODE_APETAG))
- AnsiToUTF8(value, sizeof (value));
- StringCchPrintf(string + strlen (string), 2048, "\nComment: %s", value);
- }
- if (WavpackGetTagItem(wpc, "year", value, sizeof (value)))
- StringCchPrintf(string + strlen (string), 2048, "\nYear: %s", value);
- if (WavpackGetTagItem(wpc, "track", value, sizeof (value)))
- StringCchPrintf(string + strlen (string), 2048, "\nTrack: %s", value);
- StringCchCat(string, 2048, "\n");
- }
- UTF8ToWideChar(string, w_string);
- MessageBoxW(hwnd, w_string, L"WavPack File Info Box", MB_OK);
- wpc = WavpackCloseFile(wpc);
- }
- else
- MessageBox(hwnd, string, "WavPack Decoder", MB_OK);
- return 0;
- #else
- return 1;
- #endif
- }
- void getfileinfo(const char *filename, char *title, int *length_in_ms)
- {
- if (!filename || !*filename) // currently playing file
- {
- if (length_in_ms)
- *length_in_ms = getlength ();
- if (title)
- {
- if (WavpackGetTagItem(curr.wpc, "title", NULL, 0))
- {
- char art [128], ttl [128];
- WavpackGetTagItem(curr.wpc, "title", ttl, sizeof (ttl));
- if (WavpackGetMode(curr.wpc) & MODE_APETAG)
- UTF8ToAnsi(ttl, sizeof (ttl));
- if (WavpackGetTagItem(curr.wpc, "artist", art, sizeof (art)))
- {
- if (WavpackGetMode(curr.wpc) & MODE_APETAG)
- UTF8ToAnsi(art, sizeof (art));
- StringCchPrintf(title, GETFILEINFO_TITLE_LENGTH, "%s - %s", art, ttl);
- }
- else
- lstrcpyn(title, ttl, GETFILEINFO_TITLE_LENGTH);
- }
- else
- {
- char *p = curr.lastfn + strlen (curr.lastfn);
- while (*p != '\\' && p >= curr.lastfn)
- p--;
- lstrcpyn(title, ++p, GETFILEINFO_TITLE_LENGTH);
- }
- }
- }
- else // some other file
- {
- WavpackContext *wpc;
- char error [128];
- int open_flags;
- if (length_in_ms)
- *length_in_ms = -1000;
- if (title)
- *title = 0;
- open_flags = OPEN_TAGS | OPEN_NORMALIZE;
- if (config_bits & ALLOW_WVC)
- open_flags |= OPEN_WVC;
- if (!(config_bits & ALLOW_MULTICHANNEL))
- open_flags |= OPEN_2CH_MAX;
- wpc = WavpackOpenFileInput(filename, error, open_flags, 0);
- if (wpc)
- {
- if (length_in_ms)
- *length_in_ms = (int)(WavpackGetNumSamples(wpc) * 1000.0 / WavpackGetSampleRate(wpc));
- if (title && WavpackGetTagItem(wpc, "title", NULL, 0))
- {
- char art [128], ttl [128];
- WavpackGetTagItem(wpc, "title", ttl, sizeof (ttl));
- if (WavpackGetMode(wpc) & MODE_APETAG)
- UTF8ToAnsi(ttl, sizeof (ttl));
- if (WavpackGetTagItem(wpc, "artist", art, sizeof (art)))
- {
- if (WavpackGetMode(wpc) & MODE_APETAG)
- UTF8ToAnsi(art, sizeof (art));
- StringCchPrintf(title, GETFILEINFO_TITLE_LENGTH, "%s - %s", art, ttl);
- }
- else
- lstrcpyn(title, ttl, GETFILEINFO_TITLE_LENGTH);
- }
- wpc = WavpackCloseFile(wpc);
- }
- if (title && !*title)
- {
- char *p = (char*)filename + strlen (filename);
- while (*p != '\\' && p >= filename) p--;
- lstrcpyn(title, ++p, GETFILEINFO_TITLE_LENGTH);
- }
- }
- }
- void eq_set(int on, char data [10], int preamp)
- {
- // most plug-ins can't even do an EQ anyhow.. I'm working on writing
- // a generic PCM EQ, but it looks like it'll be a little too CPU
- // consuming to be useful :)
- }
- static int read_samples(struct wpcnxt *cnxt, int num_samples);
- DWORD WINAPI __stdcall DecodeThread(void *b)
- {
- int num_chans, sample_rate;
- int done = 0;
- memset(curr.error, 0, sizeof (curr.error));
- num_chans = WavpackGetReducedChannels(curr.wpc);
- sample_rate = WavpackGetSampleRate(curr.wpc);
-
- while (!*((int *)b) )
- {
- if (seek_needed != -1)
- {
- int seek_position = seek_needed;
- int bc = 0;
- seek_needed = -1;
- if (seek_position > getlength() - 1000 && getlength() > 1000)
- seek_position = getlength() - 1000; // don't seek to last second
- mod.outMod->Flush(decode_pos_ms = seek_position);
- if (WavpackSeekSample(curr.wpc, (int)(sample_rate / 1000.0 * seek_position))) {
- decode_pos_ms = (int)(WavpackGetSampleIndex(curr.wpc) * 1000.0 / sample_rate);
- mod.outMod->Flush(decode_pos_ms);
- continue;
- }
- else
- done = 1;
- }
- if (done) {
- mod.outMod->CanWrite();
- if (!mod.outMod->IsPlaying()) {
- PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- return 0;
- }
- Sleep(10);
- }
- else if (mod.outMod->CanWrite() >= ((576 * num_chans * (curr.output_bits / 8)) << (mod.dsp_isactive () ? 1 : 0)))
- {
- int tsamples = read_samples (&curr, 576) * num_chans;
- int tbytes = tsamples * (curr.output_bits/8);
- if (tsamples)
- {
- mod.SAAddPCMData((char *) curr.sample_buffer, num_chans, curr.output_bits, decode_pos_ms);
- mod.VSAAddPCMData((char *) curr.sample_buffer, num_chans, curr.output_bits, decode_pos_ms);
- decode_pos_ms = (int)(WavpackGetSampleIndex(curr.wpc) * 1000.0 / sample_rate);
- if (mod.dsp_isactive())
- tbytes = mod.dsp_dosamples ((short *) curr.sample_buffer,
- tsamples / num_chans, curr.output_bits, num_chans, sample_rate) * (num_chans * (curr.output_bits/8));
- mod.outMod->Write ((char *) curr.sample_buffer, tbytes);
- }
- else
- done = 1;
- }
- else
- {
- mod.SetInfo((int) ((WavpackGetInstantBitrate (curr.wpc) + 500.0) / 1000.0), -1, -1, 1);
- Sleep(20);
- }
- }
- return 0;
- }
- /********* These functions provide the "transcoding" mode of winamp. *********/
- extern "C" __declspec (dllexport) intptr_t winampGetExtendedRead_open (const char *fn, int *size, int *bps, int *nch, int *srate)
- {
- struct wpcnxt *cnxt = (struct wpcnxt *)malloc(sizeof (struct wpcnxt));
- int num_chans, sample_rate, open_flags;
- char error[128];
- #ifdef DEBUG_CONSOLE
- sprintf (error, "Read_open (%s)\n", fn);
- debug_write (error);
- #endif
- if (!cnxt)
- return 0;
- memset(cnxt, 0, sizeof (struct wpcnxt));
- open_flags = OPEN_NORMALIZE | OPEN_WVC;
- if (!(config_bits & ALLOW_MULTICHANNEL) || *nch == 2)
- open_flags |= OPEN_2CH_MAX;
- if (config_bits & (REPLAYGAIN_TRACK | REPLAYGAIN_ALBUM))
- open_flags |= OPEN_TAGS;
-
- cnxt->wpc = WavpackOpenFileInput(fn, error, open_flags, 0);
- if (!cnxt->wpc) // error opening file, just return error
- {
- free (cnxt);
- return 0;
- }
- num_chans = WavpackGetReducedChannels(cnxt->wpc);
- sample_rate = WavpackGetSampleRate(cnxt->wpc);
- if (num_chans > MAX_NCH)
- {
- WavpackCloseFile(cnxt->wpc);
- free (cnxt);
- return 0;
- }
- if (*bps != 16 && *bps != 24 && *bps != 32)
- {
- cnxt->output_bits = WavpackGetBitsPerSample(cnxt->wpc) > 16 ? 24 : 16;
- if (config_bits & ALWAYS_16BIT)
- cnxt->output_bits = 16;
- else if ((config_bits & (REPLAYGAIN_TRACK | REPLAYGAIN_ALBUM)) &&
- (config_bits & REPLAYGAIN_24BIT))
- cnxt->output_bits = 24;
- }
- else
- cnxt->output_bits = *bps;
-
- if (num_chans > MAX_NCH) // don't allow too many channels!
- {
- WavpackCloseFile(cnxt->wpc);
- free (cnxt);
- return 0;
- }
- *nch = num_chans;
- *srate = sample_rate;
- *bps = cnxt->output_bits;
- *size = WavpackGetNumSamples(cnxt->wpc) * (*bps / 8) * (*nch);
- cnxt->play_gain = calculate_gain(cnxt->wpc);
- #ifdef DEBUG_CONSOLE
- sprintf (error, "Read_open success! nch=%d, srate=%d, bps=%d, size=%d\n",
- *nch, *srate, *bps, *size);
- debug_write (error);
- #endif
- return (intptr_t) cnxt;
- }
- extern "C" __declspec (dllexport) intptr_t winampGetExtendedRead_getData (intptr_t handle, char *dest, int len, int *killswitch)
- {
- struct wpcnxt *cnxt = (struct wpcnxt *)handle;
- int num_chans = WavpackGetReducedChannels(cnxt->wpc);
- int bytes_per_sample = num_chans * cnxt->output_bits / 8;
- int used = 0;
- #ifdef DEBUG_CONSOLE
- char error [128];
- #endif
- while (used < len && !*killswitch)
- {
- int nsamples = (len - used) / bytes_per_sample, tsamples;
- if (!nsamples)
- break;
- else if (nsamples > 576)
- nsamples = 576;
- tsamples = read_samples(cnxt, nsamples) * num_chans;
- if (tsamples)
- {
- int tbytes = tsamples * (cnxt->output_bits/8);
- memcpy (dest + used, cnxt->sample_buffer, tbytes);
- used += tbytes;
- }
- else
- break;
- }
- #ifdef DEBUG_CONSOLE
- sprintf (error, "Read_getData (%d), actualy read %d\n", len, used);
- debug_write (error);
- #endif
- return used;
- }
- extern "C" __declspec (dllexport) int winampGetExtendedRead_setTime (intptr_t handle, int millisecs)
- {
- struct wpcnxt *cnxt = (struct wpcnxt *) handle;
- int sample_rate = WavpackGetSampleRate(cnxt->wpc);
- return WavpackSeekSample(cnxt->wpc, (int)(sample_rate / 1000.0 * millisecs));
- }
- extern "C" __declspec (dllexport) void winampGetExtendedRead_close (intptr_t handle)
- {
- struct wpcnxt *cnxt = (struct wpcnxt *) handle;
- #ifdef DEBUG_CONSOLE
- char error [128];
- sprintf (error, "Read_close ()\n");
- debug_write (error);
- #endif
- WavpackCloseFile(cnxt->wpc);
- free (cnxt);
- }
- /* This is a generic function to read WavPack samples and convert them to a
- * form usable by winamp. It includes conversion of any WavPack format
- * (including ieee float) to 16, 24, or 32-bit integers (with noise shaping
- * for the 16-bit case) and replay gain implementation (with optional soft
- * clipping). It is used by both the regular "play" code and the newer
- * transcoding functions.
- *
- * The num_samples parameter is the number of "composite" samples to
- * convert and is limited currently to 576 samples for legacy reasons. The
- * return value is the number of samples actually converted and will be
- * equal to the number requested unless an error occurs or the end-of-file
- * is encountered. The converted samples are stored (interleaved) at
- * cnxt->sample_buffer[].
- */
- static int read_samples (struct wpcnxt *cnxt, int num_samples)
- {
- int num_chans = WavpackGetReducedChannels(cnxt->wpc), samples, tsamples;
- samples = WavpackUnpackSamples(cnxt->wpc, (int32_t*) cnxt->sample_buffer, num_samples);
- tsamples = samples * num_chans;
- if (tsamples)
- {
- if (!(WavpackGetMode(cnxt->wpc) & MODE_FLOAT))
- {
- float scaler = (float) (1.0 / ((unsigned long) 1 << (WavpackGetBytesPerSample(cnxt->wpc) * 8 - 1)));
- float *fptr = (float *) cnxt->sample_buffer;
- long *lptr = cnxt->sample_buffer;
- int cnt = tsamples;
- while (cnt--)
- *fptr++ = *lptr++ * scaler;
- }
- if (cnxt->play_gain != 1.0)
- {
- float *fptr = (float *) cnxt->sample_buffer;
- int cnt = tsamples;
- double outval;
- while (cnt--)
- {
- outval = *fptr * cnxt->play_gain;
- /*if (cnxt->soft_clipping)
- {
- if (outval > 0.75)
- outval = 1.0 - (0.0625 / (outval - 0.5));
- else if (outval < -0.75)
- outval = -1.0 - (0.0625 / (outval + 0.5));
- }*/
- *fptr++ = (float) outval;
- }
- }
- if (cnxt->output_bits == 16)
- {
- float *fptr = (float *) cnxt->sample_buffer;
- short *sptr = (short *) cnxt->sample_buffer;
- int cnt = samples, ch;
- while (cnt--)
- for (ch = 0; ch < num_chans; ++ch)
- {
- int dst;
- *fptr -= cnxt->error [ch];
- if (*fptr >= 1.0)
- dst = 32767;
- else if (*fptr <= -1.0)
- dst = -32768;
- else
- dst = (int) floor (*fptr * 32768.0);
- cnxt->error [ch] = (float)(dst / 32768.0 - *fptr++);
- *sptr++ = dst;
- }
- }
- else if (cnxt->output_bits == 24)
- {
- unsigned char *cptr = (unsigned char *) cnxt->sample_buffer;
- float *fptr = (float *) cnxt->sample_buffer;
- int cnt = tsamples;
- long outval;
- while (cnt--) {
- if (*fptr >= 1.0)
- outval = 8388607;
- else if (*fptr <= -1.0)
- outval = -8388608;
- else
- outval = (int) floor (*fptr * 8388608.0);
- *cptr++ = (unsigned char) outval;
- *cptr++ = (unsigned char) (outval >> 8);
- *cptr++ = (unsigned char) (outval >> 16);
- fptr++;
- }
- }
- else if (cnxt->output_bits == 32)
- {
- float *fptr = (float *) cnxt->sample_buffer;
- long *sptr = (long *) cnxt->sample_buffer;
- int cnt = tsamples;
- while (cnt--)
- {
- if (*fptr >= 1.0)
- *sptr++ = 8388607 << 8;
- else if (*fptr <= -1.0)
- *sptr++ = -8388608 << 8;
- else
- *sptr++ = ((int) floor (*fptr * 8388608.0)) << 8;
- fptr++;
- }
- }
- }
- return samples;
- }
- extern "C" __declspec (dllexport) In_Module * winampGetInModule2()
- {
- return &mod;
- }
- // This code provides an interface between the reader callback mechanism that
- // WavPack uses internally and the standard fstream C library.
- static int32_t read_bytes(void *id, void *data, int32_t bcount)
- {
- FILE *file = id ? *(FILE**)id : NULL;
- if (file)
- return (int32_t) fread(data, 1, bcount, file);
- else
- return 0;
- }
- static uint32_t get_pos(void *id)
- {
- FILE *file = id ? *(FILE**)id : NULL;
- if (file)
- return ftell(file);
- else
- return -1;
- }
- static int set_pos_abs(void *id, uint32_t pos)
- {
- FILE *file = id ? *(FILE**)id : NULL;
- if (file)
- return fseek(file, pos, SEEK_SET);
- else
- return 0;
- }
- static int set_pos_rel(void *id, int32_t delta, int mode)
- {
- FILE *file = id ? *(FILE**)id : NULL;
- if (file)
- return fseek(file, delta, mode);
- else
- return -1;
- }
- static int push_back_byte(void *id, int c)
- {
- FILE *file = id ? *(FILE**)id : NULL;
- if (file)
- return ungetc(c, file);
- else
- return EOF;
- }
- static uint32_t get_length(void *id)
- {
- FILE *file = id ? *(FILE**)id : NULL;
- struct stat statbuf;
- if (!file || fstat (fileno (file), &statbuf) || !(statbuf.st_mode & S_IFREG))
- return 0;
- else
- return statbuf.st_size;
- }
- static int can_seek(void *id)
- {
- FILE *file = id ? *(FILE**)id : NULL;
- struct stat statbuf;
- return file && !fstat (fileno (file), &statbuf) && (statbuf.st_mode & S_IFREG);
- }
- static int32_t write_bytes(void *id, void *data, int32_t bcount)
- {
- FILE *file = id ? *(FILE**)id : NULL;
- if (file)
- return (int32_t) fwrite (data, 1, bcount, file);
- else
- return 0;
- }
- static WavpackStreamReader freader = {
- read_bytes, get_pos, set_pos_abs,
- set_pos_rel, push_back_byte,
- get_length, can_seek, write_bytes
- };
- /* These functions provide UNICODE support for the winamp media library */
- static int metadata_we_can_write(const char *metadata);
- static void close_context(struct wpcnxt *cxt)
- {
- if (cxt->wpc)
- WavpackCloseFile(cxt->wpc);
- if (cxt->wv_id)
- fclose(cxt->wv_id);
- if (cxt->wvc_id)
- fclose(cxt->wvc_id);
- memset(cxt, 0, sizeof (*cxt));
- }
- #ifdef ANSI_METADATA
- extern "C" __declspec (dllexport) int winampGetExtendedFileInfo(char *filename, char *metadata, char *ret, int retlen)
- {
- int open_flags = OPEN_TAGS;
- char error[128];
- int retval = 0;
- #ifdef DEBUG_CONSOLE
- sprintf (error, "winampGetExtendedFileInfo (%s)\n", metadata);
- debug_write (error);
- #endif
- if (!_stricmp(metadata, "type"))
- {
- ret[0] = '0';
- ret[1] = 0;
- return 1;
- }
- else if (!_stricmp(metadata, "family"))
- {
- int len;
- const char *p;
- if (!filename || !filename[0]) return 0;
- len = lstrlen(filename);
- if (len < 3 || '.' != filename[len - 3]) return 0;
- p = &filename[len - 2];
- if (!_stricmp(p, "wv")) { WASABI_API_LNGSTRING_BUF(IDS_FAMILY_STRING, ret, retlen); return 1; }
- return 0;
- }
- if (!filename || !*filename)
- return retval;
- if (!_stricmp(metadata, "length")) { /* even if no file, return a 1 and write "0" */
- StringCchPrintf(ret, retlen, "%d", 0);
- retval = 1;
- }
- if (!info.wpc || strcmp(filename, info.lastfn) || !_stricmp(metadata, "formatinformation"))
- {
- close_context(&info);
- if (!(info.wv_id = fopen(filename, "rb")))
- return retval;
- if (config_bits & ALLOW_WVC)
- {
- int length = strlen(filename) + 10;
- char *wvc_name = (char *)malloc(length);
- if (wvc_name)
- {
- lstrcpyn(wvc_name, filename, length);
- StringCchCat(wvc_name, length, "c");
- info.wvc_id = fopen(wvc_name, "rb");
- free(wvc_name);
- }
- }
- info.wpc = WavpackOpenFileInputEx(&freader, &info.wv_id, info.wvc_id ? &info.wvc_id : NULL, error, open_flags, 0);
- if (!info.wpc)
- {
- close_context(&info);
- return retval;
- }
- lstrcpyn(info.lastfn, filename, MAX_PATH);
- info.w_lastfn [0] = 0;
- }
- if (!_stricmp(metadata, "formatinformation"))
- {
- wchar_t *temp = (wchar_t *)malloc(retlen * sizeof(wchar_t));
- generate_format_string(info.wpc, temp, retlen, 0);
- lstrcpyn(ret, AutoChar(temp), retlen);
- free(temp);
- retval = 1;
- }
- else if (!_stricmp(metadata, "length"))
- {
- StringCchPrintf(ret, retlen, "%d", (int)(WavpackGetNumSamples(info.wpc) * 1000.0 / WavpackGetSampleRate(info.wpc)));
- retval = 1;
- }
- else if (!_stricmp(metadata, "lossless"))
- {
- StringCchPrintf (ret, retlen, "%d", (WavpackGetMode(info.wpc) & MODE_LOSSLESS) ? 1 : 0);
- retval = 1;
- }
- else if (!_stricmp(metadata, "numsamples"))
- {
- StringCchPrintf(ret, retlen, "%d", WavpackGetNumSamples(info.wpc));
- retval = 1;
- }
- else if (!_stricmp(metadata, "mime"))
- {
- lstrcpyn(ret, L"audio/x-wavpack", retlen);
- retval = 1;
- }
- else if (!_stricmp(metadata, "gain"))
- {
- StringCchPrintf(ret, retlen, "%-+.2f dB", calculate_gain(info.wpc, false));
- retval = 1;
- }
- else if (WavpackGetTagItem(info.wpc, metadata, ret, retlen))
- {
- if (!_stricmp(metadata, "rating"))
- {
- int rating = atoi(ret);
- // appears to be generally 0-5 or 0-100
- if (rating > 10) {
- rating /= 20;
- }
- // or maybe we're dealing with a 1-10 range
- else if (rating > 5) {
- rating /= 2;
- }
- // otherwise it is hopefully in the 0-5 range
- StringCchPrintf(ret, retlen, "%u", rating);
- }
- else
- {
- if (WavpackGetMode(info.wpc) & MODE_APETAG)
- {
- UTF8ToAnsi(ret, retlen);
- }
- }
- retval = 1;
- }
- else if (metadata_we_can_write(metadata))
- {
- if (retlen)
- *ret = 0;
- retval = 1;
- }
- // This is a little ugly, but since the WavPack library has read the tags off the
- // files, we can close the files (but not the WavPack context) now so that we don't
- // leave handles open. We may access the file again for the "formatinformation"
- // field, so we reopen the file if we get that one.
- if (info.wv_id)
- {
- fclose(info.wv_id);
- info.wv_id = NULL;
- }
- if (info.wvc_id)
- {
- fclose(info.wvc_id);
- info.wvc_id = NULL;
- }
- return retval;
- }
- #endif
- #ifdef UNICODE_METADATA
- extern "C" __declspec (dllexport) int winampGetExtendedFileInfoW (wchar_t *filename, char *metadata, wchar_t *ret, int retlen)
- {
- char error[128], res[256];
- int open_flags = OPEN_TAGS;
- int retval = 0;
- #ifdef DEBUG_CONSOLE
- sprintf (error, "winampGetExtendedFileInfoW (%s)\n", metadata);
- debug_write (error);
- #endif
- if (!_stricmp(metadata, "type"))
- {
- ret[0] = '0';
- ret[1] = 0;
- return 1;
- }
- else if (!_stricmp(metadata, "family"))
- {
- int len;
- const wchar_t *p;
- if (!filename || !filename[0]) return 0;
- len = lstrlenW(filename);
- if (len < 3 || L'.' != filename[len - 3]) return 0;
- p = &filename[len - 2];
- if (!_wcsicmp(p, L"wv")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING, ret, retlen); return 1; }
- return 0;
- }
- if (!filename || !*filename)
- return retval;
- if (!_stricmp(metadata, "length")) /* even if no file, return a 1 and write "0" */
- {
- StringCchPrintfW(ret, retlen, L"%d", 0);
- retval = 1;
- }
- if (!info.wpc || wcscmp(filename, info.w_lastfn) || !_stricmp(metadata, "formatinformation"))
- {
- close_context(&info);
- if (!(info.wv_id = _wfopen(filename, L"rb")))
- return retval;
- if (config_bits & ALLOW_WVC) {
- int length = wcslen(filename) + 10;
- wchar_t *wvc_name = (wchar_t *)malloc(length * sizeof(wchar_t));
- if (wvc_name) {
- lstrcpynW(wvc_name, filename, length);
- StringCchCatW(wvc_name, length, L"c");
- info.wvc_id = _wfopen(wvc_name, L"rb");
- free(wvc_name);
- }
- }
- info.wpc = WavpackOpenFileInputEx(&freader, &info.wv_id, info.wvc_id ? &info.wvc_id : NULL, error, open_flags, 0);
- if (!info.wpc)
- {
- close_context(&info);
- return retval;
- }
- lstrcpynW(info.w_lastfn, filename, MAX_PATH);
- info.lastfn[0] = 0;
- }
- if (!_stricmp(metadata, "formatinformation"))
- {
- generate_format_string(info.wpc, ret, retlen, 0);
- retval = 1;
- }
- else if (!_stricmp (metadata, "length"))
- {
- StringCchPrintfW(ret, retlen, L"%d", (int)(WavpackGetNumSamples(info.wpc) * 1000.0 / WavpackGetSampleRate(info.wpc)));
- retval = 1;
- }
- else if (!_stricmp(metadata, "lossless"))
- {
- StringCchPrintfW(ret, retlen, L"%d", (WavpackGetMode(info.wpc) & MODE_LOSSLESS) ? 1 : 0);
- retval = 1;
- }
- else if (!_stricmp(metadata, "gain"))
- {
- StringCchPrintfW(ret, retlen, L"%-+.2f dB", calculate_gain(info.wpc, false));
- retval = 1;
- }
- else if (!_stricmp(metadata, "numsamples"))
- {
- StringCchPrintfW(ret, retlen, L"%d", WavpackGetNumSamples(info.wpc));
- retval = 1;
- }
- else if (!_stricmp(metadata, "mime"))
- {
- lstrcpynW(ret, L"audio/x-wavpack", retlen);
- retval = 1;
- }
- else if (WavpackGetTagItem(info.wpc, metadata, res, sizeof (res)))
- {
- if (!_stricmp(metadata, "rating"))
- {
- int rating = atoi(res);
- // appears to be generally 0-5 or 0-100
- if (rating > 10) {
- rating /= 20;
- }
- // or maybe we're dealing with a 1-10 range
- else if (rating > 5) {
- rating /= 2;
- }
- // otherwise it is hopefully in the 0-5 range
- StringCchPrintfW(ret, retlen, L"%u", rating);
- }
- else
- {
- if (!(WavpackGetMode(info.wpc) & MODE_APETAG))
- lstrcpynW(ret, AutoWide(res), retlen);
- else
- lstrcpynW(ret, AutoWide(res, CP_UTF8), retlen);
- }
- retval = 1;
- }
- else if (metadata_we_can_write (metadata))
- {
- if (retlen)
- *ret = 0;
- retval = 1;
- }
- // This is a little ugly, but since the WavPack library has read the tags off the
- // files, we can close the files (but not the WavPack context) now so that we don't
- // leave handles open. We may access the file again for the "formatinformation"
- // field, so we reopen the file if we get that one.
- if (info.wv_id)
- {
- fclose (info.wv_id);
- info.wv_id = NULL;
- }
- if (info.wvc_id)
- {
- fclose (info.wvc_id);
- info.wvc_id = NULL;
- }
- return retval;
- }
- #endif
- #ifdef ANSI_METADATA
- extern "C" int __declspec (dllexport) winampSetExtendedFileInfo(const char *filename, const char *metadata, char *val)
- {
- char error[128];
- #ifdef DEBUG_CONSOLE
- sprintf (error, "winampSetExtendedFileInfo (%s=%s)\n", metadata, val);
- debug_write (error);
- #endif
- if (!filename || !*filename || !metadata_we_can_write(metadata))
- return 0;
- if (!edit.wpc || strcmp(filename, edit.lastfn))
- {
- if (edit.wpc)
- WavpackCloseFile(edit.wpc);
- edit.wpc = WavpackOpenFileInput(filename, error, OPEN_TAGS | OPEN_EDIT_TAGS, 0);
- if (!edit.wpc)
- return 0;
- lstrcpyn(edit.lastfn, filename, MAX_PATH);
- edit.w_lastfn [0] = 0;
- }
- if (strlen(val))
- return WavpackAppendTagItem(edit.wpc, metadata, val, strlen (val));
- else
- return WavpackDeleteTagItem(edit.wpc, metadata);
- }
- #endif
- #ifdef UNICODE_METADATA
- extern "C" int __declspec (dllexport) winampSetExtendedFileInfoW(const wchar_t *filename, const char *metadata, wchar_t *val)
- {
- char error[128], utf8_val[256];
- lstrcpyn(utf8_val,AutoChar(val, CP_UTF8),sizeof(utf8_val) - 1);
- #ifdef DEBUG_CONSOLE
- sprintf (error, "winampSetExtendedFileInfoW (%s=%s)\n", metadata, utf8_val);
- debug_write (error);
- #endif
- if (!filename || !*filename || !metadata_we_can_write(metadata))
- return 0;
- if (!edit.wpc || wcscmp(filename, edit.w_lastfn))
- {
- if (edit.wpc)
- {
- WavpackCloseFile(edit.wpc);
- edit.wpc = NULL;
- }
- if (edit.wv_id)
- fclose(edit.wv_id);
- if (!(edit.wv_id = _wfopen(filename, L"r+b")))
- return 0;
- edit.wpc = WavpackOpenFileInputEx(&freader, &edit.wv_id, NULL, error, OPEN_TAGS | OPEN_EDIT_TAGS, 0);
- if (!edit.wpc)
- {
- fclose(edit.wv_id);
- return 0;
- }
- lstrcpynW(edit.w_lastfn, filename, MAX_PATH);
- edit.lastfn [0] = 0;
- }
- if (strlen(utf8_val))
- return WavpackAppendTagItem(edit.wpc, metadata, utf8_val, strlen (utf8_val));
- else
- return WavpackDeleteTagItem(edit.wpc, metadata);
- }
- #endif
- extern "C" int __declspec (dllexport) winampWriteExtendedFileInfo(void)
- {
- #ifdef DEBUG_CONSOLE
- debug_write ("winampWriteExtendedFileInfo ()\n");
- #endif
- if (edit.wpc)
- {
- WavpackWriteTag(edit.wpc);
- WavpackCloseFile(edit.wpc);
- edit.wpc = NULL;
- }
- if (edit.wv_id)
- {
- fclose(edit.wv_id);
- edit.wv_id = NULL;
- }
- close_context(&info); // make sure we re-read info on any open files
- return 1;
- }
- // return 1 if you want winamp to show it's own file info dialogue, 0 if you want to show your own (via In_Module.InfoBox)
- // if returning 1, remember to implement winampGetExtendedFileInfo("formatinformation")!
- extern "C" __declspec(dllexport) int winampUseUnifiedFileInfoDlg(const wchar_t * fn)
- {
- return 1;
- }
- static const char *writable_metadata [] = {
- "track", "genre", "year", "comment", "artist",
- "album", "title", "albumartist", "composer",
- "publisher", "disc", "tool", "encoder", "bpm",
- "category", "rating",
- "replaygain_track_gain", "replaygain_track_peak",
- "replaygain_album_gain", "replaygain_album_peak"
- };
- #define NUM_KNOWN_METADATA (sizeof (writable_metadata) / sizeof (writable_metadata [0]))
- static int metadata_we_can_write(const char *metadata)
- {
- if (!metadata || !*metadata)
- return 0;
- for (int i = 0; i < NUM_KNOWN_METADATA; ++i)
- if (!_stricmp(metadata, writable_metadata[i]))
- return 1;
- return 0;
- }
- static void generate_format_string(WavpackContext *wpc, wchar_t *string, int maxlen, int wide)
- {
- int mode = WavpackGetMode(wpc);
- unsigned char md5_sum[16];
- wchar_t modes[256];
- wchar_t fmt[256];
- WASABI_API_LNGSTRINGW_BUF(IDS_ENCODER_VERSION, fmt, sizeof(fmt));
- StringCchPrintfW(string, maxlen, fmt, WavpackGetVersion(wpc));
- while (*string && string++ && maxlen--);
- WASABI_API_LNGSTRINGW_BUF(IDS_SOURCE, fmt, sizeof (fmt));
- StringCchPrintfW(string, maxlen, fmt, WavpackGetBitsPerSample(wpc),
- WASABI_API_LNGSTRINGW((WavpackGetMode(wpc) & MODE_FLOAT) ? IDS_FLOATS : IDS_INTS),
- WavpackGetSampleRate(wpc));
- while (*string && string++ && maxlen--);
- if (WavpackGetNumChannels(wpc) > 2)
- {
- WASABI_API_LNGSTRINGW_BUF(IDS_MULTICHANNEL, fmt, sizeof (fmt));
- StringCchPrintfW(string, maxlen, fmt, WavpackGetNumChannels(wpc));
- while (*string && string++ && maxlen--);
- }
- else if (WavpackGetNumChannels(wpc) == 2)
- {
- WASABI_API_LNGSTRINGW_BUF(IDS_STEREO, fmt, sizeof (fmt));
- StringCchPrintfW(string, maxlen, fmt);
- while (*string && string++ && maxlen--);
- }
- else
- {
- WASABI_API_LNGSTRINGW_BUF(IDS_MONO, fmt, sizeof (fmt));
- StringCchPrintfW(string, maxlen, fmt);
- while (*string && string++ && maxlen--);
- }
- modes [0] = 0;
- if (WavpackGetMode(wpc) & MODE_HYBRID)
- {
- StringCchCatW(modes, 256, WASABI_API_LNGSTRINGW(IDS_HYBRID));
- StringCchCatW(modes, 256, L" ");
- }
- StringCchCatW(modes, 256, WASABI_API_LNGSTRINGW((WavpackGetMode(wpc) & MODE_LOSSLESS) ? IDS_LOSSLESS : IDS_LOSSY));
- if (WavpackGetMode(wpc) & MODE_FAST)
- StringCchCatW(modes, 256, WASABI_API_LNGSTRINGW(IDS_FAST));
- else if (WavpackGetMode(wpc) & MODE_VERY_HIGH)
- StringCchCatW(modes, 256, WASABI_API_LNGSTRINGW(IDS_VHIGH));
- else if (WavpackGetMode(wpc) & MODE_HIGH)
- StringCchCatW(modes, 256, WASABI_API_LNGSTRINGW(IDS_HIGH));
- if (WavpackGetMode(wpc) & MODE_EXTRA)
- StringCchCatW(modes, 256, WASABI_API_LNGSTRINGW(IDS_EXTRA));
- StringCchPrintfW(string, maxlen, L"%s:%s %s\n",
- WASABI_API_LNGSTRINGW(IDS_MODES),
- (wide || lstrlenW(modes) < 24) ? L"" : L"\n", modes);
- while (*string && string++ && maxlen--);
- if (WavpackGetRatio(wpc) != 0.0)
- {
- wchar_t str_kbps[32];
- StringCchPrintfW(string, maxlen, L"%s: %d %s \n",
- WASABI_API_LNGSTRINGW(IDS_BITRATE),
- (int)((WavpackGetAverageBitrate(wpc, TRUE) + 500.0) / 1000.0),
- WASABI_API_LNGSTRINGW_BUF(IDS_KBPS, str_kbps, sizeof(str_kbps)));
- while (*string && string++ && maxlen--);
- StringCchPrintfW(string, maxlen, L"%s: %.2f : 1 \n",
- WASABI_API_LNGSTRINGW(IDS_RATIO), 1.0 / WavpackGetRatio(wpc));
- while (*string && string++ && maxlen--);
- }
- if (WavpackGetMD5Sum(wpc, md5_sum))
- {
- wchar_t md5s1 [17], md5s2 [17];
- int i;
- for (i = 0; i < 8; ++i)
- {
- StringCchPrintfW(md5s1 + i * 2, sizeof(md5s1), L"%02x", md5_sum [i]);
- StringCchPrintfW(md5s2 + i * 2, sizeof(md5s2), L"%02x", md5_sum [i+8]);
- }
- StringCchPrintfW(string, maxlen, (wide ? L"%s: %s%s\n" : L"%s:\n %s\n %s\n"),
- WASABI_API_LNGSTRINGW(IDS_MD5), md5s1, md5s2);
- }
- }
- ///////////////////// native "C" functions required for AlbumArt support ///////////////////////////
- #ifdef DEBUG_CONSOLE
- static char temp_buff [256];
- static char *wide2char (const wchar_t *src)
- {
- char *dst = temp_buff;
- while (*src)
- *dst++ = (char) *src++;
- *dst = 0;
- return temp_buff;
- }
- #endif
- int WavPack_HandlesExtension(const wchar_t *extension)
- {
- return !_wcsicmp(extension, L"wv");
- }
- int WavPack_GetAlbumArt(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mime_type)
- {
- char *buffer;
- char error[128];
- int tag_size, i;
- int retval = 1;
- #ifdef DEBUG_CONSOLE
- sprintf (error, "WavPack_GetAlbumArt (%s)\n", wide2char (type));
- debug_write (error);
- #endif
- if (!filename || !*filename || _wcsicmp(type, L"cover"))
- return retval;
- if (!info.wpc || wcscmp(filename, info.w_lastfn))
- {
- close_context(&info);
- if (!(info.wv_id = _wfopen(filename, L"rb")))
- return retval;
- if (config_bits & ALLOW_WVC)
- {
- int length = wcslen(filename) + 10;
- wchar_t *wvc_name = (wchar_t *)malloc(length * sizeof(wchar_t));
- if (wvc_name)
- {
- lstrcpynW(wvc_name, filename, length);
- StringCchCatW(wvc_name, length, L"c");
- info.wvc_id = _wfopen(wvc_name, L"rb");
- free(wvc_name);
- }
- }
- info.wpc = WavpackOpenFileInputEx(&freader, &info.wv_id, info.wvc_id ? &info.wvc_id : NULL, error, OPEN_TAGS, 0);
- if (!info.wpc)
- {
- close_context(&info);
- return retval;
- }
- lstrcpynW(info.w_lastfn, filename, MAX_PATH);
- info.lastfn[0] = 0;
- }
- tag_size = WavpackGetBinaryTagItem(info.wpc, "Cover Art (Front)", NULL, 0);
- if (!tag_size)
- return retval;
- buffer = (char*)WASABI_API_MEMMGR->sysMalloc(tag_size);
- WavpackGetBinaryTagItem(info.wpc, "Cover Art (Front)", buffer, tag_size);
- for (i = 0; i < tag_size - 1; ++i)
- if (!buffer[i] && strrchr(buffer, '.')) {
- char *ext = strrchr(buffer, '.') + 1;
- wchar_t *wcptr;
- wcptr = *mime_type = (wchar_t*)WASABI_API_MEMMGR->sysMalloc(strlen(ext) * 2 + 2);
- while (*ext)
- *wcptr++ = *ext++;
- *wcptr = 0;
- *bits = buffer;
- *len = tag_size - i - 1;
- memmove(buffer, buffer + i + 1, *len);
- retval = 0;
- #ifdef DEBUG_CONSOLE
- sprintf (error, "WavPack_GetAlbumArt (\"%s\", %d) success!\n", wide2char (*mime_type), *len);
- debug_write (error);
- #endif
- }
- if (retval)
- WASABI_API_MEMMGR->sysFree(buffer);
- // This is a little ugly, but since the WavPack library has read the tags off the
- // files, we can close the files (but not the WavPack context) now so that we don't
- // leave handles open. We may access the file again for the "formatinformation"
- // field, so we reopen the file if we get that one.
- if (info.wv_id)
- {
- fclose(info.wv_id);
- info.wv_id = NULL;
- }
- if (info.wvc_id)
- {
- fclose(info.wvc_id);
- info.wvc_id = NULL;
- }
- return retval;
- }
- int WavPack_SetAlbumArt(const wchar_t *filename, const wchar_t *type, void *bits, size_t len, const wchar_t *mime_type)
- {
- #if 1
- return 2; // return 2 to indicate "read-only" cover art for now
- #else
- char error [128], name [50], *cp;
- int tag_size, retval = 0;
- unsigned char *buffer;
- #ifdef DEBUG_CONSOLE
- sprintf (error, "WavPack_SetAlbumArt (%s)\n", wide2char (mime_type));
- debug_write (error);
- #endif
- if (!filename || !*filename || _wcsicmp (type, L"cover") || wcslen (mime_type) > 16)
- return 1;
- strcpy (name, "Cover Art (Front)");
- cp = name + strlen (name);
- *cp++ = '.';
- while (*mime_type)
- *cp++ = (char) *mime_type++;
- *cp = 0;
- tag_size = strlen (name) + 1 + len;
- buffer = malloc (tag_size);
- strcpy (buffer, name);
- memcpy (buffer + strlen (buffer) + 1, bits, len);
- if (!edit.wpc || wcscmp (filename, edit.w_lastfn)) {
- if (edit.wpc) {
- WavpackCloseFile (edit.wpc);
- edit.wpc = NULL;
- }
- if (edit.wv_id)
- fclose (edit.wv_id);
- if (!(edit.wv_id = _wfopen (filename, L"r+b"))) {
- free (buffer);
- return 1;
- }
- edit.wpc = WavpackOpenFileInputEx (&freader, &edit.wv_id, NULL, error, OPEN_TAGS | OPEN_EDIT_TAGS, 0);
- if (!edit.wpc) {
- fclose (edit.wv_id);
- free (buffer);
- return 1;
- }
- wcscpy (edit.w_lastfn, filename);
- edit.lastfn [0] = 0;
- }
- retval = WavpackAppendTagItem (edit.wpc, "Cover Art (Front)", buffer, tag_size);
- free (buffer);
- if (retval) {
- winampWriteExtendedFileInfo ();
- return 0;
- }
- else {
- close_context (&edit);
- return 1;
- }
- #endif
- }
- int WavPack_DeleteAlbumArt(const wchar_t *filename, const wchar_t *type)
- {
- #if 1
- return 2; // return 2 to indicate "read-only" cover art for now
- #else
- char error [128];
- #ifdef DEBUG_CONSOLE
- sprintf (error, "WavPack_DeleteAlbumArt ()\n");
- debug_write (error);
- #endif
- if (!filename || !*filename || _wcsicmp (type, L"cover"))
- return 0;
- if (!edit.wpc || wcscmp (filename, edit.w_lastfn)) {
- if (edit.wpc) {
- WavpackCloseFile (edit.wpc);
- edit.wpc = NULL;
- }
- if (edit.wv_id)
- fclose (edit.wv_id);
- if (!(edit.wv_id = _wfopen (filename, L"r+b")))
- return 1;
- edit.wpc = WavpackOpenFileInputEx (&freader, &edit.wv_id, NULL, error, OPEN_TAGS | OPEN_EDIT_TAGS, 0);
- if (!edit.wpc) {
- fclose (edit.wv_id);
- return 1;
- }
- wcscpy (edit.w_lastfn, filename);
- edit.lastfn [0] = 0;
- }
- if (WavpackDeleteTagItem (edit.wpc, "Cover Art (Front)")) {
- winampWriteExtendedFileInfo ();
- return 0;
- }
- else {
- close_context (&edit);
- return 1;
- }
- #endif
- }
- //////////////////////////////////////////////////////////////////////////////
- // This function uses the ReplayGain mode selected by the user and the info //
- // stored in the specified tag to determine the gain value used to play the //
- // file and whether "soft clipping" is required. Note that the gain is in //
- // voltage scaling (not dB), so a value of 1.0 (not 0.0) is unity gain. //
- //////////////////////////////////////////////////////////////////////////////
- static float calculate_gain(WavpackContext *wpc, bool allowDefault)
- {
- if (AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain", false))
- {
- float dB = 0, peak = 1.0f;
- char gain[128] = "", peakVal[128] = "";
- _locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale();
- switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_source", 0))
- {
- case 0: // track
- if ((!WavpackGetTagItem(wpc, "replaygain_track_gain", gain, sizeof(gain)) || !gain[0])
- && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
- WavpackGetTagItem(wpc, "replaygain_album_gain", gain, sizeof(gain));
- if ((!WavpackGetTagItem(wpc, "replaygain_track_peak", peakVal, sizeof(peakVal)) || !peakVal[0])
- && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
- WavpackGetTagItem(wpc, "replaygain_album_peak", peakVal, sizeof(peakVal));
- break;
- case 1:
- if ((!WavpackGetTagItem(wpc, "replaygain_album_gain", gain, sizeof(gain)) || !gain[0])
- && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
- WavpackGetTagItem(wpc, "replaygain_track_gain", gain, sizeof(gain));
- if ((!WavpackGetTagItem(wpc, "replaygain_album_peak", peakVal, sizeof(peakVal)) || !peakVal[0])
- && !AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"replaygain_preferred_only", false))
- WavpackGetTagItem(wpc, "replaygain_track_peak", peakVal, sizeof(peakVal));
- break;
- }
- if (gain[0])
- {
- if (gain[0] == L'+')
- dB = (float)_atof_l(&gain[1],C_locale);
- else
- dB = (float)_atof_l(gain,C_locale);
- }
- else if (allowDefault)
- {
- dB = AGAVE_API_CONFIG->GetFloat(playbackConfigGroupGUID, L"non_replaygain", -6.0);
- return powf(10.0f, dB / 20.0f);
- }
- if (peakVal[0])
- {
- peak = (float)_atof_l(peakVal,C_locale);
- }
- switch (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_mode", 1))
- {
- case 0: // apply gain
- return powf(10.0f, dB / 20.0f);
- case 1: // apply gain, but don't clip
- return min(powf(10.0f, dB / 20.0f), 1.0f / peak);
- case 2: // normalize
- return 1.0f / peak;
- case 3: // prevent clipping
- if (peak > 1.0f)
- return 1.0f / peak;
- else
- return 1.0f;
- }
- }
- return 1.0f; // no gain
- }
- // Convert a Ansi string into its Unicode UTF-8 format equivalent. The
- // conversion is done in-place so the maximum length of the string buffer must
- // be specified because the string may become longer or shorter. If the
- // resulting string will not fit in the specified buffer size then it is
- // truncated.
- #ifdef OLD_INFO_DIALOG
- static void AnsiToUTF8(char *string, int len)
- {
- int max_chars = (int) strlen(string);
- wchar_t *temp = (wchar_t *) malloc((max_chars + 1) * 2);
- MultiByteToWideChar(CP_ACP, 0, string, -1, temp, max_chars + 1);
- lstrcpyn(string, AutoChar(temp, CP_UTF8), len);
- free(temp);
- }
- #endif
- // Convert Unicode UTF-8 string to wide format. UTF-8 string must be NULL
- // terminated. Resulting wide string must be able to fit in provided space
- // and will also be NULL terminated. The number of characters converted will
- // be returned (not counting terminator).
- static int UTF8ToWideChar(const char *pUTF8, wchar_t *pWide)
- {
- int trail_bytes = 0;
- int chrcnt = 0;
- while (*pUTF8)
- {
- if (*pUTF8 & 0x80)
- {
- if (*pUTF8 & 0x40)
- {
- if (trail_bytes)
- {
- trail_bytes = 0;
- chrcnt++;
- }
- else
- {
- char temp = *pUTF8;
- while (temp & 0x80)
- {
- trail_bytes++;
- temp <<= 1;
- }
- pWide [chrcnt] = temp >> trail_bytes--;
- }
- }
- else if (trail_bytes)
- {
- pWide [chrcnt] = (pWide [chrcnt] << 6) | (*pUTF8 & 0x3f);
- if (!--trail_bytes)
- chrcnt++;
- }
- }
- else
- pWide [chrcnt++] = *pUTF8;
- pUTF8++;
- }
- pWide [chrcnt] = 0;
- return chrcnt;
- }
- // Convert a Unicode UTF-8 format string into its Ansi equivalent. The
- // conversion is done in-place so the maximum length of the string buffer must
- // be specified because the string may become longer or shorter. If the
- // resulting string will not fit in the specified buffer size then it is
- // truncated.
- static void UTF8ToAnsi(char *string, int len)
- {
- int max_chars = (int)strlen(string);
- wchar_t *temp = (wchar_t *)malloc((max_chars + 1) * 2);
- int act_chars = UTF8ToWideChar(string, temp);
- while (act_chars)
- {
- memset (string, 0, len);
- if (WideCharToMultiByte(CP_ACP, 0, temp, act_chars, string, len - 1, NULL, NULL))
- break;
- else
- act_chars--;
- }
- if (!act_chars)
- *string = 0;
- free (temp);
- }
- extern "C" __declspec(dllexport) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
- {
- // as we're not hooking anything and have no settings we can support an on-the-fly uninstall action
- return IN_PLUGIN_UNINSTALL_NOW;
- }
|