aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_wave
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
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Input/in_wave')
-rw-r--r--Src/Plugins/Input/in_wave/AudioThread.cpp330
-rw-r--r--Src/Plugins/Input/in_wave/AudioThread.h19
-rw-r--r--Src/Plugins/Input/in_wave/ExtendedRead.cpp80
-rw-r--r--Src/Plugins/Input/in_wave/RawReader.cpp86
-rw-r--r--Src/Plugins/Input/in_wave/RawReader.h39
-rw-r--r--Src/Plugins/Input/in_wave/VirtualIO.cpp98
-rw-r--r--Src/Plugins/Input/in_wave/VirtualIO.h10
-rw-r--r--Src/Plugins/Input/in_wave/api__in_wave.h10
-rw-r--r--Src/Plugins/Input/in_wave/config.cpp128
-rw-r--r--Src/Plugins/Input/in_wave/config.h6
-rw-r--r--Src/Plugins/Input/in_wave/extensions.cpp183
-rw-r--r--Src/Plugins/Input/in_wave/in_wave.rc144
-rw-r--r--Src/Plugins/Input/in_wave/in_wave.sln40
-rw-r--r--Src/Plugins/Input/in_wave/in_wave.vcxproj282
-rw-r--r--Src/Plugins/Input/in_wave/in_wave.vcxproj.filters65
-rw-r--r--Src/Plugins/Input/in_wave/main.cpp437
-rw-r--r--Src/Plugins/Input/in_wave/main.h24
-rw-r--r--Src/Plugins/Input/in_wave/resource.h47
-rw-r--r--Src/Plugins/Input/in_wave/version.rc239
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