aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_wave/main.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Input/in_wave/main.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Input/in_wave/main.cpp')
-rw-r--r--Src/Plugins/Input/in_wave/main.cpp437
1 files changed, 437 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_wave/main.cpp b/Src/Plugins/Input/in_wave/main.cpp
new file mode 100644
index 00000000..235f1616
--- /dev/null
+++ b/Src/Plugins/Input/in_wave/main.cpp
@@ -0,0 +1,437 @@
+//#define PLUGIN_NAME "Nullsoft Waveform Decoder"
+#define PLUGIN_VERSION L"3.27"
+
+#include "../Winamp/in2.h"
+#include "../Winamp/wa_ipc.h"
+#include "main.h"
+#include "AudioThread.h"
+#include "resource.h"
+#include "config.h"
+#include "api__in_wave.h"
+#include <shlwapi.h>
+#include "../Agave/Language/api_language.h"
+#include <api/service/waservicefactory.h>
+#include "../nu/ns_wc.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoCharFn.h"
+#include "VirtualIO.h"
+#include <strsafe.h>
+#include "../nu/Singleton.h"
+#include "RawReader.h"
+
+api_config *AGAVE_API_CONFIG = NULL;
+
+// wasabi based services for localisation support
+api_language *WASABI_API_LNG = NULL;
+
+HINSTANCE WASABI_API_LNG_HINST = 0;
+HINSTANCE WASABI_API_ORIG_HINST = 0;
+
+static RawMediaReaderService raw_media_reader_service;
+static SingletonServiceFactory<svc_raw_media_reader, RawMediaReaderService> raw_factory;
+
+template <class api_T>
+void ServiceBuild( api_T *&api_t, GUID factoryGUID_t )
+{
+ if ( WASABI_API_SVC )
+ {
+ waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid( factoryGUID_t );
+ if ( factory )
+ api_t = reinterpret_cast<api_T *>( factory->getInterface() );
+ }
+}
+
+template <class api_T>
+void ServiceRelease( api_T *api_t, GUID factoryGUID_t )
+{
+ if ( WASABI_API_SVC && api_t )
+ {
+ waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid( factoryGUID_t );
+ if ( factory )
+ factory->releaseInterface( api_t );
+ }
+
+ api_t = NULL;
+}
+
+volatile int currentSongLength = 0;
+SNDFILE *sndFile = NULL;
+
+wchar_t curFile[MAX_PATH*4] = L"";
+
+char *INI_FILE;
+
+class SoundFile
+{
+public:
+ SoundFile( const wchar_t *filename, int mode, SF_INFO *info )
+ {
+ info->format = 0;
+ //reader = CreateUnicodeReader(filename);
+ //if (reader)
+ //sndFile = sf_open_virtual(&unicode_io, SFM_READ, info, reader);
+ sndFile = sf_wchar_open( filename, SFM_READ, info );
+ }
+ ~SoundFile()
+ {
+ if ( sndFile )
+ sf_close( sndFile );
+ //if (reader)
+ //DestroyUnicodeReader(reader);
+ sndFile = NULL;
+ }
+
+ operator SNDFILE *() { return sndFile; }
+ SNDFILE *operator ->() { return sndFile; }
+ operator bool() { return !!sndFile; }
+ bool operator !() { return !sndFile; }
+
+ SNDFILE *sndFile = NULL;
+ //void *reader;
+};
+
+void Config( HWND hwnd )
+{
+ WASABI_API_DIALOGBOXW( IDD_CONFIG, hwnd, PreferencesDialogProc );
+}
+
+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 message[ 1024 ] = { 0 }, text[ 1024 ] = { 0 };
+ char ver[ 128 ] = { 0 };
+
+ sf_command( 0, SFC_GET_LIB_VERSION, ver, 128 );
+
+ WASABI_API_LNGSTRINGW_BUF( IDS_NULLSOFT_WAVEFORM_DECODER_OLD, text, 1024 );
+
+ StringCchPrintfW( message, 1024, WASABI_API_LNGSTRINGW( IDS_ABOUT_TEXT ), plugin.description, __DATE__, ver );
+
+ DoAboutMessageBox( hwndParent, text, message );
+}
+
+int Init()
+{
+ if ( !IsWindow( plugin.hMainWindow ) )
+ return IN_INIT_FAILURE;
+
+ ServiceBuild( AGAVE_API_CONFIG, AgaveConfigGUID );
+
+ // loader so that we can get the localisation service api for use
+ ServiceBuild( WASABI_API_LNG, languageApiGUID );
+ raw_factory.Register( WASABI_API_SVC, &raw_media_reader_service );
+
+ // need to have this initialised before we try to do anything with localisation features
+ WASABI_API_START_LANG( plugin.hDllInstance, InWavLangGUID );
+
+ static wchar_t szDescription[ 256 ];
+ StringCchPrintfW( szDescription, 256, WASABI_API_LNGSTRINGW( IDS_NULLSOFT_WAVEFORM_DECODER ), PLUGIN_VERSION );
+ plugin.description = (char *)szDescription;
+
+ INI_FILE = (char *)SendMessage( plugin.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE );
+ BuildDefaultExtensions();
+
+ GetPrivateProfileStringA( "in_wave", "extensions", defaultExtensions, config_extensions, 1024, INI_FILE );
+ SetFileExtensions( config_extensions );
+
+ return IN_INIT_SUCCESS;
+}
+
+void Quit()
+{
+ if ( lstrcmpiA( config_extensions, defaultExtensions ) )
+ WritePrivateProfileStringA( "in_wave", "extensions", config_extensions, INI_FILE );
+ else
+ WritePrivateProfileStringA( "in_wave", "extensions", 0, INI_FILE );
+
+ ServiceRelease( AGAVE_API_CONFIG, AgaveConfigGUID );
+ WASABI_API_SVC->service_deregister( &raw_factory );
+}
+
+void GetFileInfo( const wchar_t *file, wchar_t *title, int *length_in_ms )
+{
+ SNDFILE *tempSndFile = 0;
+ SF_INFO info;
+ info.format = 0;
+ const wchar_t *fn = ( file && file[ 0 ] ) ? file : curFile;
+
+ tempSndFile = sf_wchar_open( fn, SFM_READ, &info );
+ if ( tempSndFile )
+ {
+ if ( length_in_ms )
+ {
+ *length_in_ms = MulDiv( (int)info.frames, 1000, info.samplerate ); // TODO: is this correct?
+ if ( !file || !file[ 0 ] )
+ currentSongLength = *length_in_ms;
+ }
+
+ if ( title )
+ {
+ const char *meta = sf_get_string( tempSndFile, SF_STR_TITLE );
+ if ( meta && meta[ 0 ] )
+ MultiByteToWideCharSZ( CP_UTF8, 0, meta, -1, title, GETFILEINFO_TITLE_LENGTH );
+ else
+ {
+ lstrcpynW( title, fn, GETFILEINFO_TITLE_LENGTH );
+ PathStripPathW( title );
+ }
+ }
+
+ sf_close( tempSndFile );
+ }
+ else
+ {
+ *length_in_ms = -1;
+ if ( title )
+ {
+ lstrcpynW( title, fn, GETFILEINFO_TITLE_LENGTH );
+ PathStripPathW( title );
+ }
+ }
+}
+
+int InfoBox( const wchar_t *file, HWND hwndParent )
+{
+ SNDFILE *metaFile = 0;
+ SF_INFO info;
+ info.format = 0;
+ metaFile = sf_wchar_open( file, SFM_READ, &info );
+ if ( metaFile )
+ {
+ SF_FORMAT_INFO formatInfo;
+ formatInfo.format = info.format & SF_FORMAT_SUBMASK;
+ sf_command( 0, SFC_GET_FORMAT_INFO, &formatInfo, sizeof( formatInfo ) );
+
+ char temp[ 1024 ] = { 0 };
+ StringCchPrintfA( temp, 1024, WASABI_API_LNGSTRING( IDS_INFO_STR_FMT ), formatInfo.name, info.channels, info.samplerate );
+ MessageBoxA( NULL, temp, WASABI_API_LNGSTRING( IDS_FILE_INFORMATION ), MB_OK );
+ sf_close( metaFile );
+ }
+
+ return INFOBOX_UNCHANGED;
+}
+
+int IsOurFile( const wchar_t *file )
+{
+ return 0;
+}
+
+int Play( const wchar_t *file )
+{
+ AudioThreadInit();
+ lstrcpynW( curFile, file, MAX_PATH * 4 );
+ QueueUserAPC( APCStart, audioThread, (ULONG_PTR)curFile );
+
+ return 0;
+}
+
+static int paused = 0;
+
+void Pause()
+{
+ paused = 1;
+ QueueUserAPC( APCPause, audioThread, (ULONG_PTR)1 );
+}
+
+void UnPause()
+{
+ paused = 0;
+ QueueUserAPC( APCPause, audioThread, (ULONG_PTR)0 );
+}
+
+int IsPaused()
+{
+ return paused;
+}
+
+void Stop()
+{
+ QueueUserAPC( APCStop, audioThread, (ULONG_PTR)0 );
+
+ WaitForSingleObject( stopped, INFINITE );
+
+ plugin.outMod->Close();
+ plugin.SAVSADeInit();
+
+ Kill();
+
+ WaitForSingleObject( audioThread, INFINITE );
+
+ AudioThreadQuit();
+}
+
+int GetLength()
+{
+ return currentSongLength;
+}
+
+int GetOutputTime()
+{
+ if ( plugin.outMod )
+ return plugin.outMod->GetOutputTime();
+ else
+ return 0;
+}
+
+void SetOutputTime( int time_in_ms )
+{
+ QueueUserAPC( APCSeek, audioThread, (ULONG_PTR)time_in_ms );
+}
+
+int pan = 0;
+int volume = -666;
+
+void SetVolume( int _volume )
+{
+ volume = _volume;
+ if ( plugin.outMod )
+ plugin.outMod->SetVolume( volume );
+}
+
+void SetPan( int _pan )
+{
+ pan = _pan;
+ if ( plugin.outMod )
+ plugin.outMod->SetPan( pan );
+}
+
+void EQSet( int on, char data[ 10 ], int preamp )
+{}
+
+In_Module plugin = {
+ IN_VER_RET,
+ "nullsoft(in_wave.dll)",
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ Config,
+ About,
+ Init,
+ Quit,
+ GetFileInfo,
+ InfoBox,
+ IsOurFile,
+ Play,
+ Pause,
+ UnPause,
+ IsPaused,
+ Stop,
+ GetLength,
+ GetOutputTime,
+ SetOutputTime,
+ SetVolume,
+ SetPan,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ EQSet,
+ 0,
+ 0
+};
+
+extern "C" __declspec( dllexport ) In_Module * winampGetInModule2()
+{
+ return &plugin;
+}
+
+inline bool KeywordMatch(const char *mainString, const char *keyword)
+{
+ return !lstrcmpiA(mainString, keyword);
+}
+
+extern "C" __declspec( dllexport ) int winampGetExtendedFileInfoW( const wchar_t *fn, const char *data, wchar_t *dest, int destlen )
+{
+ if ( KeywordMatch( data, "type" ) )
+ {
+ StringCchCopyW( dest, destlen, L"0" );
+
+ return 1;
+ }
+
+ if ( KeywordMatch( data, "family" ) )
+ {
+ LPCWSTR ext = PathFindExtensionW( fn );
+ if ( L'.' != *ext )
+ return 0;
+
+ return GetExtensionName( ++ext, dest, destlen );
+ }
+
+ if ( KeywordMatch( data, "mime" ) )
+ {
+ LPCWSTR ext = PathFindExtensionW( fn );
+ if ( ext && !_wcsicmp( ext, L".wav" ) )
+ {
+ StringCchCopyW( dest, destlen, L"audio/wav" );
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if ( !fn || ( fn && !fn[ 0 ] ) )
+ return 0;
+
+ SF_INFO info;
+ SoundFile metaFile( fn, SFM_READ, &info );
+ if ( !metaFile )
+ return 0;
+
+ dest[ 0 ] = 0;
+ if ( KeywordMatch( data, "artist" ) )
+ {
+ const char *meta = sf_get_string( metaFile, SF_STR_ARTIST );
+ if ( meta )
+ lstrcpynW( dest, AutoWide( meta ), destlen );
+ }
+ else if ( KeywordMatch( data, "title" ) )
+ {
+ const char *meta = sf_get_string( metaFile, SF_STR_TITLE );
+ if ( meta )
+ lstrcpynW( dest, AutoWide( meta ), destlen );
+ }
+ else if ( KeywordMatch( data, "comment" ) )
+ {
+ const char *meta = sf_get_string( metaFile, SF_STR_COMMENT );
+ if ( meta )
+ lstrcpynW( dest, AutoWide( meta ), destlen );
+ }
+ else if ( KeywordMatch( data, "bitrate" ) )
+ {
+ int br = CalcBitRate( &info );
+ if ( br )
+ StringCchPrintfW( dest, destlen, L"%d", br );
+ }
+ else if ( KeywordMatch( data, "length" ) )
+ {
+ uint64_t length = info.frames * 1000 / info.samplerate;
+ StringCchPrintfW( dest, destlen, L"%I64u", length );
+ }
+ else
+ return 0;
+
+ return 1;
+}