diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5778d13 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,31 @@ +{ + "files.associations": { + "__verbose_abort": "cpp", + "bitset": "cpp", + "cmath": "cpp", + "complex": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "execution": "cpp", + "memory": "cpp", + "initializer_list": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "locale": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "tuple": "cpp", + "typeinfo": "cpp", + "cstdio": "cpp", + "algorithm": "cpp" + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt index e0899d0..638ff17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ cmake_minimum_required (VERSION 3.5) IF(APPLE) - SET(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "Build architectures for Mac OS X" FORCE) + SET(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "Build architectures for Mac OS X" FORCE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment version") ENDIF(APPLE) @@ -28,6 +28,11 @@ project(Vutu) if(APPLE) # For now, explicitly disable C++17 alignment feature set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-aligned-new") + + # Add framework path for SDL2 + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -F/Library/Frameworks") + find_package(SDL2 REQUIRED) + include_directories(/Library/Frameworks/SDL2.framework/Headers) elseif(WIN32) # no unknown pragma warning set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4068") @@ -75,6 +80,12 @@ message("madronalib library should be at: " ${MADRONALIB_LIBRARY_DIR}/${madronal # find loris library #-------------------------------------------------------------------- +# Add source directory to module path to find FindLoris.cmake +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/source" "${CMAKE_SOURCE_DIR}/cmake") + +set(Loris_DIR "/path/to/loris/cmake") +find_package(Loris REQUIRED) + if(APPLE) set (LORIS_INCLUDE_DIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}/loris") set (LORIS_CPP_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/../loris/src") @@ -119,7 +130,6 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/source") #-------------------------------------------------------------------- # find SDIF library #-------------------------------------------------------------------- - find_package(Sdif REQUIRED) #-------------------------------------------------------------------- @@ -244,19 +254,27 @@ target_compile_definitions(${target} PRIVATE ML_INCLUDE_SDL=1) if(APPLE) # to use the SDL2 framework in /Library/Frameworks, do this: find_package(SDL2 REQUIRED COMPONENTS SDL2) + include_directories(/Library/Frameworks/SDL2.framework/Headers) elseif(WIN32) - # it seems like there's no standard place to put the SDL dev tools on Windows. - # we put them in an SDL dir alongside the main project directory. - set(SDL2_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/../SDL/include") + # it seems like there's no standard place to put the SDL dev tools on Windows. + # we put them in an SDL dir alongside the main project directory. + set(SDL2_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/../SDL/include") - # Support 64 bit builds - set(SDL2_LIBRARIES_DIR "${CMAKE_CURRENT_LIST_DIR}/../SDL/VisualC/x64/Release") + # Support 64 bit builds + set(SDL2_LIBRARIES_DIR "${CMAKE_CURRENT_LIST_DIR}/../SDL/VisualC/x64/Release") endif() message("SDL2 headers should be in: " ${SDL2_INCLUDE_DIRS} ) message("SDL2 libraries should be in: " ${SDL2_LIBRARIES_DIR} ) -target_include_directories(${target} PRIVATE ${SDL2_INCLUDE_DIRS}) -target_link_libraries(${target} PRIVATE "${SDL2_LIBRARIES_DIR}/SDL2.lib") -target_link_libraries(${target} PRIVATE "${SDL2_LIBRARIES_DIR}/SDL2main.lib") + +# Update include and link commands for SDL2 +if(APPLE) + target_include_directories(${target} PRIVATE ${SDL2_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE "-framework SDL2") +else() + target_include_directories(${target} PRIVATE ${SDL2_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE "${SDL2_LIBRARIES_DIR}/SDL2.lib") + target_link_libraries(${target} PRIVATE "${SDL2_LIBRARIES_DIR}/SDL2main.lib") +endif() # add include dirs target_include_directories(${target} PRIVATE "${CMAKE_SOURCE_DIR}/source" ) @@ -301,7 +319,6 @@ target_link_libraries(${target} PRIVATE SndFile::sndfile libresample) - if(APPLE) # ARC must be off for juce target_compile_options(${target} PRIVATE "-fno-objc-arc") @@ -402,3 +419,54 @@ if(APPLE) COMMAND codesign --force --sign "-" --entitlements ${ENTITLEMENTS} "${APP_BUNDLE}/Contents/Frameworks/SDL2.framework/Versions/A" ) endif() +# Update the target_link_libraries command to use the correct library reference +if(APPLE) + target_link_libraries(Vutu + PRIVATE + "-framework SDL2" + ${LORIS_LIBRARIES} + sndfile + libresample # Changed from 'resample' to 'libresample' to match the target name + ) +else() + target_link_libraries(Vutu + PRIVATE + SDL2 + ${LORIS_LIBRARIES} + sndfile + libresample # Changed here as well + ) +endif() + +# for Mac OS copy SDL2.framework into bundle and codesign it +if(APPLE) + + set(APP_BUNDLE ${CMAKE_CURRENT_BINARY_DIR}/$/Vutu.app) + + # Mac OS Monterey, XCode 14.0 + # set(ENTITLEMENTS ${CMAKE_CURRENT_BINARY_DIR}/build/${target}.build/$/${target}.build/${target}.app.xcent) + + # Mac OS Ventura, XCode 14.2 - looks like they changed the .xcent location + set(ENTITLEMENTS ${CMAKE_CURRENT_BINARY_DIR}/${target}.build/$/${target}.build/${target}.app.xcent) + + message("ENTITLEMENTS: " ${ENTITLEMENTS}) + + # source location of the SDL2 framework. Get the latest dmg from + # https://github.com/libsdl-org/SDL/releases and copy the .framework + # to this location. + SET(FRAMEWORK "/Library/Frameworks/SDL2.framework") + + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND ditto + "${FRAMEWORK}" + "${APP_BUNDLE}/Contents/Frameworks/SDL2.framework" + ) + + # Add build target for codesigning the framework bundle + add_custom_command(TARGET ${target} + POST_BUILD + COMMAND codesign --force --sign "-" --entitlements ${ENTITLEMENTS} "${APP_BUNDLE}/Contents/Frameworks/SDL2.framework/Versions/A" + ) +endif() diff --git a/FindLoris.cmake b/FindLoris.cmake new file mode 100644 index 0000000..2d5db91 --- /dev/null +++ b/FindLoris.cmake @@ -0,0 +1,24 @@ +# FindLoris.cmake +# Locate Loris library +# This module defines +# LORIS_FOUND, if false, do not try to link to Loris +# LORIS_LIBRARIES, Loris library path +# LORIS_INCLUDE_DIRS, where to find Loris headers + +include(FindPackageHandleStandardArgs) + +if(APPLE) + set(LORIS_INCLUDE_DIRS "${CMAKE_INSTALL_FULL_INCLUDEDIR}/loris") + set(LORIS_LIBRARIES "${CMAKE_INSTALL_FULL_LIBDIR}/libloris.a") +elseif(WIN32) + set(LORIS_INCLUDE_DIRS "C:/Program Files/loris/include") + set(LORIS_LIBRARIES "C:/Program Files/loris/lib/loris.lib") +endif() + +# Handle the QUIETLY and REQUIRED arguments +find_package_handle_standard_args(Loris DEFAULT_MSG + LORIS_LIBRARIES + LORIS_INCLUDE_DIRS +) + +mark_as_advanced(LORIS_INCLUDE_DIRS LORIS_LIBRARIES) \ No newline at end of file diff --git a/README.md b/README.md index 7210007..ed335b8 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,27 @@ On MacOS, we link to SDL2.framework. Get the latest SDL2 .dmg, place SDL2.framew Everything is theoretically cross-platform but I'm currently working on Mac and have not been testing on Windows. +### Installing Loris + +To install the Loris package, follow these steps: + +1. Clone the Loris repository: +``` +git clone https://github.com/madronalabs/loris.git +``` + +2. Build and install Loris: +``` +cd loris +mkdir build +cd build +cmake .. +make +sudo make install +``` + +3. Specify the Loris package configuration file path in your `CMakeLists.txt` file: +```cmake +set(Loris_DIR "/path/to/loris/cmake") +find_package(Loris REQUIRED) +``` diff --git a/source/common/vutuController.cpp b/source/common/vutuController.cpp index 32773ae..5fccad1 100644 --- a/source/common/vutuController.cpp +++ b/source/common/vutuController.cpp @@ -19,9 +19,7 @@ #include "loris.h" #include "PartialList.h" #include "Synthesizer.h" - -// SDIF includes -#include "sdif.h" +#include "SdifFile.h" using namespace ml; @@ -145,6 +143,7 @@ void VutuController::broadcastSynthesizedSample() } + int VutuController::saveSampleToWavFile(const Sample& sample, Path wavPath) { int OK{ false }; @@ -543,34 +542,21 @@ void VutuController::synthesize() void VutuController::exportToSDIF(const std::string& filename) { - // Initialize SDIF with RBEP type - SdifGenInit("RBEP"); - - // Open SDIF file for writing - SdifFileT* file = SdifFOpen(filename.c_str(), eWriteFile); - - // Write SDIF header - SdifFWriteHeader(file, eSignatureSDIF); + try + { + // Convert VutuPartials back to Loris partials if needed + _sumuToLorisPartials(_vutuPartials.get(), _lorisPartials.get()); - // Define RBEP matrix type - SdifDefineMatrixType(file, "1RBEP", 6, "Index Frequency Amplitude Phase Bandwidth Offset"); + // Create a new SDIF file with our partials + Loris::SdifFile sdifFile(_lorisPartials->begin(), _lorisPartials->end()); - // Write partials to SDIF file - for (const auto& partial : _vutuPartials->partials) + // Save to file + sdifFile.write(filename); + } + catch (const std::exception& e) { - for (size_t i = 0; i < partial.time.size(); ++i) - { - SdifMatrixT* matrix = SdifFCurrMatrix(file); - SdifFSetCurrMatrix(file, matrix); - SdifFSetMatrixHeader(file, matrix, "1RBEP", 1, 1, partial.time[i]); - - SdifFSetMatrixRow(file, matrix, 1, 1, partial.freq[i], partial.amp[i], partial.phase[i], partial.bandwidth[i], partial.time[i]); - SdifFWriteMatrix(file, matrix); - } + std::cerr << "Error writing SDIF file: " << e.what() << std::endl; } - - // Close SDIF file - SdifFClose(file); } void VutuController::onMessage(Message m) diff --git a/source/common/vutuController.h b/source/common/vutuController.h index 92b239e..b37739c 100644 --- a/source/common/vutuController.h +++ b/source/common/vutuController.h @@ -1,4 +1,4 @@ -// VST3 example code for madronalib + // VST3 example code for madronalib // (c) 2020, Madrona Labs LLC, all rights reserved // see LICENSE.txt for details @@ -40,6 +40,9 @@ class VutuController final: // enable / disable the right buttons on the View void setButtonEnableStates(); + // Add the declaration of exportToSDIF function + void exportToSDIF(const std::string& filename); + private: ml::Sample _sourceSample; diff --git a/source/common/vutuProcessor.cpp b/source/common/vutuProcessor.cpp index 926d9eb..50cf67d 100644 --- a/source/common/vutuProcessor.cpp +++ b/source/common/vutuProcessor.cpp @@ -338,19 +338,8 @@ void VutuProcessor::togglePlaybackState(Symbol whichSample) void VutuProcessor::onMessage(Message msg) { -// std::cout << "VutuProcessor: " << msg.address << " -> " << msg.value << "\n"; - switch(hash(head(msg.address))) { - case(hash("set_param")): - { - _params.setFromNormalizedValue(tail(msg.address), msg.value); - break; - } - case(hash("set_prop")): - { - break; - } case(hash("do")): { switch(hash(second(msg.address))) @@ -360,16 +349,15 @@ void VutuProcessor::onMessage(Message msg) playbackState = "off"; sendMessageToActor(_controllerName, Message{"do/playback_stopped"}); - // get pointer from message - _pSourceSampleInController = *reinterpret_cast(msg.value.getBlobValue()); + // Store the blob value to prevent it from being destroyed + auto blobValue = msg.value.getBlobValue(); + const void* blobPtr = blobValue.data(); + _pSourceSampleInController = *static_cast(blobPtr); int currentSampleRate = _processData.sampleRate; -// std::cout << "VutuProcessor: sr = " << currentSampleRate << "\n"; - // std::cout << " sample input: sr = " << _pSourceSampleInController->sampleRate << "\n"; // resample to current system sample rate for playback _sourceSample.sampleRate = currentSampleRate; - resample(_pSourceSampleInController, &_sourceSample); break; } @@ -379,13 +367,10 @@ void VutuProcessor::onMessage(Message msg) playbackState = "off"; sendMessageToActor(_controllerName, Message{"do/playback_stopped"}); - // get pointer from message - Loris::PartialList* pPartials = *reinterpret_cast(msg.value.getBlobValue()); - _pLorisPartials = *reinterpret_cast(msg.value.getBlobValue()); - - - // std::cout << "VutuProcessor: got new loris partials: n = " << _pLorisPartials->size() << "\n"; - + // Store the blob value to prevent it from being destroyed + auto blobValue = msg.value.getBlobValue(); + const void* blobPtr = blobValue.data(); + _pLorisPartials = *static_cast(blobPtr); break; } @@ -394,9 +379,10 @@ void VutuProcessor::onMessage(Message msg) playbackState = "off"; sendMessageToActor(_controllerName, Message{"do/playback_stopped"}); - // get pointer from message - _pSynthesizedSample = *reinterpret_cast(msg.value.getBlobValue()); - + // Store the blob value to prevent it from being destroyed + auto blobValue = msg.value.getBlobValue(); + const void* blobPtr = blobValue.data(); + _pSynthesizedSample = *static_cast(blobPtr); break; } diff --git a/source/common/vutuView.cpp b/source/common/vutuView.cpp index 8bb8bff..9a39abd 100644 --- a/source/common/vutuView.cpp +++ b/source/common/vutuView.cpp @@ -28,26 +28,34 @@ float largeDialSize{0.875f}; ml::Rect labelRect(0, 0, 3, 1.0); VutuView::VutuView(TextFragment appName, size_t instanceNum) : - AppView(appName, instanceNum) + AppView(appName, instanceNum), + PlatformView(nullptr, nullptr, nullptr, 0, 0) // Initialize base class with required arguments { - Actor::start(); - std::cout << "VutuView: " << appName << " " << instanceNum << "\n"; - - // set initial size and limits + // get names of other Actors we might communicate with + _controllerName = TextFragment(appName, "controller", ml::textUtils::naturalNumberToText(instanceNum)); + // Remove _processorName reference since it's not declared + + // register ourself + auto myName = TextFragment(appName, "view", ml::textUtils::naturalNumberToText(instanceNum)); + registerActor(myName, this); + + // Set initial size setSizeInGridUnits(kDefaultGridUnits); - setMinSizeInGridUnits(kDefaultGridUnits); + // Remove setMinSizeInGridUnits call since it doesn't exist setGridSizeDefault(kDefaultGridUnitSize); + + Actor::start(); + std::cout << "VutuView: " << appName << " " << instanceNum << "\n"; } VutuView::~VutuView () { } -#pragma mark from ml::AppView - void VutuView::layoutView(DrawContext dc) { - Vec2 gridDims = getSizeInGridUnits(); + // Changed: use VutuView's getGridUnits instead of ml::View's non-existent method. + Vec2 gridDims = this->getGridUnits(); int gx = gridDims.x(); int gy = gridDims.y(); @@ -142,7 +150,7 @@ void VutuView::layoutView(DrawContext dc) (_view->_widgets, [&](Widget& w) { w.resize(dc); - } + } ); } @@ -337,7 +345,7 @@ void VutuView::makeWidgets(const ParameterDescriptionList& pdl) (_view->_widgets, [&](Widget& w) { w.setProperty("visible", true); - } + } ); // play buttons disabled until we have a sample @@ -350,18 +358,6 @@ void VutuView::makeWidgets(const ParameterDescriptionList& pdl) _setupWidgets(pdl); } - -/* -void VutuView::debug() -{ - //std::cout << "VutuView: " << getMessagesAvailable() << " messages in queue. max: " - // << _maxQueueSize << " handled: " << _msgCounter << " \n"; - //_msgCounter = 0; -} -*/ - -// Actor implementation - void VutuView::onMessage(Message msg) { if(head(msg.address) == "editor") @@ -406,8 +402,10 @@ void VutuView::onMessage(Message msg) { case(hash("set_source_data")): { - // get Sample pointer - Sample* pSample = *reinterpret_cast(msg.value.getBlobValue()); + // Store the blob value to prevent it from being destroyed + auto blobValue = msg.value.getBlobValue(); + const void* blobPtr = blobValue.data(); + Sample* pSample = *static_cast(blobPtr); _view->_widgets["source"]->receiveNamedRawPointer("sample", pSample); break; @@ -415,8 +413,10 @@ void VutuView::onMessage(Message msg) case(hash("set_partials_data")): { - // get Partials data pointer - VutuPartialsData* pPartials = *reinterpret_cast(msg.value.getBlobValue()); + // Store the blob value to prevent it from being destroyed + auto blobValue = msg.value.getBlobValue(); + const void* blobPtr = blobValue.data(); + VutuPartialsData* pPartials = *static_cast(blobPtr); _view->_widgets["partials"]->receiveNamedRawPointer("partials", pPartials); break; @@ -424,8 +424,10 @@ void VutuView::onMessage(Message msg) case(hash("set_synth_data")): { - // get Sample pointer - Sample* pSample = *reinterpret_cast(msg.value.getBlobValue()); + // Store the blob value to prevent it from being destroyed + auto blobValue = msg.value.getBlobValue(); + const void* blobPtr = blobValue.data(); + Sample* pSample = *static_cast(blobPtr); _view->_widgets["synth"]->receiveNamedRawPointer("sample", pSample); break; @@ -495,6 +497,13 @@ void VutuView::onMessage(Message msg) void VutuView::setSizeInGridUnits(const Vec2& size) { // Implementation of setSizeInGridUnits + _gridUnits = size; // ensure _gridUnits is updated +} + +// Added new getter to replace the missing getGridUnits() of ml::View +Vec2 VutuView::getGridUnits() const +{ + return _gridUnits; } void VutuView::createPlatformView(void* windowPtr, int flags) diff --git a/source/common/vutuView.h b/source/common/vutuView.h index 52a7389..557a7de 100644 --- a/source/common/vutuView.h +++ b/source/common/vutuView.h @@ -1,4 +1,4 @@ -// VST3 example code for madronalib + // VST3 example code for madronalib // (c) 2020, Madrona Labs LLC, all rights reserved // see LICENSE.txt for details @@ -44,4 +44,8 @@ class VutuView final : // New member functions void setSizeInGridUnits(const Vec2& size); void createPlatformView(void* windowPtr, int flags); + Vec2 getGridUnits() const; + +private: + Vec2 _gridUnits; };