diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Input/in_wave | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Input/in_wave')
-rw-r--r-- | Src/Plugins/Input/in_wave/AudioThread.cpp | 330 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/AudioThread.h | 19 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/ExtendedRead.cpp | 80 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/RawReader.cpp | 86 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/RawReader.h | 39 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/VirtualIO.cpp | 98 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/VirtualIO.h | 10 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/api__in_wave.h | 10 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/config.cpp | 128 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/config.h | 6 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/extensions.cpp | 183 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/in_wave.rc | 144 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/in_wave.sln | 40 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/in_wave.vcxproj | 282 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/in_wave.vcxproj.filters | 65 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/main.cpp | 437 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/main.h | 24 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/resource.h | 47 | ||||
-rw-r--r-- | Src/Plugins/Input/in_wave/version.rc2 | 39 |
19 files changed, 2067 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_wave/AudioThread.cpp b/Src/Plugins/Input/in_wave/AudioThread.cpp new file mode 100644 index 00000000..b6e8676c --- /dev/null +++ b/Src/Plugins/Input/in_wave/AudioThread.cpp @@ -0,0 +1,330 @@ +#include <windows.h> +#include "main.h" +#include "../Winamp/wa_ipc.h" +#include "config.h" +#include "api__in_wave.h" +#include <shlwapi.h> +#include "VirtualIO.h" + +// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F} +static const GUID playbackConfigGroupGUID = + { 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } }; + +HANDLE audioThread = INVALID_HANDLE_VALUE; +DWORD WINAPI ThreadProcedure( void *data ); + +#define kill events[0] +#define running events[1] + +HANDLE stopped = 0; +HANDLE events[ 2 ] = { 0 }; + +static size_t bufferSize = 0; +static char *audioBuffer = 0; +static int frameSize = 0; // in bytes +static int endOfFile = 0; +static int bits = 0; +static SF_INFO info; +static void *reader = 0; + + +int CalcBits() +{ + switch (info.format & SF_FORMAT_SUBMASK) + { + case SF_FORMAT_DOUBLE: + return 64; + + case SF_FORMAT_PCM_32: + case SF_FORMAT_FLOAT: + return 32; + + case SF_FORMAT_DWVW_24: + case SF_FORMAT_PCM_24: + return 24; + + case SF_FORMAT_DPCM_16: + case SF_FORMAT_DWVW_16: + case SF_FORMAT_PCM_16: + return 16; + + //case SF_FORMAT_PCM_S8: // cut, because 8bits is assumed unsigned + case SF_FORMAT_PCM_U8: + case SF_FORMAT_DPCM_8: + return 8; + + default: return 16; + } +} + +int CalcBitRate( const SF_INFO *info ) +{ + switch ( info->format & SF_FORMAT_SUBMASK ) + { + case SF_FORMAT_PCM_S8: + case SF_FORMAT_PCM_U8: + case SF_FORMAT_DPCM_8: + return MulDiv( 8 * info->channels, info->samplerate, 1000 ); + case SF_FORMAT_DWVW_12: + return MulDiv( 12 * info->channels, info->samplerate, 1000 ); + case SF_FORMAT_DPCM_16: + case SF_FORMAT_DWVW_16: + case SF_FORMAT_PCM_16: + return MulDiv( 16 * info->channels, info->samplerate, 1000 ); + case SF_FORMAT_DWVW_24: + case SF_FORMAT_PCM_24: + return MulDiv( 24 * info->channels, info->samplerate, 1000 ); + case SF_FORMAT_PCM_32: + case SF_FORMAT_FLOAT: + return MulDiv( 32 * info->channels, info->samplerate, 1000 ); + case SF_FORMAT_DOUBLE: + return MulDiv( 64 * info->channels, info->samplerate, 1000 ); + + case SF_FORMAT_G721_32: + return 32; + + case SF_FORMAT_G723_24: + return 24; + + case SF_FORMAT_G723_40: + return 40; + case SF_FORMAT_MS_ADPCM: + case SF_FORMAT_VOX_ADPCM: + case SF_FORMAT_IMA_ADPCM: + return MulDiv( 4 * info->channels, info->samplerate, 1000 ); + default: + return MulDiv( 16 * info->channels, info->samplerate, 1000 ); + } +} + + +void CALLBACK APCSeek( ULONG_PTR p_data ) +{ + endOfFile = 0; + + int time_in_ms = (int)p_data; + int frames = MulDiv( time_in_ms, info.samplerate, 1000 ); // TODO: verify calculation + + sf_seek( sndFile, frames, SEEK_SET ); + + plugin.outMod->Flush( time_in_ms ); +} + +void CALLBACK APCPause( ULONG_PTR p_data ) +{ + int pause = (int)p_data; + if ( pause ) + ResetEvent( running ); + else + SetEvent( running ); + + plugin.outMod->Pause( !!pause ); +} + +void CALLBACK APCStart( ULONG_PTR p_data ) +{ + endOfFile = 0; + const wchar_t *file = (const wchar_t *)p_data; + + info.format = 0; + if ( PathIsURLW( file ) ) + { + reader = CreateReader( file ); + if ( reader ) + sndFile = sf_open_virtual( &httpIO, SFM_READ, &info, reader ); + } + else // It's a local file + { + sndFile = sf_wchar_open( file, SFM_READ, &info ); + } + + if ( !sndFile ) + { + if ( WaitForSingleObject( kill, 200 ) == WAIT_TIMEOUT ) + PostMessage( plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0 ); + + return; + } + + currentSongLength = MulDiv( (int)info.frames, 1000, info.samplerate ); // TODO: is this correct? + switch ( info.format & SF_FORMAT_SUBMASK ) + { + case SF_FORMAT_FLOAT: + case SF_FORMAT_DOUBLE: + sf_command( sndFile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE ); + break; + } + + bits = CalcBits(); + + size_t config_bits = AGAVE_API_CONFIG->GetUnsigned( playbackConfigGroupGUID, L"bits", 16 ); + if ( config_bits == 16 && config_bits < (size_t)bits ) + bits = (int)config_bits; + + if ( bits < 16 && config_upsample8bit ) + bits = 16; + + int latency = plugin.outMod->Open( info.samplerate, info.channels, bits, -1, -1 ); + if ( latency < 0 ) + { + sf_close( sndFile ); + if ( reader ) + DestroyReader( reader ); + + reader = 0; + sndFile = NULL; + + if ( WaitForSingleObject( kill, 200 ) == WAIT_TIMEOUT ) + PostMessage( plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0 ); + + return; + } + + frameSize = ( bits / 8 ) * info.channels; + + plugin.SAVSAInit( latency, info.samplerate ); + plugin.VSASetInfo( info.samplerate, info.channels ); + + int bitrate = CalcBitRate( &info ); + + plugin.SetInfo( bitrate, info.samplerate / 1000, info.channels, 1 ); + plugin.is_seekable = info.seekable; + + plugin.outMod->SetVolume( volume ); + plugin.outMod->SetPan( pan ); + + size_t requiredBufferSize = 576 * frameSize * 2; // * 2 for dsp bullshit + if ( requiredBufferSize > bufferSize ) + { + free( audioBuffer ); + + audioBuffer = (char *)calloc( requiredBufferSize, sizeof( char ) ); + bufferSize = requiredBufferSize; + } + + SetEvent( running ); +} + +void CALLBACK APCStop( ULONG_PTR p_data ) +{ + if ( sndFile ) + { + sf_close( sndFile ); + if ( reader ) + DestroyReader( reader ); + + reader = 0; + sndFile = NULL; + + } + + ResetEvent( running ); + SetEvent( stopped ); +} + + +void Kill() +{ + SetEvent( kill ); +} + +void AudioThreadInit() +{ + DWORD id; + + kill = CreateEvent( NULL, TRUE, FALSE, NULL ); + running = CreateEvent( NULL, TRUE, FALSE, NULL ); + stopped = CreateEvent( NULL, FALSE, FALSE, NULL ); + audioThread = CreateThread( NULL, 0, ThreadProcedure, 0, 0, &id ); + + if ( audioThread ) + SetThreadPriority( audioThread, (int)AGAVE_API_CONFIG->GetInt( playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST ) ); +} + +void AudioThreadQuit() +{ + free( audioBuffer ); + audioBuffer = 0; + + bufferSize = 0; + + CloseHandle( running ); + running = 0; + + CloseHandle( kill ); + kill = 0; + + CloseHandle( stopped ); + stopped = 0; + + CloseHandle( audioThread ); + audioThread = 0; +} + + +DWORD WINAPI ThreadProcedure( void *data ) +{ + DWORD result; + sf_count_t framesRead; + while ( true ) + { + result = WaitForMultipleObjectsEx( 2, events, FALSE, INFINITE, TRUE ); + if ( result == WAIT_OBJECT_0 ) // kill thread + return 0; + + if ( result == ( WAIT_OBJECT_0 + 1 ) ) + { + if ( endOfFile ) // if we hit the end of file previously ... + { + if ( plugin.outMod->IsPlaying() ) // see if we're still going + SleepEx( 10, TRUE ); // sleep for a bit + else // yay done playing + { + PostMessage( plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0 ); // tell winamp we're stopped + // don't shut down completely yet (mpegeof will trigger a call to stop) + ResetEvent( running ); // but we can at least sit in waitformultipleobjects ... + } + } + else if ( plugin.outMod->CanWrite() > ( 576 * frameSize ) ) + { + switch ( bits ) + { + case 16: + framesRead = sf_readf_short( sndFile, (short *)audioBuffer, 576 ); + break; + case 32: + framesRead = sf_readf_int( sndFile, (int *)audioBuffer, 576 ); + break; + default: + framesRead = sf_read_raw( sndFile, (int *)audioBuffer, 576 * frameSize ) / frameSize; + break; + } + + + if ( framesRead == 0 ) + { + endOfFile = 1; + + plugin.outMod->Write( NULL, 0 ); + } + else + { + framesRead = plugin.dsp_dosamples( (short *)audioBuffer, (int)framesRead, bits, info.channels, info.samplerate ); + if ( framesRead >= 576 ) + { + int timestamp = plugin.outMod->GetWrittenTime(); + + plugin.SAAddPCMData( (char *)audioBuffer, info.channels, bits, timestamp ); + plugin.VSAAddPCMData( (char *)audioBuffer, info.channels, bits, timestamp ); + } + + plugin.outMod->Write( audioBuffer, (int)framesRead * frameSize ); + } + } + else + { + SleepEx( 10, TRUE ); + } + } + } +} diff --git a/Src/Plugins/Input/in_wave/AudioThread.h b/Src/Plugins/Input/in_wave/AudioThread.h new file mode 100644 index 00000000..5679e44a --- /dev/null +++ b/Src/Plugins/Input/in_wave/AudioThread.h @@ -0,0 +1,19 @@ +#ifndef NULLSOFT_AUDIOTHREADH +#define NULLSOFT_AUDIOTHREADH + +#include <windows.h> + +VOID CALLBACK APCSeek( ULONG_PTR p_data ); +VOID CALLBACK APCPause( ULONG_PTR p_data ); +VOID CALLBACK APCStart( ULONG_PTR p_data ); +VOID CALLBACK APCStop( ULONG_PTR p_data ); + +void Kill(); +void AudioThreadInit(); +void AudioThreadQuit(); + +extern HANDLE audioThread; +extern HANDLE stopped; +extern HANDLE events[2]; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_wave/ExtendedRead.cpp b/Src/Plugins/Input/in_wave/ExtendedRead.cpp new file mode 100644 index 00000000..44bed186 --- /dev/null +++ b/Src/Plugins/Input/in_wave/ExtendedRead.cpp @@ -0,0 +1,80 @@ +#include "main.h" +#include <stddef.h> + +struct ExtendedRead +{ + SF_INFO info; + SNDFILE *soundFile; + int bits; + int frameSize; +}; + +extern "C" +{ + //returns handle!=0 if successful, 0 if error + //size will return the final nb of bytes written to the output, -1 if unknown + __declspec( dllexport ) intptr_t winampGetExtendedRead_openW( const wchar_t *fn, int *size, int *bps, int *nch, int *srate ) + { + ExtendedRead *extRead = (ExtendedRead *)calloc( 1, sizeof( ExtendedRead ) ); + + extRead->info.format = 0; + extRead->soundFile = sf_wchar_open( fn, SFM_READ, &extRead->info ); + if ( !extRead->soundFile ) + { + free( extRead ); + return 0; + } + + switch ( extRead->info.format & SF_FORMAT_SUBMASK ) + { + case SF_FORMAT_FLOAT: + case SF_FORMAT_DOUBLE: + sf_command( extRead->soundFile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE ); + break; + } + + extRead->bits = 16; // TODO: calculate bits per sample (what we want to use, not necessarily what the file has) + + *bps = extRead->bits; + *nch = extRead->info.channels; + *srate = extRead->info.samplerate; + + extRead->frameSize = ( extRead->bits / 8 ) * extRead->info.channels; + + *size = (int)extRead->info.frames * extRead->frameSize; // TODO: is this correct? + + return (intptr_t)extRead; + } + + //returns nb of bytes read. -1 if read error (like CD ejected). if (ret<len), EOF is assumed + __declspec( dllexport ) intptr_t winampGetExtendedRead_getData( intptr_t handle, char *dest, int len, int *killswitch ) + { + ExtendedRead *extRead = (ExtendedRead *)handle; + + sf_count_t framesRead = sf_readf_short( extRead->soundFile, (short *)dest, len / extRead->frameSize ); + + return (int)framesRead * extRead->frameSize; + } + + // return nonzero on success, zero on failure. + __declspec( dllexport ) int winampGetExtendedRead_setTime( intptr_t handle, int time_in_ms ) + { + ExtendedRead *extRead = (ExtendedRead *)handle; + if ( !extRead->info.seekable ) + return 0; + + int frames = MulDiv( time_in_ms, extRead->info.samplerate, 1000 ); // TODO: verify calculation + + sf_seek( extRead->soundFile, frames, SEEK_SET ); + + return 1; + } + + __declspec( dllexport ) void winampGetExtendedRead_close( intptr_t handle ) + { + ExtendedRead *extRead = (ExtendedRead *)handle; + sf_close( extRead->soundFile ); + + free( extRead ); + } +} diff --git a/Src/Plugins/Input/in_wave/RawReader.cpp b/Src/Plugins/Input/in_wave/RawReader.cpp new file mode 100644 index 00000000..c20cb85f --- /dev/null +++ b/Src/Plugins/Input/in_wave/RawReader.cpp @@ -0,0 +1,86 @@ +#include "main.h" +#include "RawReader.h" +#include <shlwapi.h> + /* +bool IsMyExtension(const wchar_t *filename) +{ + const wchar_t *ext = PathFindExtension(filename); + if (ext && *ext) + { + ext++; + return fileTypes.GetAVType(ext) != -1; + } + return false; +}*/ + +int RawMediaReaderService::CreateRawMediaReader(const wchar_t *filename, ifc_raw_media_reader **out_reader) +{ + // TODO:if (IsMyExtension(filename)) + if (!_wcsicmp(L".WAV", PathFindExtensionW(filename))) + { + RawMediaReader *raw_reader = new RawMediaReader(); + if (!raw_reader) + { + return NErr_OutOfMemory; + } + + int ret = raw_reader->Initialize(filename); + if (ret != NErr_Success) + { + delete raw_reader; + return ret; + } + + *out_reader = raw_reader; + return NErr_Success; + } + else + { + return NErr_False; + } +} + +#define CBCLASS RawMediaReaderService +START_DISPATCH; +CB( CREATERAWMEDIAREADER, CreateRawMediaReader ) +END_DISPATCH; +#undef CBCLASS + + +RawMediaReader::~RawMediaReader() +{ + if (soundFile) + sf_close(soundFile); +} + +int RawMediaReader::Initialize(const wchar_t *filename) +{ + info.format = 0; + soundFile = sf_wchar_open(filename, SFM_READ, &info); + if (!soundFile) + return NErr_FileNotFound; + + return NErr_Success; +} + +int RawMediaReader::Read(void *out_buffer, size_t buffer_size, size_t *bytes_read) +{ + sf_count_t sf_read = sf_read_raw(soundFile, out_buffer, buffer_size); + if (sf_read == 0) + return NErr_EndOfFile; + *bytes_read = (size_t)sf_read; + return NErr_Success; +} + +size_t RawMediaReader::Release() +{ + delete this; + return 0; +} + +#define CBCLASS RawMediaReader +START_DISPATCH; +CB(RELEASE, Release); +CB(RAW_READ, Read); +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/Plugins/Input/in_wave/RawReader.h b/Src/Plugins/Input/in_wave/RawReader.h new file mode 100644 index 00000000..55697cf2 --- /dev/null +++ b/Src/Plugins/Input/in_wave/RawReader.h @@ -0,0 +1,39 @@ +#pragma once +#include "../Agave/DecodeFile/svc_raw_media_reader.h" +#include "../Agave/DecodeFile/ifc_raw_media_reader.h" +#include "main.h" + +// {4FB808DC-C327-4999-9822-BDDDE20F44B0} +static const GUID sndfile_raw_reader_guid = +{ 0x4fb808dc, 0xc327, 0x4999, { 0x98, 0x22, 0xbd, 0xdd, 0xe2, 0xf, 0x44, 0xb0 } }; + + +class RawMediaReaderService : public svc_raw_media_reader +{ +public: + static const char *getServiceName() { return "SndFile Raw Reader"; } + static GUID getServiceGuid() { return sndfile_raw_reader_guid; } + + int CreateRawMediaReader(const wchar_t *filename, ifc_raw_media_reader **reader); + +protected: + RECVS_DISPATCH; +}; + +class RawMediaReader : public ifc_raw_media_reader +{ +public: + RawMediaReader() {} + ~RawMediaReader(); + + int Initialize(const wchar_t *filename); + int Read(void *buffer, size_t buffer_size, size_t *bytes_read); + size_t Release(); + +protected: + RECVS_DISPATCH; + +private: + SNDFILE *soundFile = NULL; + SF_INFO info; +}; diff --git a/Src/Plugins/Input/in_wave/VirtualIO.cpp b/Src/Plugins/Input/in_wave/VirtualIO.cpp new file mode 100644 index 00000000..b09c2523 --- /dev/null +++ b/Src/Plugins/Input/in_wave/VirtualIO.cpp @@ -0,0 +1,98 @@ +#include "VirtualIO.h" +#include "api__in_wave.h" +#include <api/service/waservicefactory.h> +#include "../nu/AutoWide.h" +#include <assert.h> +#include <windows.h> + +// TODO: extend this to use api_filereader +// instead of just the HTTP reader directly +// then we could use this is a workaround for unicode filenames + +sf_count_t VirtualGetFileLength( void *user_data ) +{ + svc_fileReader *reader = (svc_fileReader *)user_data; + + return reader->getLength(); +} + +sf_count_t VirtualSeek( sf_count_t offset, int whence, void *user_data ) +{ + svc_fileReader *reader = (svc_fileReader *)user_data; + switch ( whence ) + { + case SEEK_SET: + reader->seek( offset ); + break; + case SEEK_CUR: + { + uint64_t cur = reader->getPos(); + reader->seek( offset + cur ); + } + break; + case SEEK_END: + { + uint64_t total = reader->getLength(); + reader->seek( total + offset ); + } + break; + + } + + return reader->getPos(); +} + +sf_count_t VirtualRead( void *ptr, sf_count_t count, void *user_data ) +{ + svc_fileReader *reader = (svc_fileReader *)user_data; + + return reader->read( (int8_t *)ptr, (size_t)count ); +} + +sf_count_t VirtualWrite( const void *ptr, sf_count_t count, void *user_data ) +{ + svc_fileReader *reader = (svc_fileReader *)user_data; + + return reader->write( (int8_t *)ptr, (size_t)count ); +} + +sf_count_t VirtualTell( void *user_data ) +{ + svc_fileReader *reader = (svc_fileReader *)user_data; + + return reader->getPos(); +} + +SF_VIRTUAL_IO httpIO = +{ + VirtualGetFileLength, + VirtualSeek, + VirtualRead, + VirtualWrite, + VirtualTell +}; + +static const GUID HTTPReaderGUID = +{ 0xbc10fa00, 0x53f5, 0x4032, { 0xa0, 0x09, 0x2, 0x2b, 0x87, 0xec, 0x34, 0x04 } }; + +void *CreateReader( const wchar_t *url ) +{ + static waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( HTTPReaderGUID ); + if ( sf ) + { + svc_fileReader *l_reader = (svc_fileReader *)sf->getInterface(); + if ( l_reader ) + l_reader->open( url ); + + return l_reader; + } + else + return 0; +} + +void DestroyReader( void *reader ) +{ + static waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( HTTPReaderGUID ); + if ( sf ) + sf->releaseInterface( reader ); +}
\ No newline at end of file diff --git a/Src/Plugins/Input/in_wave/VirtualIO.h b/Src/Plugins/Input/in_wave/VirtualIO.h new file mode 100644 index 00000000..00be557d --- /dev/null +++ b/Src/Plugins/Input/in_wave/VirtualIO.h @@ -0,0 +1,10 @@ +#ifndef NULLSOFT_IN_WAVE_VIRTUALIO_H +#define NULLSOFT_IN_WAVE_VIRTUALIO_H +#include "main.h" +#include <api/service/svcs/svc_fileread.h> + +extern SF_VIRTUAL_IO httpIO, unicode_io; +void *CreateReader(const wchar_t *url); +void DestroyReader(void *reader); + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_wave/api__in_wave.h b/Src/Plugins/Input/in_wave/api__in_wave.h new file mode 100644 index 00000000..5bd2eb75 --- /dev/null +++ b/Src/Plugins/Input/in_wave/api__in_wave.h @@ -0,0 +1,10 @@ +#ifndef NULLSOFT_IN_WAVE_API_H +#define NULLSOFT_IN_WAVE_API_H + +#include "../Agave/Config/api_config.h" +extern api_config *configApi; +#define AGAVE_API_CONFIG configApi + +#define WASABI_API_SVC plugin.service + +#endif // !NULLSOFT_IN_WAVE_API_H
\ No newline at end of file diff --git a/Src/Plugins/Input/in_wave/config.cpp b/Src/Plugins/Input/in_wave/config.cpp new file mode 100644 index 00000000..9e5a82af --- /dev/null +++ b/Src/Plugins/Input/in_wave/config.cpp @@ -0,0 +1,128 @@ +#include "main.h" +#include "config.h" +#include "resource.h" + +char config_extensions[1024] = {0}; +bool config_upsample8bit=false; + +static int ExtensionInList(HWND hwndDlg, int id, const char *string) +{ + return (int)SendMessageA(GetDlgItem(hwndDlg, id), LB_FINDSTRINGEXACT, 0, (LPARAM)string); +} + +void FillExtensionList( HWND hwndDlg ) +{ + int numTypes; + sf_command( 0, SFC_GET_FORMAT_MAJOR_COUNT, &numTypes, sizeof( numTypes ) ); + SF_FORMAT_INFO info; + for ( int i = 0; i < numTypes; i++ ) + { + info.format = i; + sf_command( 0, SFC_GET_FORMAT_MAJOR, &info, sizeof( info ) ); + if ( !_strcmpi( info.extension, "mpc" ) ) + continue; + + if ( ExtensionInList( hwndDlg, IDC_EXTENSION_LIST, info.extension ) == LB_ERR ) + { + LRESULT index = SendMessageA( GetDlgItem( hwndDlg, IDC_EXTENSION_LIST ), LB_ADDSTRING, 0, (LPARAM)info.extension ); + if ( ExtensionExists( info.extension, config_extensions ) ) + SendMessage( GetDlgItem( hwndDlg, IDC_EXTENSION_LIST ), LB_SETSEL, TRUE, index ); + } + } +} + +void FillExtensionsEditControl( HWND hwndDlg ) +{ + char extensions[ 256 ] = ""; + char temp[ 20 ] = { 0 }; + + char *s = config_extensions; + + while ( s && *s ) + { + lstrcpynA( temp, s, 20 ); + + char *scan = temp; + while ( scan && *scan && *scan != ';' ) + scan = CharNextA( scan ); + + *scan = 0; + + if ( ExtensionInList( hwndDlg, IDC_EXTENSION_LIST, temp ) == LB_ERR ) + { + if ( *extensions ) + lstrcatA( extensions, ";" ); + + lstrcatA( extensions, temp ); + } + + s += lstrlenA( temp ); + if ( *s == ';' ) + s = CharNextA( s ); + } + + SetDlgItemTextA( hwndDlg, IDC_ADDITIONAL_EXTENSIONS, extensions ); +} + +void Preferences_Init( HWND hwndDlg ) +{ + SendMessageA( GetDlgItem( hwndDlg, IDC_OUTPUTBITS ), CB_ADDSTRING, 0, (LPARAM)"16 bit" ); // TODO: string table + SendMessageA( GetDlgItem( hwndDlg, IDC_OUTPUTBITS ), CB_ADDSTRING, 0, (LPARAM)"32 bit" ); // TODO: string table + + FillExtensionList( hwndDlg ); + FillExtensionsEditControl( hwndDlg ); +} + + +void Preferences_OnOK( HWND hwndDlg ) +{ + config_extensions[ 0 ] = 0; + LRESULT num = SendMessage( GetDlgItem( hwndDlg, IDC_EXTENSION_LIST ), LB_GETCOUNT, 0, 0 ); + for ( int i = 0; i < num; i++ ) + { + if ( SendMessage( GetDlgItem( hwndDlg, IDC_EXTENSION_LIST ), LB_GETSEL, i, 0 ) > 0 ) + { + char thisExtension[ 256 ] = { 0 }; + if ( config_extensions[ 0 ] ) + lstrcatA( config_extensions, ";" ); + + SendMessageA( GetDlgItem( hwndDlg, IDC_EXTENSION_LIST ), LB_GETTEXT, i, (LPARAM)thisExtension ); + lstrcatA( config_extensions, thisExtension ); + } + } + + char additional[ 1024 ] = { 0 }; + GetDlgItemTextA( hwndDlg, IDC_ADDITIONAL_EXTENSIONS, additional, 1024 ); + if ( additional[ 0 ] ) + { + if ( config_extensions[ 0 ] ) + lstrcatA( config_extensions, ";" ); + + lstrcatA( config_extensions, additional ); + } + + SetFileExtensions( config_extensions ); +} + +BOOL CALLBACK PreferencesDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + switch ( uMsg ) + { + case WM_INITDIALOG: + Preferences_Init( hwndDlg ); + break; + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDOK: + Preferences_OnOK( hwndDlg ); + EndDialog( hwndDlg, 0 ); + break; + case IDCANCEL: + EndDialog( hwndDlg, 0 ); + break; + } + } + + return 0; +} diff --git a/Src/Plugins/Input/in_wave/config.h b/Src/Plugins/Input/in_wave/config.h new file mode 100644 index 00000000..9163c8ab --- /dev/null +++ b/Src/Plugins/Input/in_wave/config.h @@ -0,0 +1,6 @@ +#ifndef NULLSOFT_IN_WAVE_CONFIG_H +#define NULLSOFT_IN_WAVE_CONFIG_H + +extern char config_extensions[1024]; +extern bool config_upsample8bit; +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_wave/extensions.cpp b/Src/Plugins/Input/in_wave/extensions.cpp new file mode 100644 index 00000000..998c734b --- /dev/null +++ b/Src/Plugins/Input/in_wave/extensions.cpp @@ -0,0 +1,183 @@ +#include "main.h" +#include "resource.h" +#include "config.h" +#include "assert.h" +#include "../Agave/Language/api_language.h" +#include "../nu/AutoWide.h" + +#include <strsafe.h> + +char defaultExtensions[1024] = {0}; +char fileExtensionsString[1200] = {0}; + +int SizeAvailableTypes() +{ + int size = 0; + int numTypes = 0; + + sf_command( 0, SFC_GET_FORMAT_MAJOR_COUNT, &numTypes, sizeof( numTypes ) ); + + SF_FORMAT_INFO info; + for ( int i = 0; i < numTypes; i++ ) + { + info.format = i; + sf_command( 0, SFC_GET_FORMAT_MAJOR, &info, sizeof( info ) ); + size += lstrlenA( info.extension ) + 1 /* ; or \0 */; + //size+=lstrlen(info.name) + 1 /* \0 */; + } + + return size; +} + +int ExtensionExists( const char *ext, const char *extensionList ) +{ + size_t len = lstrlenA( ext ); + char temp[ 20 ] = { 0 }; + const char *s = extensionList; + + while ( s && *s ) + { + lstrcpynA( temp, s, 20 ); + + char *scan = temp; + while ( scan && *scan && *scan != ';' ) + scan = CharNextA( scan ); + + *scan = 0; + + if ( !lstrcmpiA( temp, ext ) ) + return 1; + + s += lstrlenA( temp ); + if ( *s == ';' ) + s = CharNextA( s ); + } + + return 0; +} + +// TODO: sort default extension list +void BuildDefaultExtensions() +{ + // if we want a light extension list, here it is: lstrcpyn(defaultExtensions, "WAV;AIFF;VOC;AU;AIF;AIFC;SND"); + int size = SizeAvailableTypes() + 1; + assert( size < 1024 ); // TODO + + char *extPtr = defaultExtensions; + size_t extPtrCch = 1023; + extPtr[ 0 ] = 0; + + int numTypes = 0; + + sf_command( 0, SFC_GET_FORMAT_MAJOR_COUNT, &numTypes, sizeof( numTypes ) ); + + SF_FORMAT_INFO info = { 0 }; + + for ( int i = 0; i < numTypes; i++ ) + { + info.format = i; + + sf_command( 0, SFC_GET_FORMAT_MAJOR, &info, sizeof( info ) ); + if ( !_strcmpi( info.extension, "mpc" ) ) + continue; + + if ( ExtensionExists( info.extension, defaultExtensions ) ) + continue; + + if ( *CharPrevA( defaultExtensions, extPtr ) ) + StringCchCatExA( extPtr, extPtrCch, ";", &extPtr, &extPtrCch, 0 ); + + StringCchCatExA( extPtr, extPtrCch, info.extension, &extPtr, &extPtrCch, 0 ); + } +} + +void SetFileExtensions( const char *extList ) +{ + ZeroMemory( &fileExtensionsString, sizeof( fileExtensionsString ) ); + + char *end = 0; + + StringCchCopyExA( fileExtensionsString, 1200, extList, &end, 0, 0 ); + StringCchCopyExA( end + 1, 1200, WASABI_API_LNGSTRING( IDS_SOUND_FILES ), 0, 0, 0 ); + + plugin.FileExtensions = fileExtensionsString; +} + +static const wchar_t *pExtList[]={L"AIFF",L"AIF",L"AU",L"AVR",L"CAF",L"HTK",L"IFF",L"MAT",L"PAF",L"PVF",L"RAW",L"RF64",L"SD2",L"SDS",L"SF",L"VOC",L"W64",L"WAV",L"WVE",L"XI"}; +static const int pExtDescIdList[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; +static const int pExtDescList[] = +{ + IDS_FAMILY_STRING_AAIF, + IDS_FAMILY_STRING_AAIF, + IDS_FAMILY_STRING_AU, + IDS_FAMILY_STRING_AVR, + IDS_FAMILY_STRING_ACA, + IDS_FAMILY_STRING_HMMTS, + IDS_FAMILY_STRING_AAIF, + IDS_FAMILY_STRING_MATLAB, + IDS_FAMILY_STRING_PARIS, + IDS_FAMILY_STRING_PVF, + IDS_FAMILY_STRING_HEADERLESS_RAW, + IDS_FAMILY_STRING_RF64, + IDS_FAMILY_STRING_SDII, + IDS_FAMILY_STRING_RAW_MIDI_SAMPLE_DUMP, + IDS_FAMILY_STRING_IRCAM, + IDS_FAMILY_STRING_CVOC, + IDS_FAMILY_STRING_SFWOW64, + IDS_FAMILY_STRING_MSWAV, + IDS_FAMILY_STRING_MSWAV, + IDS_FAMILY_STRING_FT2WAV, +}; + +BOOL GetExtensionName( LPCWSTR pszExt, LPWSTR pszDest, INT cchDest ) +{ + INT maxCount, index; + DWORD lcid; + SF_FORMAT_INFO info; + + lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT ); + // first scan our list if there is no entry ask libsnd. we do this cause libsnd format description sucks + + for ( index = sizeof( pExtList ) / sizeof( wchar_t * ) - 1; index >= 0 && CSTR_EQUAL != CompareStringW( lcid, NORM_IGNORECASE, pszExt, -1, pExtList[ index ], -1 ); index-- ); + if ( index >= 0 && S_OK == StringCchCopyW( pszDest, cchDest, WASABI_API_LNGSTRINGW( pExtDescList[ pExtDescIdList[ index ] ] ) ) ) return TRUE; + + sf_command( 0, SFC_GET_FORMAT_MAJOR_COUNT, &maxCount, sizeof( maxCount ) ); + for ( index = 0; index < maxCount; index++ ) + { + info.format = index; + sf_command( 0, SFC_GET_FORMAT_MAJOR, &info, sizeof( info ) ); + if ( CSTR_EQUAL == CompareStringW( lcid, NORM_IGNORECASE, pszExt, -1, AutoWide( info.extension ), -1 ) ) + { + INT len1, len2; + len1 = lstrlenA( info.extension ); + len2 = lstrlenA( info.name ); + if ( len2 > len1 ) + { + if ( CSTR_EQUAL == CompareStringA( lcid, NORM_IGNORECASE, info.extension, len1, info.name, len1 ) ) + { + info.name += len1; + len2 -= len1; + } + + if ( len2 > 0 && ' ' == *info.name ) + { + info.name++; + len2--; + } + + if ( len2 > 0 && '(' == *info.name ) + { + info.name++; + len2--; + } + + if ( len2 > 0 && ')' == info.name[ len2 - 1 ] ) + len2--; + } + + return ( S_OK == StringCchCopyNW( pszDest, cchDest, AutoWide( info.name ), len2 ) ); + } + } + + return FALSE; +} diff --git a/Src/Plugins/Input/in_wave/in_wave.rc b/Src/Plugins/Input/in_wave/in_wave.rc new file mode 100644 index 00000000..7a674704 --- /dev/null +++ b/Src/Plugins/Input/in_wave/in_wave.rc @@ -0,0 +1,144 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""version.rc2""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 125, 244 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Waveform Decoder" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Built-in Extensions",IDC_STATIC,4,4,99,8 + LISTBOX IDC_EXTENSION_LIST,4,16,117,163,LBS_MULTIPLESEL | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LTEXT "Additional Extensions\nseparated with semi-colons\ne.g. aifc;snd",IDC_STATIC,4,183,117,24 + EDITTEXT IDC_ADDITIONAL_EXTENSIONS,4,211,117,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,4,227,50,13 + PUSHBUTTON "Cancel",IDCANCEL,71,227,50,13 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 121 + TOPMARGIN, 4 + BOTTOMMARGIN, 240 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_NULLSOFT_WAVEFORM_DECODER "Nullsoft Waveform Decoder v%s" + 65535 "{96374982-0142-41a5-AEDE-244505C45D30}" +END + +STRINGTABLE +BEGIN + IDS_NULLSOFT_WAVEFORM_DECODER_OLD "Nullsoft Waveform Decoder" + IDS_SOUND_FILES "Sound Files" + IDS_INFO_STR_FMT "%s\n%u Channel(s)\n%u Hz" + IDS_FILE_INFORMATION "Waveform File Information" + IDS_FAMILY_STRING_AAIF "Apple Audio Interchange File" + IDS_FAMILY_STRING_AU "AU Format Sound File" + IDS_FAMILY_STRING_AVR "Audio Visual Research File" + IDS_FAMILY_STRING_ACA "Apple Core Audio Format" + IDS_FAMILY_STRING_HMMTS "Hidden Markov Model Toolkit Speech Recognition File" + IDS_FAMILY_STRING_MATLAB "Matlab Audio Format" + IDS_FAMILY_STRING_PARIS "Paris Audio File" + IDS_FAMILY_STRING_PVF "Portable Voice Format File" + IDS_FAMILY_STRING_HEADERLESS_RAW "Headerless RAW Waveform" + IDS_FAMILY_STRING_SDII "Sound Designer II Audio File" +END + +STRINGTABLE +BEGIN + IDS_FAMILY_STRING_RAW_MIDI_SAMPLE_DUMP + "Raw Midi Sample Dump Standard File" + IDS_FAMILY_STRING_IRCAM "IRCAM Sound File" + IDS_FAMILY_STRING_CVOC "Creative VOC Format" + IDS_FAMILY_STRING_SFWOW64 "Soundforge Wow 64 Format" + IDS_FAMILY_STRING_MSWAV "Microsoft Wave Sound Format" + IDS_FAMILY_STRING_FT2WAV "Fasttracker 2 Waveform" + IDS_ABOUT_TEXT "%s\n© 2005-2023 Winamp SA\nWritten by: Ben Allison\nBuild date: %hs\n\nUses %hs\n© Erik de Castro Lopo" + IDS_FAMILY_STRING_RF64 "RIFF 64 Broadcast Wave Format" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc2" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/Plugins/Input/in_wave/in_wave.sln b/Src/Plugins/Input/in_wave/in_wave.sln new file mode 100644 index 00000000..d17d6f36 --- /dev/null +++ b/Src/Plugins/Input/in_wave/in_wave.sln @@ -0,0 +1,40 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29424.173 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "in_wave", "in_wave.vcxproj", "{03366121-F8F5-4845-8EDD-B0EEC955282F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsndfile", "..\libsndfile\libsndfile.vcxproj", "{6BFA7E64-2074-4885-A685-2772AF31E288}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {03366121-F8F5-4845-8EDD-B0EEC955282F}.Debug|Win32.ActiveCfg = Debug|Win32 + {03366121-F8F5-4845-8EDD-B0EEC955282F}.Debug|Win32.Build.0 = Debug|Win32 + {03366121-F8F5-4845-8EDD-B0EEC955282F}.Debug|x64.ActiveCfg = Debug|x64 + {03366121-F8F5-4845-8EDD-B0EEC955282F}.Debug|x64.Build.0 = Debug|x64 + {03366121-F8F5-4845-8EDD-B0EEC955282F}.Release|Win32.ActiveCfg = Release|Win32 + {03366121-F8F5-4845-8EDD-B0EEC955282F}.Release|Win32.Build.0 = Release|Win32 + {03366121-F8F5-4845-8EDD-B0EEC955282F}.Release|x64.ActiveCfg = Release|x64 + {03366121-F8F5-4845-8EDD-B0EEC955282F}.Release|x64.Build.0 = Release|x64 + {6BFA7E64-2074-4885-A685-2772AF31E288}.Debug|Win32.ActiveCfg = Debug|Win32 + {6BFA7E64-2074-4885-A685-2772AF31E288}.Debug|Win32.Build.0 = Debug|Win32 + {6BFA7E64-2074-4885-A685-2772AF31E288}.Debug|x64.ActiveCfg = Debug|x64 + {6BFA7E64-2074-4885-A685-2772AF31E288}.Debug|x64.Build.0 = Debug|x64 + {6BFA7E64-2074-4885-A685-2772AF31E288}.Release|Win32.ActiveCfg = Release|Win32 + {6BFA7E64-2074-4885-A685-2772AF31E288}.Release|Win32.Build.0 = Release|Win32 + {6BFA7E64-2074-4885-A685-2772AF31E288}.Release|x64.ActiveCfg = Release|x64 + {6BFA7E64-2074-4885-A685-2772AF31E288}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E0AC775B-F8AF-40E3-A215-1D903C9B8C3F} + EndGlobalSection +EndGlobal diff --git a/Src/Plugins/Input/in_wave/in_wave.vcxproj b/Src/Plugins/Input/in_wave/in_wave.vcxproj new file mode 100644 index 00000000..f502afbe --- /dev/null +++ b/Src/Plugins/Input/in_wave/in_wave.vcxproj @@ -0,0 +1,282 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{03366121-F8F5-4845-8EDD-B0EEC955282F}</ProjectGuid> + <RootNamespace>in_wave</RootNamespace> + <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnableManifest>false</VcpkgEnableManifest> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;IN_WAVE_EXPORTS;_WIN32_WINNT=0x601;UNICODE_INPUT_PLUGIN;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;IN_WAVE_EXPORTS;_WIN32_WINNT=0x601;UNICODE_INPUT_PLUGIN;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;IN_WAVE_EXPORTS;_WIN32_WINNT=0x601;UNICODE_INPUT_PLUGIN;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <ObjectFileName>$(IntDir)</ObjectFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;IN_WAVE_EXPORTS;_WIN32_WINNT=0x601;UNICODE_INPUT_PLUGIN;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <ObjectFileName>$(IntDir)</ObjectFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs> + <GenerateDebugInformation>false</GenerateDebugInformation> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\replicant\jnetlib\jnetlib.vcxproj"> + <Project>{e105a0a2-7391-47c5-86ac-718003524c3d}</Project> + </ProjectReference> + <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <ClInclude Include="api__in_wave.h" /> + <ClInclude Include="AudioThread.h" /> + <ClInclude Include="config.h" /> + <ClInclude Include="main.h" /> + <ClInclude Include="RawReader.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="VirtualIO.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="AudioThread.cpp" /> + <ClCompile Include="config.cpp" /> + <ClCompile Include="ExtendedRead.cpp" /> + <ClCompile Include="extensions.cpp" /> + <ClCompile Include="main.cpp" /> + <ClCompile Include="RawReader.cpp" /> + <ClCompile Include="VirtualIO.cpp" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="in_wave.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Input/in_wave/in_wave.vcxproj.filters b/Src/Plugins/Input/in_wave/in_wave.vcxproj.filters new file mode 100644 index 00000000..2729af0f --- /dev/null +++ b/Src/Plugins/Input/in_wave/in_wave.vcxproj.filters @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="AudioThread.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="config.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ExtendedRead.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="extensions.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="RawReader.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="VirtualIO.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="api__in_wave.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="AudioThread.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="main.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="RawReader.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="VirtualIO.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{5702576b-51d6-4db9-81de-3bbe5a177a43}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{29eaf111-75c2-4703-ae85-69f56a51561e}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{aeb6933e-bfc2-47ba-ad37-db67bbcf0ab5}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="in_wave.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file 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; +} diff --git a/Src/Plugins/Input/in_wave/main.h b/Src/Plugins/Input/in_wave/main.h new file mode 100644 index 00000000..2614325f --- /dev/null +++ b/Src/Plugins/Input/in_wave/main.h @@ -0,0 +1,24 @@ +#ifndef NULLSOFT_IN_WAVE_MAINH +#define NULLSOFT_IN_WAVE_MAINH + +extern volatile int currentSongLength; +#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES +#include "sndfile.h" +extern SNDFILE *sndFile; +#include "../Winamp/in2.h" +extern In_Module plugin; + +extern int pan, volume; + +#include <windows.h> +BOOL CALLBACK PreferencesDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +int ExtensionExists(const char *ext, const char *extensionList); + +void BuildDefaultExtensions(); + +extern char defaultExtensions[1024]; +void SetFileExtensions(const char *extList); +int CalcBitRate(const SF_INFO *info); +BOOL GetExtensionName(LPCWSTR pszExt, LPWSTR pszDest, INT cchDest); + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Input/in_wave/resource.h b/Src/Plugins/Input/in_wave/resource.h new file mode 100644 index 00000000..861b0d8e --- /dev/null +++ b/Src/Plugins/Input/in_wave/resource.h @@ -0,0 +1,47 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by in_wave.rc +// +#define IDS_NULLSOFT_WAVEFORM_DECODER_OLD 0 +#define IDS_WAVEFORM_DECODER 1 +#define IDS_ABOUT_STR 2 +#define IDS_SOUND_FILES 3 +#define IDS_INFO_STR_FMT 4 +#define IDS_STRING5 5 +#define IDS_WAVE_U_MS 6 +#define IDS_FAMILY_STRING_AAIF 6 +#define IDS_FAMILY_STRING_AU 7 +#define IDS_FAMILY_STRING_AVR 8 +#define IDS_FAMILY_STRING_ACA 9 +#define IDS_FAMILY_STRING_HMMTS 10 +#define IDS_FAMILY_STRING_MATLAB 11 +#define IDS_FAMILY_STRING_PARIS 12 +#define IDS_FAMILY_STRING_PVF 13 +#define IDS_FAMILY_STRING_HEADERLESS_RAW 14 +#define IDS_FAMILY_STRING_SDII 15 +#define IDS_FAMILY_STRING_RAW_MIDI_SAMPLE_DUMP 16 +#define IDS_FAMILY_STRING_IRCAM 17 +#define IDS_FAMILY_STRING_CVOC 18 +#define IDS_FAMILY_STRING_SFWOW64 19 +#define IDS_FAMILY_STRING_MSWAV 20 +#define IDS_FAMILY_STRING_FT2WAV 21 +#define IDS_ABOUT_TEXT 22 +#define IDS_FAMILY_STRING_RF64 23 +#define IDS_FILE_INFORMATION 24 +#define IDD_CONFIG 101 +#define IDC_EXTENSION_LIST 1001 +#define IDC_EDIT1 1002 +#define IDC_ADDITIONAL_EXTENSIONS 1002 +#define IDC_OUTPUTBITS 1003 +#define IDS_NULLSOFT_WAVEFORM_DECODER 65534 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 25 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1004 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/Plugins/Input/in_wave/version.rc2 b/Src/Plugins/Input/in_wave/version.rc2 new file mode 100644 index 00000000..e7ecb3e9 --- /dev/null +++ b/Src/Plugins/Input/in_wave/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 3,27,0,0 + PRODUCTVERSION WINAMP_PRODUCTVER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Winamp SA" + VALUE "FileDescription", "Winamp Input Plug-in" + VALUE "FileVersion", "3,27,0,0" + VALUE "InternalName", "Nullsoft Waveform Decoder" + VALUE "LegalCopyright", "Copyright © 2005-2023 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "in_wave.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END |