Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VST support for macOS. #70

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions .appveyor.yml
Original file line number Diff line number Diff line change
@@ -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

5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
34 changes: 34 additions & 0 deletions Data/Info.plist.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
</dict>
</plist>
7 changes: 7 additions & 0 deletions Data/resourcestr.h
Original file line number Diff line number Diff line change
@@ -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"
26 changes: 26 additions & 0 deletions Data/vstgui.patch
Original file line number Diff line number Diff line change
@@ -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 <QuickTime/QuickTime.h>
+#include <Carbon/Carbon.h>
#include <CoreServices/CoreServices.h>

#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
66 changes: 58 additions & 8 deletions Vsts/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
291 changes: 186 additions & 105 deletions Vsts/Specimen/SpecimenEditor.cpp
Original file line number Diff line number Diff line change
@@ -9,18 +9,27 @@ using namespace WaveSabreCore;
#include <exception>
using namespace std;

#ifdef _WIN32
#include <Windows.h>

HACMDRIVERID SpecimenEditor::driverId = NULL;
WAVEFORMATEX *SpecimenEditor::foundWaveFormat = nullptr;
#endif

#ifdef HAVE_LIBGSM
#include <WaveSabreCore/Win32defs.h>
#include <gsm.h>

#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<CNewFileSelector*>(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
11 changes: 7 additions & 4 deletions Vsts/Specimen/SpecimenEditor.h
Original file line number Diff line number Diff line change
@@ -7,7 +7,9 @@ using namespace WaveSabreVstLib;
#include <WaveSabreCore.h>
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;
};

286 changes: 186 additions & 100 deletions Vsts/Thunder/ThunderEditor.cpp
Original file line number Diff line number Diff line change
@@ -9,18 +9,27 @@ using namespace WaveSabreCore;
#include <exception>
using namespace std;

#ifdef _WIN32
#include <Windows.h>

HACMDRIVERID ThunderEditor::driverId = NULL;
WAVEFORMATEX *ThunderEditor::foundWaveFormat = nullptr;
#endif

#ifdef HAVE_LIBGSM
#include <WaveSabreCore/Win32defs.h>
#include <gsm.h>

#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<CNewFileSelector*>(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
10 changes: 6 additions & 4 deletions Vsts/Thunder/ThunderEditor.h
Original file line number Diff line number Diff line change
@@ -7,8 +7,9 @@ using namespace WaveSabreVstLib;
#include <WaveSabreCore.h>
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;
};

4 changes: 3 additions & 1 deletion WaveSabreCore/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
14 changes: 14 additions & 0 deletions WaveSabreCore/include/WaveSabreCore/Specimen.h
Original file line number Diff line number Diff line change
@@ -6,13 +6,20 @@
#include "StateVariableFilter.h"
#include "SamplePlayer.h"

#ifdef _WIN32
#include <Windows.h>
#include <mmreg.h>

#ifdef UNICODE
#define _UNICODE
#endif
#include <MSAcm.h>
#endif

#ifdef __APPLE__
#include <AudioToolbox/AudioToolbox.h>
#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;

15 changes: 14 additions & 1 deletion WaveSabreCore/include/WaveSabreCore/Thunder.h
Original file line number Diff line number Diff line change
@@ -3,13 +3,20 @@

#include "SynthDevice.h"

#ifdef _WIN32
#include <Windows.h>
#include <mmreg.h>

#ifdef UNICODE
#define _UNICODE
#endif
#include <MSAcm.h>
#endif

#ifdef __APPLE__
#include <AudioToolbox/AudioToolbox.h>
#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;
23 changes: 23 additions & 0 deletions WaveSabreCore/include/WaveSabreCore/Win32defs.h
Original file line number Diff line number Diff line change
@@ -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
24 changes: 23 additions & 1 deletion WaveSabreCore/src/GmDls.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
#include <WaveSabreCore/GmDls.h>

#ifdef _WIN32
#include <Windows.h>
#endif

#ifdef __APPLE__
#include <sys/stat.h>
#include <CoreFoundation/CoreFoundation.h>
#include <glob.h>
#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;
}
}
70 changes: 69 additions & 1 deletion WaveSabreCore/src/Specimen.cpp
Original file line number Diff line number Diff line change
@@ -3,9 +3,17 @@

#include <math.h>

#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
}
70 changes: 69 additions & 1 deletion WaveSabreCore/src/Thunder.cpp
Original file line number Diff line number Diff line change
@@ -3,9 +3,17 @@

#include <math.h>

#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
}
13 changes: 12 additions & 1 deletion WaveSabreVstLib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions WaveSabreVstLib/src/ImageManager.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
#include <WaveSabreVstLib/ImageManager.h>
#include <WaveSabreVstLib/Common.h>

#ifdef _WIN32
#include "../../Data/resource.h"
#endif

#ifdef __APPLE__
#include "../../Data/resourcestr.h"
#endif

using namespace std;