diff --git a/.appveyor.yml b/.appveyor.yml
index 8a6de92f..56f79cc0 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -1,18 +1,27 @@
version: '{build}'
-image: Visual Studio 2013
+
+image:
+ - Visual Studio 2013
+ - macOS
platform:
- Win32
- x64
+matrix:
+ exclude:
+ - image: macOS
+ platform: Win32
+
cache:
- - C:\tmp\VST3 SDK
+ - c:\tmp\VST3 SDK -> Data/vstgui.patch
install:
- ps: |
- if (-Not (Test-Path "C:\tmp\VST3 SDK")) {
+ if (-Not (Test-Path "c:\tmp\VST3 SDK")) {
Invoke-WebRequest "https://www.steinberg.net/sdk_downloads/vstsdk366_27_06_2016_build_61.zip" -OutFile "vstsdk.zip"
- Expand-Archive "vstsdk.zip" "C:\tmp"
+ Expand-Archive "vstsdk.zip" "c:\tmp"
+ & git apply -p2 --unsafe-paths --directory /tmp Data/vstgui.patch
}
build_script:
@@ -22,3 +31,22 @@ build_script:
- msbuild /v:minimal /nologo WaveSabre.sln
- msbuild /v:minimal /nologo /property:Configuration="MinSizeRel" WaveSabre.sln
- cd ..
+
+for:
+ -
+ matrix:
+ only:
+ - image: macOS
+ cache: /private/tmp/VST3 SDK -> Data/vstgui.patch
+ install:
+ - ps: |
+ if (-Not (Test-Path "/private/tmp/VST3 SDK")) {
+ Invoke-WebRequest "https://www.steinberg.net/sdk_downloads/vstsdk366_27_06_2016_build_61.zip" -OutFile "vstsdk.zip"
+ Expand-Archive "vstsdk.zip" "/private/tmp"
+ & git apply -p2 --unsafe-paths --directory /private/tmp Data/vstgui.patch
+ }
+ - HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 brew install libgsm
+ build_script:
+ - cmake -B build -G Xcode -DVSTSDK3_DIR="/private/tmp/VST3 SDK"
+ - xcodebuild -project build/WaveSabre.xcodeproj -scheme ALL_BUILD -configuration Release build
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5d02e504..7546b16e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,6 @@
project("WaveSabre")
+set (CMAKE_CXX_STANDARD 11)
cmake_minimum_required(VERSION 3.11)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@@ -11,13 +12,17 @@ endif()
set(VSTSDK3_DIR "${CMAKE_SOURCE_DIR}/Vst3.x/" CACHE PATH "VSTSDK location")
# shared code
+if(MSVC)
add_subdirectory(MSVCRT)
+endif()
add_subdirectory(WaveSabreCore)
+if(MSVC)
add_subdirectory(WaveSabrePlayerLib)
# binaries
add_subdirectory(Tests/PlayerTest)
add_subdirectory(WaveSabreStandAlonePlayer)
+endif()
# VSTs
if(VSTSDK3_DIR)
diff --git a/Data/Info.plist.in b/Data/Info.plist.in
new file mode 100644
index 00000000..f61f8fae
--- /dev/null
+++ b/Data/Info.plist.in
@@ -0,0 +1,34 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleExecutable
+ ${MACOSX_BUNDLE_EXECUTABLE_NAME}
+ CFBundleGetInfoString
+ ${MACOSX_BUNDLE_INFO_STRING}
+ CFBundleIconFile
+ ${MACOSX_BUNDLE_ICON_FILE}
+ CFBundleIdentifier
+ ${MACOSX_BUNDLE_GUI_IDENTIFIER}
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleLongVersionString
+ ${MACOSX_BUNDLE_LONG_VERSION_STRING}
+ CFBundleName
+ ${MACOSX_BUNDLE_BUNDLE_NAME}
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ ${MACOSX_BUNDLE_SHORT_VERSION_STRING}
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ ${MACOSX_BUNDLE_BUNDLE_VERSION}
+ CSResourcesFileMapped
+
+ NSHumanReadableCopyright
+ ${MACOSX_BUNDLE_COPYRIGHT}
+
+
diff --git a/Data/resourcestr.h b/Data/resourcestr.h
new file mode 100644
index 00000000..5ffd4883
--- /dev/null
+++ b/Data/resourcestr.h
@@ -0,0 +1,7 @@
+/* For using CResourceDescription(const char* name) instead of CResourceDescription(int id). */
+
+#define IDB_PNG1 "background.png"
+#define IDB_PNG2 "knob1.png"
+#define IDB_PNG3 "tinybutton.png"
+#define IDB_PNG4 "optionmenu-unpressed.png"
+#define IDB_PNG5 "optionmenu-pressed.png"
diff --git a/Data/vstgui.patch b/Data/vstgui.patch
new file mode 100644
index 00000000..12c1a19a
--- /dev/null
+++ b/Data/vstgui.patch
@@ -0,0 +1,26 @@
+diff --git a/vstsdk.orig/VST3 SDK/vstgui.sf/vstgui/vstgui.cpp b/vstsdk/VST3 SDK/vstgui.sf/vstgui/vstgui.cpp
+index dd081cf..29f0467 100644
+--- a/vstsdk.orig/VST3 SDK/vstgui.sf/vstgui/vstgui.cpp
++++ b/vstsdk/VST3 SDK/vstgui.sf/vstgui/vstgui.cpp
+@@ -217,7 +217,7 @@ END_NAMESPACE_VSTGUI
+ //-----------------------------------------------------------------------------
+ #if MAC
+ //-----------------------------------------------------------------------------
+-#include
++#include
+ #include
+
+ #if MAC_CARBON
+diff --git a/vstsdk.orig/VST3 SDK/vstgui.sf/vstgui/vstgui.h b/vstsdk/VST3 SDK/vstgui.sf/vstgui/vstgui.h
+index ad75218..86db083 100644
+--- a/vstsdk.orig/VST3 SDK/vstgui.sf/vstgui/vstgui.h
++++ b/vstsdk/VST3 SDK/vstgui.sf/vstgui/vstgui.h
+@@ -66,7 +66,7 @@
+ #endif
+
+ #if WINDOWS
+- #define _WIN32_WINNT 0x0501
++ #define _WIN32_WINNT 0x0600
+ #ifndef GDIPLUS
+ #define GDIPLUS 1 // by default we use GDIPlus
+ #endif
diff --git a/Vsts/CMakeLists.txt b/Vsts/CMakeLists.txt
index 323d34e6..f65b207e 100644
--- a/Vsts/CMakeLists.txt
+++ b/Vsts/CMakeLists.txt
@@ -1,18 +1,68 @@
set(VSTDIR "" CACHE PATH "VST system directory")
+find_path(LIBGSM_INCLUDE_DIR NAMES gsm.h
+ PATHS
+ /usr/local/include/gsm
+ /usr/local/include
+ /usr/include/gsm
+ /usr/include
+ )
+
+find_library(LIBGSM_LIBRARY NAMES gsm
+ PATHS
+ /usr/local/lib
+ /usr/lib
+ )
+
+if(LIBGSM_INCLUDE_DIR AND LIBGSM_LIBRARY)
+ add_definitions(-DHAVE_LIBGSM)
+endif(LIBGSM_INCLUDE_DIR AND LIBGSM_LIBRARY)
+
+if(APPLE)
+ find_library(CARBON_LIBRARY Carbon)
+ find_library(COCOA_LIBRARY Cocoa)
+ find_library(AUDIO_TOOLBOX_LIBRARY AudioToolbox)
+ mark_as_advanced(CARBON_LIBRARY COCOA_LIBRARY)
+ set(EXTRA_LIBS ${CARBON_LIBRARY} ${COCOA_LIBRARY} ${AUDIO_TOOLBOX_LIBRARY} ${LIBGSM_LIBRARY})
+ file(GLOB RESOURCE_FILES ../Data/*.png)
+endif(APPLE)
+
file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
foreach(child ${children})
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${child})
file(GLOB sources ${CMAKE_CURRENT_SOURCE_DIR}/${child}/*.h)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/${child} sources)
- file(WRITE "${CMAKE_BINARY_DIR}/${child}.def"
- "LIBRARY ${child}\nEXPORTS\nVSTPluginMain\nmain=VSTPluginMain")
- add_library(${child} SHARED
- ${sources} ../Data/data.rc ${CMAKE_BINARY_DIR}/${child}.def)
- target_link_libraries(${child} WaveSabreCore WaveSabreVstLib)
- set_property(TARGET ${child} APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL
- " /LTCG")
- set_property(TARGET ${child} PROPERTY FOLDER VSTs)
+
+ if(WIN32)
+ file(WRITE "${CMAKE_BINARY_DIR}/${child}.def"
+ "LIBRARY ${child}\nEXPORTS\nVSTPluginMain\nmain=VSTPluginMain")
+ add_library(${child} SHARED
+ ${sources} ../Data/data.rc ${CMAKE_BINARY_DIR}/${child}.def)
+ set_property(TARGET ${child} APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL
+ " /LTCG")
+ set_property(TARGET ${child} PROPERTY FOLDER VSTs)
+ endif(WIN32)
+
+ if(APPLE)
+ add_library(${child} MODULE ${sources} ${RESOURCE_FILES})
+ set_target_properties(${child} PROPERTIES
+ BUNDLE true
+ BUNDLE_EXTENSION "vst"
+ XCODE_ATTRIBUTE_WRAPPER_EXTENSION "vst"
+ MACOSX_BUNDLE_INFO_PLIST "Data/Info.plist.in"
+ MACOSX_BUNDLE_BUNDLE_NAME "${child}"
+ MACOSX_BUNDLE_GUI_IDENTIFIER "io.logicoma.wavesabre.${child}"
+ MACOSX_BUNDLE_ICON_FILE ""
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0.0"
+ MACOSX_BUNDLE_COPYRIGHT "Copyright 2012-2021 WaveSabre Team"
+ XCODE_ATTRIBUTE_USE_HEADERMAP YES
+ RESOURCE "${RESOURCE_FILES}"
+ )
+ target_include_directories(${child} PUBLIC ${LIBGSM_INCLUDE_DIR})
+ target_link_options(${child} PUBLIC "LINKER:-all_load")
+ endif(APPLE)
+
+ target_link_libraries(${child} WaveSabreCore WaveSabreVstLib ${EXTRA_LIBS})
if(VSTDIR)
add_custom_command(TARGET ${child} POST_BUILD
diff --git a/Vsts/Specimen/SpecimenEditor.cpp b/Vsts/Specimen/SpecimenEditor.cpp
index 084543ae..58d4c81f 100644
--- a/Vsts/Specimen/SpecimenEditor.cpp
+++ b/Vsts/Specimen/SpecimenEditor.cpp
@@ -9,18 +9,27 @@ using namespace WaveSabreCore;
#include
using namespace std;
+#ifdef _WIN32
#include
HACMDRIVERID SpecimenEditor::driverId = NULL;
WAVEFORMATEX *SpecimenEditor::foundWaveFormat = nullptr;
+#endif
+
+#ifdef HAVE_LIBGSM
+#include
+#include
+
+#define GSM_PACKET_SIZE 160
+#define GSM_MS_PACKET_SIZE (GSM_PACKET_SIZE * 2)
+#define GSM_MS_BLOCK_SIZE 65
+#endif
SpecimenEditor::SpecimenEditor(AudioEffect *audioEffect)
: VstEditor(audioEffect, 580, 400, "SPECIMEN")
{
pressedTheFuck = false;
- fileSelector = nullptr;
-
specimen = ((SpecimenVst *)audioEffect)->GetSpecimen();
}
@@ -30,8 +39,6 @@ SpecimenEditor::~SpecimenEditor()
void SpecimenEditor::Open()
{
- if (!fileSelector) fileSelector = new CFileSelector(nullptr);
-
addSpacer();
addButton(1000, "LOAD SAMPLE");
addSpacer();
@@ -106,110 +113,183 @@ void SpecimenEditor::setParameter(VstInt32 index, float value)
bool oldValue = pressedTheFuck;
pressedTheFuck = value != 0.0f;
if (pressedTheFuck != oldValue && oldValue)
- {
- VstFileSelect vfs;
- memset(&vfs, 0, sizeof(vfs));
- vfs.command = kVstFileLoad;
- vfs.type = kVstFileType;
- if (fileSelector->run(&vfs))
- {
- try
- {
- ifstream input(vfs.returnPath, ios::in | ios::binary | ios::ate);
- if (!input.is_open()) throw exception("Could not open file.");
- auto inputSize = input.tellg();
- auto inputBuf = new unsigned char[(unsigned int)inputSize];
- input.seekg(0, ios::beg);
- input.read((char *)inputBuf, inputSize);
- input.close();
-
- if (*((unsigned int *)inputBuf) != 0x46464952) throw exception("Input file missing RIFF header.");
- if (*((unsigned int *)(inputBuf + 4)) != (unsigned int)inputSize - 8) throw exception("Input file contains invalid RIFF header.");
- if (*((unsigned int *)(inputBuf + 8)) != 0x45564157) throw exception("Input file missing WAVE chunk.");
-
- if (*((unsigned int *)(inputBuf + 12)) != 0x20746d66) throw exception("Input file missing format sub-chunk.");
- if (*((unsigned int *)(inputBuf + 16)) != 16) throw exception("Input file is not a PCM waveform.");
- auto inputFormat = (LPWAVEFORMATEX)(inputBuf + 20);
- if (inputFormat->wFormatTag != WAVE_FORMAT_PCM) throw exception("Input file is not a PCM waveform.");
- if (inputFormat->nChannels != 1) throw exception("Input file is not mono.");
- if (inputFormat->nSamplesPerSec != Specimen::SampleRate) throw exception(("Input file is not " + to_string(Specimen::SampleRate) + "hz.").c_str());
- if (inputFormat->wBitsPerSample != sizeof(short) * 8) throw exception("Input file is not 16-bit.");
-
- int chunkPos = 36;
- int chunkSizeBytes;
- while (true)
- {
- if (chunkPos >= (int)inputSize) throw exception("Input file missing data sub-chunk.");
- chunkSizeBytes = *((unsigned int *)(inputBuf + chunkPos + 4));
- if (*((unsigned int *)(inputBuf + chunkPos)) == 0x61746164) break;
- else chunkPos += 8 + chunkSizeBytes;
- }
- int rawDataLength = chunkSizeBytes / 2;
- auto rawData = new short[rawDataLength];
- memcpy(rawData, inputBuf + chunkPos + 8, chunkSizeBytes);
-
- auto compressedData = new char[chunkSizeBytes];
-
- int waveFormatSize = 0;
- acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &waveFormatSize);
- auto waveFormat = (WAVEFORMATEX *)(new char[waveFormatSize]);
- memset(waveFormat, 0, waveFormatSize);
- waveFormat->wFormatTag = WAVE_FORMAT_GSM610;
- waveFormat->nSamplesPerSec = Specimen::SampleRate;
-
- ACMFORMATCHOOSE formatChoose;
- memset(&formatChoose, 0, sizeof(formatChoose));
- formatChoose.cbStruct = sizeof(formatChoose);
- formatChoose.pwfx = waveFormat;
- formatChoose.cbwfx = waveFormatSize;
- formatChoose.pwfxEnum = waveFormat;
- formatChoose.fdwEnum = ACM_FORMATENUMF_WFORMATTAG | ACM_FORMATENUMF_NSAMPLESPERSEC;
-
- if (acmFormatChoose(&formatChoose)) throw exception("acmFormatChoose failed");
-
- acmDriverEnum(driverEnumCallback, (DWORD_PTR)waveFormat, NULL);
- HACMDRIVER driver = NULL;
- if (acmDriverOpen(&driver, driverId, 0)) throw exception("acmDriverOpen failed");
-
- HACMSTREAM stream = NULL;
- if (acmStreamOpen(&stream, driver, inputFormat, waveFormat, NULL, NULL, NULL, ACM_STREAMOPENF_NONREALTIME)) throw exception("acmStreamOpen failed");
-
- ACMSTREAMHEADER streamHeader;
- memset(&streamHeader, 0, sizeof(streamHeader));
- streamHeader.cbStruct = sizeof(streamHeader);
- streamHeader.pbSrc = (LPBYTE)rawData;
- streamHeader.cbSrcLength = chunkSizeBytes;
- streamHeader.pbDst = (LPBYTE)compressedData;
- streamHeader.cbDstLength = chunkSizeBytes;
- if (acmStreamPrepareHeader(stream, &streamHeader, 0)) throw exception("acmStreamPrepareHeader failed");
- if (acmStreamConvert(stream, &streamHeader, 0)) throw exception("acmStreamConvert failed");
-
- delete [] rawData;
-
- acmStreamClose(stream, 0);
- acmDriverClose(driver, 0);
-
- specimen->LoadSample(compressedData, streamHeader.cbDstLengthUsed, chunkSizeBytes, waveFormat);
-
- delete [] (char *)waveFormat;
-
- delete [] compressedData;
-
- delete [] inputBuf;
- }
- catch (const exception& e)
- {
- MessageBoxA(0, e.what(), "FUCK THAT SHIT", MB_OK | MB_ICONEXCLAMATION);
- }
- }
- }
- } else
- {
- VstEditor::setParameter(index, value);
- }
+ {
+ CNewFileSelector* fileSelector =
+ CNewFileSelector::create(getFrame(), CNewFileSelector::kSelectFile);
+ if (fileSelector)
+ {
+ fileSelector->setDefaultExtension(CFileExtension("WAVE", "wav"));
+ fileSelector->setTitle("Choose An Audio File");
+ fileSelector->run(this);
+ fileSelector->forget();
+ }
+ }
+ }
+ else
+ {
+ VstEditor::setParameter(index, value);
+ }
+}
+CMessageResult SpecimenEditor::notify(CBaseObject* sender, const char* message)
+{
+ if (message == CNewFileSelector::kSelectEndMessage) {
+ CNewFileSelector* sel = dynamic_cast(sender);
+ if (sel && (sel->getNumSelectedFiles() > 0))
+ {
+ try
+ {
+ const char *selectedFile = sel->getSelectedFile(0);
+ ifstream input(selectedFile, ios::in | ios::binary | ios::ate);
+ if (!input.is_open()) throw runtime_error("Could not open file.");
+ auto inputSize = input.tellg();
+ auto inputBuf = new unsigned char[(unsigned int)inputSize];
+ input.seekg(0, ios::beg);
+ input.read((char *)inputBuf, inputSize);
+ input.close();
+
+ if (*((unsigned int *)inputBuf) != 0x46464952) throw runtime_error("Input file missing RIFF header.");
+ if (*((unsigned int *)(inputBuf + 4)) != (unsigned int)inputSize - 8) throw runtime_error("Input file contains invalid RIFF header.");
+ if (*((unsigned int *)(inputBuf + 8)) != 0x45564157) throw runtime_error("Input file missing WAVE chunk.");
+
+ if (*((unsigned int *)(inputBuf + 12)) != 0x20746d66) throw runtime_error("Input file missing format sub-chunk.");
+ if (*((unsigned int *)(inputBuf + 16)) != 16) throw runtime_error("Input file is not a PCM waveform.");
+ auto inputFormat = (LPWAVEFORMATEX)(inputBuf + 20);
+ if (inputFormat->wFormatTag != WAVE_FORMAT_PCM) throw runtime_error("Input file is not a PCM waveform.");
+ if (inputFormat->nChannels != 1) throw runtime_error("Input file is not mono.");
+ if (inputFormat->nSamplesPerSec != Specimen::SampleRate) throw runtime_error(("Input file is not " + to_string(Specimen::SampleRate) + "hz.").c_str());
+ if (inputFormat->wBitsPerSample != sizeof(short) * 8) throw runtime_error("Input file is not 16-bit.");
+
+ int chunkPos = 36;
+ int chunkSizeBytes;
+ while (true)
+ {
+ if (chunkPos >= (int)inputSize) throw runtime_error("Input file missing data sub-chunk.");
+ chunkSizeBytes = *((unsigned int *)(inputBuf + chunkPos + 4));
+ if (*((unsigned int *)(inputBuf + chunkPos)) == 0x61746164) break;
+ else chunkPos += 8 + chunkSizeBytes;
+ }
+#ifdef _WIN32
+ int rawDataLength = chunkSizeBytes / 2;
+ auto rawData = new short[rawDataLength];
+ memcpy(rawData, inputBuf + chunkPos + 8, chunkSizeBytes);
+
+ auto compressedData = new char[chunkSizeBytes];
+ int waveFormatSize = 0;
+ acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &waveFormatSize);
+ auto waveFormat = (WAVEFORMATEX *)(new char[waveFormatSize]);
+ memset(waveFormat, 0, waveFormatSize);
+ waveFormat->wFormatTag = WAVE_FORMAT_GSM610;
+ waveFormat->nSamplesPerSec = Specimen::SampleRate;
+
+ ACMFORMATCHOOSE formatChoose;
+ memset(&formatChoose, 0, sizeof(formatChoose));
+ formatChoose.cbStruct = sizeof(formatChoose);
+ formatChoose.pwfx = waveFormat;
+ formatChoose.cbwfx = waveFormatSize;
+ formatChoose.pwfxEnum = waveFormat;
+ formatChoose.fdwEnum = ACM_FORMATENUMF_WFORMATTAG | ACM_FORMATENUMF_NSAMPLESPERSEC;
+
+ if (acmFormatChoose(&formatChoose)) throw runtime_error("acmFormatChoose failed");
+
+ acmDriverEnum(driverEnumCallback, (DWORD_PTR)waveFormat, NULL);
+ HACMDRIVER driver = NULL;
+ if (acmDriverOpen(&driver, driverId, 0)) throw runtime_error("acmDriverOpen failed");
+
+ HACMSTREAM stream = NULL;
+ if (acmStreamOpen(&stream, driver, inputFormat, waveFormat, NULL, NULL, NULL, ACM_STREAMOPENF_NONREALTIME)) throw runtime_error("acmStreamOpen failed");
+
+ ACMSTREAMHEADER streamHeader;
+ memset(&streamHeader, 0, sizeof(streamHeader));
+ streamHeader.cbStruct = sizeof(streamHeader);
+ streamHeader.pbSrc = (LPBYTE)rawData;
+ streamHeader.cbSrcLength = chunkSizeBytes;
+ streamHeader.pbDst = (LPBYTE)compressedData;
+ streamHeader.cbDstLength = chunkSizeBytes;
+ if (acmStreamPrepareHeader(stream, &streamHeader, 0)) throw runtime_error("acmStreamPrepareHeader failed");
+ if (acmStreamConvert(stream, &streamHeader, 0)) throw runtime_error("acmStreamConvert failed");
+
+ delete [] rawData;
+
+ acmStreamClose(stream, 0);
+ acmDriverClose(driver, 0);
+ specimen->LoadSample(compressedData, streamHeader.cbDstLengthUsed, chunkSizeBytes, waveFormat);
+#elif HAVE_LIBGSM
+ int numberOfSamples = chunkSizeBytes / sizeof(gsm_signal);
+ int numberOfPackets = ((numberOfSamples + GSM_MS_PACKET_SIZE - 1) / GSM_MS_PACKET_SIZE);
+ int rawDataLength = GSM_MS_PACKET_SIZE * numberOfPackets;
+ auto rawData = new gsm_signal[rawDataLength];
+ memcpy(rawData, inputBuf + chunkPos + 8, chunkSizeBytes);
+ bzero(rawData + numberOfSamples, sizeof(gsm_signal) * (rawDataLength - numberOfSamples));
+
+ int compressedSize = GSM_MS_BLOCK_SIZE * numberOfPackets;
+ auto compressedData = new gsm_byte[compressedSize];
+ gsm context = gsm_create();
+
+ int one = 1;
+ gsm_option(context, GSM_OPT_WAV49, &one);
+
+ gsm_signal *samples = rawData;
+ gsm_byte *output = compressedData;
+ for (int currentPacket = 0; currentPacket < numberOfPackets; currentPacket++) {
+ gsm_encode(context, samples, output);
+ gsm_encode(context, samples + GSM_PACKET_SIZE, output + 32);
+ samples += GSM_MS_PACKET_SIZE;
+ output += GSM_MS_BLOCK_SIZE;
+ }
+ gsm_destroy(context);
+
+ int waveFormatSize = sizeof(GSMWAVEFORMAT);
+ auto waveFormat = (GSMWAVEFORMAT *)(new char[waveFormatSize]);
+ memset(waveFormat, 0, waveFormatSize);
+ waveFormat->wf.wFormatTag = WAVE_FORMAT_GSM610;
+ waveFormat->wf.nSamplesPerSec = Specimen::SampleRate;
+ waveFormat->wf.nChannels = 1;
+ waveFormat->wf.nAvgBytesPerSec = 8957;
+ waveFormat->wf.nBlockAlign = GSM_MS_BLOCK_SIZE;
+ waveFormat->wf.cbSize = sizeof(GSMWAVEFORMAT) - sizeof(WAVEFORMATEX);
+ waveFormat->wSamplesPerPacket = GSM_MS_PACKET_SIZE;
+
+ delete [] rawData;
+
+ specimen->LoadSample((char *) compressedData, compressedSize, chunkSizeBytes, (WAVEFORMATEX *) waveFormat);
+#else
+#error "Install libgsm so we can GSM encode in Specimen"
+#endif
+ delete [] (char *)waveFormat;
+ delete [] compressedData;
+ delete [] inputBuf;
+ }
+ catch (const exception& e)
+ {
+#ifdef _WIN32
+ MessageBoxA(0, e.what(), "FUCK THAT SHIT", MB_OK | MB_ICONEXCLAMATION);
+#endif
+#ifdef __APPLE__
+ SInt32 nRes = 0;
+ const void* keys[] = {
+ kCFUserNotificationAlertHeaderKey,
+ kCFUserNotificationAlertMessageKey
+ };
+ const void* vals[] = {
+ CFSTR("FUCK THAT SHIT"),
+ CFStringCreateWithCString(kCFAllocatorDefault, e.what(), kCFStringEncodingUTF8)
+ };
+ CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ CFUserNotificationRef notificationRef = CFUserNotificationCreate(kCFAllocatorDefault, 0, kCFUserNotificationPlainAlertLevel, &nRes, dict);
+ CFRelease(notificationRef);
+ CFRelease(dict);
+ CFRelease(vals[1]);
+#endif
+ }
+ }
+ }
}
+#ifdef _WIN32
BOOL __stdcall SpecimenEditor::driverEnumCallback(HACMDRIVERID driverId, DWORD_PTR dwInstance, DWORD fdwSupport)
{
ACMDRIVERDETAILS driverDetails;
@@ -248,3 +328,4 @@ BOOL __stdcall SpecimenEditor::formatEnumCallback(HACMDRIVERID driverId, LPACMFO
return 1;
}
+#endif
diff --git a/Vsts/Specimen/SpecimenEditor.h b/Vsts/Specimen/SpecimenEditor.h
index d9eac7bc..6c33152a 100644
--- a/Vsts/Specimen/SpecimenEditor.h
+++ b/Vsts/Specimen/SpecimenEditor.h
@@ -7,7 +7,9 @@ using namespace WaveSabreVstLib;
#include
using namespace WaveSabreCore;
-class SpecimenEditor : public VstEditor
+#include "vstgui.sf/vstgui/cfileselector.h"
+
+class SpecimenEditor : public VstEditor, public CBaseObject
{
public:
SpecimenEditor(AudioEffect *audioEffect);
@@ -17,17 +19,18 @@ class SpecimenEditor : public VstEditor
virtual void setParameter(VstInt32 index, float value);
+ CMessageResult notify(CBaseObject* sender, const char* message);
+
private:
+#ifdef _WIN32
static BOOL __stdcall driverEnumCallback(HACMDRIVERID driverId, DWORD_PTR dwInstance, DWORD fdwSupport);
static BOOL __stdcall formatEnumCallback(HACMDRIVERID driverId, LPACMFORMATDETAILS formatDetails, DWORD_PTR dwInstance, DWORD fdwSupport);
static HACMDRIVERID driverId;
static WAVEFORMATEX *foundWaveFormat;
-
+#endif
bool pressedTheFuck;
- CFileSelector *fileSelector;
-
Specimen *specimen;
};
diff --git a/Vsts/Thunder/ThunderEditor.cpp b/Vsts/Thunder/ThunderEditor.cpp
index 62f7b816..26c0d9f4 100644
--- a/Vsts/Thunder/ThunderEditor.cpp
+++ b/Vsts/Thunder/ThunderEditor.cpp
@@ -9,18 +9,27 @@ using namespace WaveSabreCore;
#include
using namespace std;
+#ifdef _WIN32
#include
HACMDRIVERID ThunderEditor::driverId = NULL;
WAVEFORMATEX *ThunderEditor::foundWaveFormat = nullptr;
+#endif
+
+#ifdef HAVE_LIBGSM
+#include
+#include
+
+#define GSM_PACKET_SIZE 160
+#define GSM_MS_PACKET_SIZE (GSM_PACKET_SIZE * 2)
+#define GSM_MS_BLOCK_SIZE 65
+#endif
ThunderEditor::ThunderEditor(AudioEffect *audioEffect)
: VstEditor(audioEffect, 140, 80, "THUNDER")
{
pressedTheFuck = false;
- fileSelector = nullptr;
-
thunder = ((ThunderVst *)audioEffect)->GetThunder();
}
@@ -30,8 +39,6 @@ ThunderEditor::~ThunderEditor()
void ThunderEditor::Open()
{
- if (!fileSelector) fileSelector = new CFileSelector(nullptr);
-
addSpacer();
addButton(1000, "LOAD SAMPLE");
addSpacer();
@@ -48,105 +55,183 @@ void ThunderEditor::setParameter(VstInt32 index, float value)
pressedTheFuck = value != 0.0f;
if (pressedTheFuck != oldValue && oldValue)
{
- VstFileSelect vfs;
- memset(&vfs, 0, sizeof(vfs));
- vfs.command = kVstFileLoad;
- vfs.type = kVstFileType;
- if (fileSelector->run(&vfs))
- {
- try
- {
- ifstream input(vfs.returnPath, ios::in | ios::binary | ios::ate);
- if (!input.is_open()) throw exception("Could not open file.");
- auto inputSize = input.tellg();
- auto inputBuf = new unsigned char[(unsigned int)inputSize];
- input.seekg(0, ios::beg);
- input.read((char *)inputBuf, inputSize);
- input.close();
-
- if (*((unsigned int *)inputBuf) != 0x46464952) throw exception("Input file missing RIFF header.");
- if (*((unsigned int *)(inputBuf + 4)) != (unsigned int)inputSize - 8) throw exception("Input file contains invalid RIFF header.");
- if (*((unsigned int *)(inputBuf + 8)) != 0x45564157) throw exception("Input file missing WAVE chunk.");
-
- if (*((unsigned int *)(inputBuf + 12)) != 0x20746d66) throw exception("Input file missing format sub-chunk.");
- if (*((unsigned int *)(inputBuf + 16)) != 16) throw exception("Input file is not a PCM waveform.");
- auto inputFormat = (LPWAVEFORMATEX)(inputBuf + 20);
- if (inputFormat->wFormatTag != WAVE_FORMAT_PCM) throw exception("Input file is not a PCM waveform.");
- if (inputFormat->nChannels != 1) throw exception("Input file is not mono.");
- if (inputFormat->nSamplesPerSec != Thunder::SampleRate) throw exception(("Input file is not " + to_string(Thunder::SampleRate) + "hz.").c_str());
- if (inputFormat->wBitsPerSample != sizeof(short) * 8) throw exception("Input file is not 16-bit.");
-
- int chunkPos = 36;
- int chunkSizeBytes;
- while (true)
- {
- if (chunkPos >= (int)inputSize) throw exception("Input file missing data sub-chunk.");
- chunkSizeBytes = *((unsigned int *)(inputBuf + chunkPos + 4));
- if (*((unsigned int *)(inputBuf + chunkPos)) == 0x61746164) break;
- else chunkPos += 8 + chunkSizeBytes;
- }
- int rawDataLength = chunkSizeBytes / 2;
- auto rawData = new short[rawDataLength];
- memcpy(rawData, inputBuf + chunkPos + 8, chunkSizeBytes);
-
- auto compressedData = new char[chunkSizeBytes];
-
- int waveFormatSize = 0;
- acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &waveFormatSize);
- auto waveFormat = (WAVEFORMATEX *)(new char[waveFormatSize]);
- memset(waveFormat, 0, waveFormatSize);
- waveFormat->wFormatTag = WAVE_FORMAT_GSM610;
- waveFormat->nSamplesPerSec = Thunder::SampleRate;
-
- ACMFORMATCHOOSE formatChoose;
- memset(&formatChoose, 0, sizeof(formatChoose));
- formatChoose.cbStruct = sizeof(formatChoose);
- formatChoose.pwfx = waveFormat;
- formatChoose.cbwfx = waveFormatSize;
- formatChoose.pwfxEnum = waveFormat;
- formatChoose.fdwEnum = ACM_FORMATENUMF_WFORMATTAG | ACM_FORMATENUMF_NSAMPLESPERSEC;
-
- if (acmFormatChoose(&formatChoose)) throw exception("acmFormatChoose failed");
-
- acmDriverEnum(driverEnumCallback, (DWORD_PTR)waveFormat, NULL);
- HACMDRIVER driver = NULL;
- if (acmDriverOpen(&driver, driverId, 0)) throw exception("acmDriverOpen failed");
-
- HACMSTREAM stream = NULL;
- if (acmStreamOpen(&stream, driver, inputFormat, waveFormat, NULL, NULL, NULL, ACM_STREAMOPENF_NONREALTIME)) throw exception("acmStreamOpen failed");
-
- ACMSTREAMHEADER streamHeader;
- memset(&streamHeader, 0, sizeof(streamHeader));
- streamHeader.cbStruct = sizeof(streamHeader);
- streamHeader.pbSrc = (LPBYTE)rawData;
- streamHeader.cbSrcLength = chunkSizeBytes;
- streamHeader.pbDst = (LPBYTE)compressedData;
- streamHeader.cbDstLength = chunkSizeBytes;
- if (acmStreamPrepareHeader(stream, &streamHeader, 0)) throw exception("acmStreamPrepareHeader failed");
- if (acmStreamConvert(stream, &streamHeader, 0)) throw exception("acmStreamConvert failed");
-
- delete [] rawData;
-
- acmStreamClose(stream, 0);
- acmDriverClose(driver, 0);
-
- thunder->LoadSample(compressedData, streamHeader.cbDstLengthUsed, chunkSizeBytes, waveFormat);
-
- delete [] (char *)waveFormat;
-
- delete [] compressedData;
-
- delete [] inputBuf;
- }
- catch (const exception& e)
- {
- MessageBoxA(0, e.what(), "FUCK THAT SHIT", MB_OK | MB_ICONEXCLAMATION);
- }
- }
- }
+ CNewFileSelector* fileSelector =
+ CNewFileSelector::create(getFrame(), CNewFileSelector::kSelectFile);
+ if (fileSelector)
+ {
+ fileSelector->setDefaultExtension(CFileExtension("WAVE", "wav"));
+ fileSelector->setTitle("Choose An Audio File");
+ fileSelector->run(this);
+ fileSelector->forget();
+ }
+ }
+ }
+}
+
+CMessageResult ThunderEditor::notify(CBaseObject* sender, const char* message)
+{
+ if (message == CNewFileSelector::kSelectEndMessage) {
+ CNewFileSelector* sel = dynamic_cast(sender);
+ if (sel && (sel->getNumSelectedFiles() > 0))
+ {
+ try
+ {
+ const char *selectedFile = sel->getSelectedFile(0);
+ ifstream input(selectedFile, ios::in | ios::binary | ios::ate);
+ if (!input.is_open()) throw runtime_error("Could not open file.");
+ auto inputSize = input.tellg();
+ auto inputBuf = new unsigned char[(unsigned int)inputSize];
+ input.seekg(0, ios::beg);
+ input.read((char *)inputBuf, inputSize);
+ input.close();
+
+ if (*((unsigned int *)inputBuf) != 0x46464952) throw runtime_error("Input file missing RIFF header.");
+ if (*((unsigned int *)(inputBuf + 4)) != (unsigned int)inputSize - 8) throw runtime_error("Input file contains invalid RIFF header.");
+ if (*((unsigned int *)(inputBuf + 8)) != 0x45564157) throw runtime_error("Input file missing WAVE chunk.");
+
+ if (*((unsigned int *)(inputBuf + 12)) != 0x20746d66) throw runtime_error("Input file missing format sub-chunk.");
+ if (*((unsigned int *)(inputBuf + 16)) != 16) throw runtime_error("Input file is not a PCM waveform.");
+ auto inputFormat = (LPWAVEFORMATEX)(inputBuf + 20);
+ if (inputFormat->wFormatTag != WAVE_FORMAT_PCM) throw runtime_error("Input file is not a PCM waveform.");
+ if (inputFormat->nChannels != 1) throw runtime_error("Input file is not mono.");
+ if (inputFormat->nSamplesPerSec != Thunder::SampleRate) throw runtime_error(("Input file is not " + to_string(Thunder::SampleRate) + "hz.").c_str());
+ if (inputFormat->wBitsPerSample != sizeof(short) * 8) throw runtime_error("Input file is not 16-bit.");
+
+ int chunkPos = 36;
+ int chunkSizeBytes;
+ while (true)
+ {
+ if (chunkPos >= (int)inputSize) throw runtime_error("Input file missing data sub-chunk.");
+ chunkSizeBytes = *((unsigned int *)(inputBuf + chunkPos + 4));
+ if (*((unsigned int *)(inputBuf + chunkPos)) == 0x61746164) break;
+ else chunkPos += 8 + chunkSizeBytes;
+ }
+#ifdef _WIN32
+ int rawDataLength = chunkSizeBytes / 2;
+ auto rawData = new short[rawDataLength];
+ memcpy(rawData, inputBuf + chunkPos + 8, chunkSizeBytes);
+
+ auto compressedData = new char[chunkSizeBytes];
+
+ int waveFormatSize = 0;
+ acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &waveFormatSize);
+ auto waveFormat = (WAVEFORMATEX *)(new char[waveFormatSize]);
+ memset(waveFormat, 0, waveFormatSize);
+ waveFormat->wFormatTag = WAVE_FORMAT_GSM610;
+ waveFormat->nSamplesPerSec = Thunder::SampleRate;
+
+ ACMFORMATCHOOSE formatChoose;
+ memset(&formatChoose, 0, sizeof(formatChoose));
+ formatChoose.cbStruct = sizeof(formatChoose);
+ formatChoose.pwfx = waveFormat;
+ formatChoose.cbwfx = waveFormatSize;
+ formatChoose.pwfxEnum = waveFormat;
+ formatChoose.fdwEnum = ACM_FORMATENUMF_WFORMATTAG | ACM_FORMATENUMF_NSAMPLESPERSEC;
+
+ if (acmFormatChoose(&formatChoose)) throw runtime_error("acmFormatChoose failed");
+
+ acmDriverEnum(driverEnumCallback, (DWORD_PTR)waveFormat, NULL);
+ HACMDRIVER driver = NULL;
+ if (acmDriverOpen(&driver, driverId, 0)) throw runtime_error("acmDriverOpen failed");
+
+ HACMSTREAM stream = NULL;
+ if (acmStreamOpen(&stream, driver, inputFormat, waveFormat, NULL, NULL, NULL, ACM_STREAMOPENF_NONREALTIME)) throw runtime_error("acmStreamOpen failed");
+
+ ACMSTREAMHEADER streamHeader;
+ memset(&streamHeader, 0, sizeof(streamHeader));
+ streamHeader.cbStruct = sizeof(streamHeader);
+ streamHeader.pbSrc = (LPBYTE)rawData;
+ streamHeader.cbSrcLength = chunkSizeBytes;
+ streamHeader.pbDst = (LPBYTE)compressedData;
+ streamHeader.cbDstLength = chunkSizeBytes;
+ if (acmStreamPrepareHeader(stream, &streamHeader, 0)) throw runtime_error("acmStreamPrepareHeader failed");
+ if (acmStreamConvert(stream, &streamHeader, 0)) throw runtime_error("acmStreamConvert failed");
+
+ delete [] rawData;
+
+ acmStreamClose(stream, 0);
+ acmDriverClose(driver, 0);
+
+ thunder->LoadSample(compressedData, streamHeader.cbDstLengthUsed, chunkSizeBytes, waveFormat);
+#elif HAVE_LIBGSM
+ int numberOfSamples = chunkSizeBytes / sizeof(gsm_signal);
+ int numberOfPackets = ((numberOfSamples + GSM_MS_PACKET_SIZE - 1) / GSM_MS_PACKET_SIZE);
+ int rawDataLength = GSM_MS_PACKET_SIZE * numberOfPackets;
+ auto rawData = new gsm_signal[rawDataLength];
+ memcpy(rawData, inputBuf + chunkPos + 8, chunkSizeBytes);
+ bzero(rawData + numberOfSamples, sizeof(gsm_signal) * (rawDataLength - numberOfSamples));
+
+ int compressedSize = GSM_MS_BLOCK_SIZE * numberOfPackets;
+ auto compressedData = new gsm_byte[compressedSize];
+ gsm context = gsm_create();
+
+ int one = 1;
+ gsm_option(context, GSM_OPT_WAV49, &one);
+
+ gsm_signal *samples = rawData;
+ gsm_byte *output = compressedData;
+ for (int currentPacket = 0; currentPacket < numberOfPackets; currentPacket++) {
+ gsm_encode(context, samples, output);
+ gsm_encode(context, samples + GSM_PACKET_SIZE, output + 32);
+ samples += GSM_MS_PACKET_SIZE;
+ output += GSM_MS_BLOCK_SIZE;
+ }
+ gsm_destroy(context);
+
+ int waveFormatSize = sizeof(GSMWAVEFORMAT);
+ auto waveFormat = (GSMWAVEFORMAT *)(new char[waveFormatSize]);
+ memset(waveFormat, 0, waveFormatSize);
+ waveFormat->wf.wFormatTag = WAVE_FORMAT_GSM610;
+ waveFormat->wf.nSamplesPerSec = Specimen::SampleRate;
+ waveFormat->wf.nChannels = 1;
+ waveFormat->wf.nAvgBytesPerSec = 8957;
+ waveFormat->wf.nBlockAlign = GSM_MS_BLOCK_SIZE;
+ waveFormat->wf.cbSize = sizeof(GSMWAVEFORMAT) - sizeof(WAVEFORMATEX);
+ waveFormat->wSamplesPerPacket = GSM_MS_PACKET_SIZE;
+
+ delete [] rawData;
+
+ thunder->LoadSample((char *) compressedData, compressedSize, chunkSizeBytes, (WAVEFORMATEX *) waveFormat);
+#else
+#error "Install libgsm so we can GSM encode in Thunder"
+#endif
+ delete [] (char *)waveFormat;
+
+ delete [] compressedData;
+
+ delete [] inputBuf;
+ }
+ catch (const exception& e)
+ {
+#ifdef _WIN32
+ MessageBoxA(0, e.what(), "FUCK THAT SHIT", MB_OK | MB_ICONEXCLAMATION);
+#endif
+#ifdef __APPLE__
+ SInt32 nRes = 0;
+ const void* keys[] = {
+ kCFUserNotificationAlertHeaderKey,
+ kCFUserNotificationAlertMessageKey
+ };
+ const void* vals[] = {
+ CFSTR("FUCK THAT SHIT"),
+ CFStringCreateWithCString(kCFAllocatorDefault, e.what(), kCFStringEncodingUTF8)
+ };
+ CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ CFUserNotificationRef notificationRef = CFUserNotificationCreate(kCFAllocatorDefault, 0, kCFUserNotificationPlainAlertLevel, &nRes, dict);
+ CFRelease(notificationRef);
+ CFRelease(dict);
+ CFRelease(vals[1]);
+#endif
+ }
+ }
+ return kMessageNotified;
}
}
+#ifdef _WIN32
BOOL __stdcall ThunderEditor::driverEnumCallback(HACMDRIVERID driverId, DWORD_PTR dwInstance, DWORD fdwSupport)
{
ACMDRIVERDETAILS driverDetails;
@@ -185,3 +270,4 @@ BOOL __stdcall ThunderEditor::formatEnumCallback(HACMDRIVERID driverId, LPACMFOR
return 1;
}
+#endif
diff --git a/Vsts/Thunder/ThunderEditor.h b/Vsts/Thunder/ThunderEditor.h
index 6c2c85c7..a26488a2 100644
--- a/Vsts/Thunder/ThunderEditor.h
+++ b/Vsts/Thunder/ThunderEditor.h
@@ -7,8 +7,9 @@ using namespace WaveSabreVstLib;
#include
using namespace WaveSabreCore;
+#include "vstgui.sf/vstgui/cfileselector.h"
-class ThunderEditor : public VstEditor
+class ThunderEditor : public VstEditor, public CBaseObject
{
public:
ThunderEditor(AudioEffect *audioEffect);
@@ -18,17 +19,18 @@ class ThunderEditor : public VstEditor
virtual void setParameter(VstInt32 index, float value);
+ virtual CMessageResult notify(CBaseObject* sender, const char* message);
+
private:
+#ifdef _WIN32
static BOOL __stdcall driverEnumCallback(HACMDRIVERID driverId, DWORD_PTR dwInstance, DWORD fdwSupport);
static BOOL __stdcall formatEnumCallback(HACMDRIVERID driverId, LPACMFORMATDETAILS formatDetails, DWORD_PTR dwInstance, DWORD fdwSupport);
static HACMDRIVERID driverId;
static WAVEFORMATEX *foundWaveFormat;
-
+#endif
bool pressedTheFuck;
- CFileSelector *fileSelector;
-
Thunder *thunder;
};
diff --git a/WaveSabreCore/CMakeLists.txt b/WaveSabreCore/CMakeLists.txt
index 31ca1e2e..e67acea3 100644
--- a/WaveSabreCore/CMakeLists.txt
+++ b/WaveSabreCore/CMakeLists.txt
@@ -54,7 +54,9 @@ add_library(WaveSabreCore
src/Thunder.cpp
src/Twister.cpp)
-target_link_libraries(WaveSabreCore Msacm32.lib)
+if(WIN32)
+ target_link_libraries(WaveSabreCore Msacm32.lib)
+endif(WIN32)
target_include_directories(WaveSabreCore PUBLIC include)
if(MSVC)
diff --git a/WaveSabreCore/include/WaveSabreCore/Specimen.h b/WaveSabreCore/include/WaveSabreCore/Specimen.h
index 86c3d7ec..9cf67f63 100644
--- a/WaveSabreCore/include/WaveSabreCore/Specimen.h
+++ b/WaveSabreCore/include/WaveSabreCore/Specimen.h
@@ -6,6 +6,7 @@
#include "StateVariableFilter.h"
#include "SamplePlayer.h"
+#ifdef _WIN32
#include
#include
@@ -13,6 +14,12 @@
#define _UNICODE
#endif
#include
+#endif
+
+#ifdef __APPLE__
+#include
+#include "Win32defs.h"
+#endif
namespace WaveSabreCore
{
@@ -99,10 +106,17 @@ namespace WaveSabreCore
float velocity;
};
+#ifdef _WIN32
static BOOL __stdcall driverEnumCallback(HACMDRIVERID driverId, DWORD_PTR dwInstance, DWORD fdwSupport);
static BOOL __stdcall formatEnumCallback(HACMDRIVERID driverId, LPACMFORMATDETAILS formatDetails, DWORD_PTR dwInstance, DWORD fdwSupport);
static HACMDRIVERID driverId;
+#endif
+#ifdef __APPLE__
+ static OSStatus callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
+ AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription,
+ void *inUserData);
+#endif
char *chunkData;
diff --git a/WaveSabreCore/include/WaveSabreCore/Thunder.h b/WaveSabreCore/include/WaveSabreCore/Thunder.h
index 44e5d4b6..583bbc26 100644
--- a/WaveSabreCore/include/WaveSabreCore/Thunder.h
+++ b/WaveSabreCore/include/WaveSabreCore/Thunder.h
@@ -3,6 +3,7 @@
#include "SynthDevice.h"
+#ifdef _WIN32
#include
#include
@@ -10,6 +11,12 @@
#define _UNICODE
#endif
#include
+#endif
+
+#ifdef __APPLE__
+#include
+#include "Win32defs.h"
+#endif
namespace WaveSabreCore
{
@@ -43,11 +50,17 @@ namespace WaveSabreCore
int samplePos;
};
+#ifdef _WIN32
static BOOL __stdcall driverEnumCallback(HACMDRIVERID driverId, DWORD_PTR dwInstance, DWORD fdwSupport);
static BOOL __stdcall formatEnumCallback(HACMDRIVERID driverId, LPACMFORMATDETAILS formatDetails, DWORD_PTR dwInstance, DWORD fdwSupport);
static HACMDRIVERID driverId;
-
+#endif
+#ifdef __APPLE__
+ static OSStatus callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
+ AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription,
+ void *inUserData);
+#endif
char *chunkData;
char *waveFormatData;
diff --git a/WaveSabreCore/include/WaveSabreCore/Win32defs.h b/WaveSabreCore/include/WaveSabreCore/Win32defs.h
new file mode 100644
index 00000000..ebc6326c
--- /dev/null
+++ b/WaveSabreCore/include/WaveSabreCore/Win32defs.h
@@ -0,0 +1,23 @@
+#ifndef __WIN32DEFS_H__
+#define __WIN32DEFS_H__
+
+#define WAVE_FORMAT_PCM 1
+
+typedef struct __attribute__((packed)) {
+ uint16_t wFormatTag;
+ uint16_t nChannels;
+ uint32_t nSamplesPerSec;
+ uint32_t nAvgBytesPerSec;
+ uint16_t nBlockAlign;
+ uint16_t wBitsPerSample;
+ uint16_t cbSize;
+} WAVEFORMATEX, *LPWAVEFORMATEX;
+
+#define WAVE_FORMAT_GSM610 49
+
+typedef struct __attribute__((packed)) {
+ WAVEFORMATEX wf;
+ uint16_t wSamplesPerPacket;
+} GSMWAVEFORMAT;
+
+#endif
diff --git a/WaveSabreCore/src/GmDls.cpp b/WaveSabreCore/src/GmDls.cpp
index 1ca8e566..b02f4933 100644
--- a/WaveSabreCore/src/GmDls.cpp
+++ b/WaveSabreCore/src/GmDls.cpp
@@ -1,17 +1,28 @@
#include
+#ifdef _WIN32
#include
+#endif
+#ifdef __APPLE__
+#include
+#include
+#include
+#endif
+
+#ifdef _WIN32
static char *gmDlsPaths[2] =
{
"drivers/gm.dls",
"drivers/etc/gm.dls"
};
+#endif
namespace WaveSabreCore
{
unsigned char *GmDls::Load()
{
+#ifdef _WIN32
HANDLE gmDlsFile = INVALID_HANDLE_VALUE;
for (int i = 0; gmDlsFile == INVALID_HANDLE_VALUE; i++)
{
@@ -24,7 +35,18 @@ namespace WaveSabreCore
unsigned int bytesRead;
ReadFile(gmDlsFile, gmDls, gmDlsFileSize, (LPDWORD)&bytesRead, NULL);
CloseHandle(gmDlsFile);
-
+#endif
+#ifdef __APPLE__
+ glob_t g;
+ glob("~/Library/Audio/Sounds/Banks/gm.dls", GLOB_TILDE, NULL, &g);
+ FILE *file = fopen(g.gl_pathv[0], "rb");
+ struct stat st;
+ stat(g.gl_pathv[0], &st);
+ unsigned char *gmDls = new unsigned char[st.st_size];
+ fread(gmDls, 1, st.st_size, file);
+ fclose(file);
+ globfree(&g);
+#endif
return gmDls;
}
}
diff --git a/WaveSabreCore/src/Specimen.cpp b/WaveSabreCore/src/Specimen.cpp
index eb0abd88..8bdabd75 100644
--- a/WaveSabreCore/src/Specimen.cpp
+++ b/WaveSabreCore/src/Specimen.cpp
@@ -3,9 +3,17 @@
#include
+#ifdef __APPLE__
+#define GSM_FRAME_SIZE 160
+#define GSM_MS_FRAME_SIZE (GSM_FRAME_SIZE * 2)
+#define GSM_MS_BLOCK_SIZE 65
+#endif
+
namespace WaveSabreCore
{
+#ifdef _WIN32
HACMDRIVERID Specimen::driverId = NULL;
+#endif
Specimen::Specimen()
: SynthDevice(0)
@@ -240,6 +248,7 @@ namespace WaveSabreCore
compressedData = new char[compressedSize];
memcpy(compressedData, data, compressedSize);
+#ifdef _WIN32
acmDriverEnum(driverEnumCallback, NULL, NULL);
HACMDRIVER driver = NULL;
acmDriverOpen(&driver, driverId, 0);
@@ -272,8 +281,50 @@ namespace WaveSabreCore
acmStreamClose(stream, 0);
acmDriverClose(driver, 0);
-
sampleLength = streamHeader.cbDstLengthUsed / sizeof(short);
+#endif
+#ifdef __APPLE__
+ AudioConverterRef converter;
+ AudioStreamBasicDescription inSourceFormat = {0};
+ AudioStreamBasicDescription inDestinationFormat = {0};
+ OSStatus status;
+
+ inSourceFormat.mSampleRate = Specimen::SampleRate;
+ inSourceFormat.mChannelsPerFrame = 1;
+ inSourceFormat.mFormatID = kAudioFormatMicrosoftGSM;
+ inSourceFormat.mBytesPerPacket = 0;
+
+ inDestinationFormat.mFormatID = kAudioFormatLinearPCM;
+ inDestinationFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
+ inDestinationFormat.mFramesPerPacket = 1;
+ inDestinationFormat.mBitsPerChannel = 16;
+ inDestinationFormat.mSampleRate = inSourceFormat.mSampleRate;
+ inDestinationFormat.mChannelsPerFrame = inSourceFormat.mChannelsPerFrame;
+
+ status = AudioConverterNew(&inSourceFormat, &inDestinationFormat, &converter);
+ // TODO: check status.
+
+ char *ptr = compressedData;
+ UInt32 ioOutputDataPacketSize = GSM_MS_FRAME_SIZE * (compressedSize / GSM_MS_BLOCK_SIZE);
+ AudioBufferList outOutputData;
+ outOutputData.mNumberBuffers = 1;
+ outOutputData.mBuffers[0].mNumberChannels = 1;
+ outOutputData.mBuffers[0].mDataByteSize = uncompressedSize;
+ auto uncompressedData = new short[uncompressedSize / 2];
+ outOutputData.mBuffers[0].mData = uncompressedData;
+
+ AudioStreamPacketDescription *outPacketDescription = NULL;
+ status = AudioConverterFillComplexBuffer(converter,
+ callback,
+ &ptr,
+ &ioOutputDataPacketSize,
+ &outOutputData,
+ outPacketDescription);
+ // TODO: check status.
+ AudioConverterReset(converter);
+ AudioConverterDispose(converter);
+ sampleLength = uncompressedSize / 2;
+#endif
if (sampleData) delete [] sampleData;
sampleData = new float[sampleLength];
for (int i = 0; i < sampleLength; i++) sampleData[i] = (float)((double)uncompressedData[i] / 32768.0);
@@ -391,6 +442,7 @@ namespace WaveSabreCore
samplePlayer.CalcPitch(GetNote() - 60 + Detune + specimen->fineTune * 2.0f - 1.0f + SpecimenVoice::coarseDetune(specimen->coarseTune));
}
+#ifdef _WIN32
BOOL __stdcall Specimen::driverEnumCallback(HACMDRIVERID driverId, DWORD_PTR dwInstance, DWORD fdwSupport)
{
if (Specimen::driverId) return 1;
@@ -427,4 +479,20 @@ namespace WaveSabreCore
}
return 1;
}
+#endif
+
+#ifdef __APPLE__
+ OSStatus Specimen::callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
+ AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription,
+ void *inUserData) {
+
+ *ioNumberDataPackets = 1;
+ ioData->mNumberBuffers = 1;
+ ioData->mBuffers[0].mNumberChannels = 1;
+ ioData->mBuffers[0].mDataByteSize = GSM_MS_BLOCK_SIZE;
+ ioData->mBuffers[0].mData = *((u_int8_t **) inUserData);
+ (*(char **) inUserData) += GSM_MS_BLOCK_SIZE;
+ return 0;
+ }
+#endif
}
diff --git a/WaveSabreCore/src/Thunder.cpp b/WaveSabreCore/src/Thunder.cpp
index c40d9094..53673f1c 100644
--- a/WaveSabreCore/src/Thunder.cpp
+++ b/WaveSabreCore/src/Thunder.cpp
@@ -3,9 +3,17 @@
#include
+#ifdef __APPLE__
+#define GSM_FRAME_SIZE 160
+#define GSM_MS_FRAME_SIZE (GSM_FRAME_SIZE * 2)
+#define GSM_MS_BLOCK_SIZE 65
+#endif
+
namespace WaveSabreCore
{
+#ifdef _WIN32
HACMDRIVERID Thunder::driverId = NULL;
+#endif
Thunder::Thunder()
: SynthDevice(0)
@@ -74,6 +82,7 @@ namespace WaveSabreCore
compressedData = new char[compressedSize];
memcpy(compressedData, data, compressedSize);
+#ifdef _WIN32
acmDriverEnum(driverEnumCallback, NULL, NULL);
HACMDRIVER driver = NULL;
acmDriverOpen(&driver, driverId, 0);
@@ -106,8 +115,50 @@ namespace WaveSabreCore
acmStreamClose(stream, 0);
acmDriverClose(driver, 0);
-
sampleLength = streamHeader.cbDstLengthUsed / sizeof(short);
+#endif
+#ifdef __APPLE__
+ AudioConverterRef converter;
+ AudioStreamBasicDescription inSourceFormat = {0};
+ AudioStreamBasicDescription inDestinationFormat = {0};
+ OSStatus status;
+
+ inSourceFormat.mSampleRate = Thunder::SampleRate;
+ inSourceFormat.mChannelsPerFrame = 1;
+ inSourceFormat.mFormatID = kAudioFormatMicrosoftGSM;
+ inSourceFormat.mBytesPerPacket = 0;
+
+ inDestinationFormat.mFormatID = kAudioFormatLinearPCM;
+ inDestinationFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
+ inDestinationFormat.mFramesPerPacket = 1;
+ inDestinationFormat.mBitsPerChannel = 16;
+ inDestinationFormat.mSampleRate = inSourceFormat.mSampleRate;
+ inDestinationFormat.mChannelsPerFrame = inSourceFormat.mChannelsPerFrame;
+
+ status = AudioConverterNew(&inSourceFormat, &inDestinationFormat, &converter);
+ // TODO: check status.
+
+ char *ptr = compressedData;
+ UInt32 ioOutputDataPacketSize = GSM_MS_FRAME_SIZE * (compressedSize / GSM_MS_BLOCK_SIZE);
+ AudioBufferList outOutputData;
+ outOutputData.mNumberBuffers = 1;
+ outOutputData.mBuffers[0].mNumberChannels = 1;
+ outOutputData.mBuffers[0].mDataByteSize = uncompressedSize;
+ auto uncompressedData = new short[uncompressedSize / 2];
+ outOutputData.mBuffers[0].mData = uncompressedData;
+
+ AudioStreamPacketDescription *outPacketDescription = NULL;
+ status = AudioConverterFillComplexBuffer(converter,
+ callback,
+ &ptr,
+ &ioOutputDataPacketSize,
+ &outOutputData,
+ outPacketDescription);
+ // TODO: check status.
+ AudioConverterReset(converter);
+ AudioConverterDispose(converter);
+ sampleLength = uncompressedSize / 2;
+#endif
if (sampleData) delete [] sampleData;
sampleData = new float[sampleLength];
for (int i = 0; i < sampleLength; i++) sampleData[i] = (float)((double)uncompressedData[i] / 32768.0);
@@ -147,6 +198,7 @@ namespace WaveSabreCore
samplePos = 0;
}
+#ifdef _WIN32
BOOL __stdcall Thunder::driverEnumCallback(HACMDRIVERID driverId, DWORD_PTR dwInstance, DWORD fdwSupport)
{
if (Thunder::driverId) return 1;
@@ -183,4 +235,20 @@ namespace WaveSabreCore
}
return 1;
}
+#endif
+
+#ifdef __APPLE__
+ OSStatus Thunder::callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
+ AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription,
+ void *inUserData) {
+
+ *ioNumberDataPackets = 1;
+ ioData->mNumberBuffers = 1;
+ ioData->mBuffers[0].mNumberChannels = 1;
+ ioData->mBuffers[0].mDataByteSize = GSM_MS_BLOCK_SIZE;
+ ioData->mBuffers[0].mData = *((u_int8_t **) inUserData);
+ (*(char **) inUserData) += GSM_MS_BLOCK_SIZE;
+ return 0;
+ }
+#endif
}
diff --git a/WaveSabreVstLib/CMakeLists.txt b/WaveSabreVstLib/CMakeLists.txt
index 330d4d04..26c88ace 100644
--- a/WaveSabreVstLib/CMakeLists.txt
+++ b/WaveSabreVstLib/CMakeLists.txt
@@ -1,3 +1,13 @@
+if(APPLE)
+ set(EXTRA_VSTGUI
+ ${VSTSDK3_DIR}/vstgui.sf/vstgui/cocoasupport.mm
+ ${VSTSDK3_DIR}/vstgui.sf/vstgui/cvstguitimer.cpp)
+endif(APPLE)
+if(MSVC)
+ set(EXTRA_VSTGUI
+ ${VSTSDK3_DIR}/vstgui.sf/vstgui/winfileselector.cpp)
+endif(MSVC)
+
add_library(WaveSabreVstLib STATIC
${VSTSDK3_DIR}/public.sdk/source/vst2.x/audioeffect.cpp
${VSTSDK3_DIR}/public.sdk/source/vst2.x/audioeffectx.cpp
@@ -24,6 +34,7 @@ add_library(WaveSabreVstLib STATIC
${VSTSDK3_DIR}/vstgui.sf/vstgui/vstcontrols.cpp
${VSTSDK3_DIR}/vstgui.sf/vstgui/vstgui.cpp
${VSTSDK3_DIR}/vstgui.sf/vstgui/vstguidebug.cpp
+ ${EXTRA_VSTGUI}
${VSTSDK3_DIR}/vstgui.sf/zlib/adler32.c
${VSTSDK3_DIR}/vstgui.sf/zlib/compress.c
${VSTSDK3_DIR}/vstgui.sf/zlib/crc32.c
@@ -54,7 +65,7 @@ target_include_directories(WaveSabreVstLib PUBLIC
target_compile_definitions(WaveSabreVstLib PUBLIC USE_LIBPNG)
if(MSVC)
- target_compile_definitions(WaveSabreVstLib PUBLIC _CRT_SECURE_NO_WARNINGS)
+ target_compile_definitions(WaveSabreVstLib PUBLIC _CRT_SECURE_NO_WARNINGS VSTGUI_NEW_CFILESELECTOR)
target_compile_options(WaveSabreVstLib PUBLIC /EHsc)
set_source_files_properties(${VSTSDK3_DIR}/vstgui.sf/vstgui/vstgui.cpp
${VSTSDK3_DIR}/vstgui.sf/zlib/minigzip.c
diff --git a/WaveSabreVstLib/src/ImageManager.cpp b/WaveSabreVstLib/src/ImageManager.cpp
index 5fa1f9c7..c174c24b 100644
--- a/WaveSabreVstLib/src/ImageManager.cpp
+++ b/WaveSabreVstLib/src/ImageManager.cpp
@@ -1,7 +1,13 @@
#include
#include
+#ifdef _WIN32
#include "../../Data/resource.h"
+#endif
+
+#ifdef __APPLE__
+#include "../../Data/resourcestr.h"
+#endif
using namespace std;