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

Switch to statically-linked cmake build #32

Merged
merged 23 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5ecc6c7
start making CMake build
Birch-san Dec 28, 2021
8f6baf8
start effort to statically-link with fluidsynth
Birch-san Dec 29, 2021
469fd19
documented failed effort to do multi-arch build (we shouldn't smash t…
Birch-san Dec 29, 2021
f952e0e
conditionally support dynamic libraries, position independent code
Birch-san Dec 29, 2021
90f5abb
start making our own FindPkgConfig to add support for static targets,…
Birch-san Dec 30, 2021
20b1cfc
Update FindPkgConfig to create a target with _LINK_LIBRARIES variable…
Birch-san Dec 30, 2021
6fb41f5
simplify FindPkgConfig, set _LINK_LIBRARIES variables correctly
Birch-san Dec 30, 2021
d7a7420
parameterize static/dynamic build, add logo, delete unused stuff.
Birch-san Dec 30, 2021
cb55fe8
ignore Finder metadata
Birch-san Dec 30, 2021
de56d7d
source-control juce_header, for better IDE experience
Birch-san Dec 30, 2021
ba9f978
AU loading in Garageband, FL Studio (albeit with horrid noise). VST2+…
Birch-san Dec 30, 2021
64963b6
fill in metadata
Birch-san Dec 30, 2021
dd9f481
tried external VST3 SDK, but lacked arm64 symbol for VST3::StringConv…
Birch-san Dec 30, 2021
b490b24
delete instructions for dead-end which didn't help
Birch-san Dec 30, 2021
a43d69a
comment
Birch-san Dec 30, 2021
eef87c9
some refactors on FindPkgConfig. and a fix for dynamic library lookup
Birch-san Jan 1, 2022
57f7b18
build Universal Binary (not a very idiomatic way, but the dependencie…
Birch-san Jan 1, 2022
871dcb7
zero out incoming audio buffer (this has become necessary for AU plug…
Birch-san Jan 1, 2022
dd6a9cd
build AUv3. ask for filesystem access. not sure if we count as sandbo…
Birch-san Jan 1, 2022
da0393d
include CoreFoundation helpers, attempt to make bookmark upon picking…
Birch-san Jan 2, 2022
ed8ddbe
make soundfonts load correctly inside macOS sandbox
Birch-san Jan 2, 2022
af7e90d
XCode generator considers build type to be a config concern instead
Birch-san Jan 2, 2022
ca73d73
code-signing
Birch-san Jan 3, 2022
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.vscode
.vscode
/build/
.DS_Store
192 changes: 192 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# cmake -B build -DCMAKE_INSTALL_PREFIX="$HOME/juicydeps" -DCMAKE_BUILD_TYPE=Debug
# cmake --build build

# To get started on a new plugin, copy this entire folder (containing this file and C++ sources) to
# a convenient location, and then start making modifications.

# The first line of any CMake project should be a call to `cmake_minimum_required`, which checks
# that the installed CMake will be able to understand the following CMakeLists, and ensures that
# CMake's behaviour is compatible with the named version. This is a standard CMake command, so more
# information can be found in the CMake docs.

cmake_minimum_required(VERSION 3.15)

# The top-level CMakeLists.txt file for a project must contain a literal, direct call to the
# `project()` command. `project()` sets up some helpful variables that describe source/binary
# directories, and the current project version. This is a standard CMake command.

project(JUICY_SF_PLUGIN VERSION 3.0.0)

# If you've installed JUCE somehow (via a package manager, or directly using the CMake install
# target), you'll need to tell this project that it depends on the installed copy of JUCE. If you've
# included JUCE directly in your source tree (perhaps as a submodule), you'll need to tell CMake to
# include that subdirectory as part of the build.

find_package(JUCE CONFIG REQUIRED) # If you've installed JUCE to your system
# or
# add_subdirectory(JUCE) # If you've put JUCE in a subdirectory called JUCE

# default to static libraries, since distribution is easier
option(BUILD_SHARED_LIBS "Build using shared libraries" off)
set(VST2_SDK_PATH "" CACHE STRING "VST2 SDK path")

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
find_package(PkgConfig REQUIRED)

if (BUILD_SHARED_LIBS)
set(TARGET_STATIC_QUALIFIER "")
else (BUILD_SHARED_LIBS)
set(TARGET_STATIC_QUALIFIER "-static")
endif (BUILD_SHARED_LIBS)

set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH off)
pkg_search_module(FLUIDSYNTH REQUIRED IMPORTED_TARGET fluidsynth>=2)
set(FLUIDSYNTH_TARGET "PkgConfig::FLUIDSYNTH${TARGET_STATIC_QUALIFIER}")

if (EXTRA_ARCH_PKG_CONFIG_PATH)
set(ENV{PKG_CONFIG_PATH} "${EXTRA_ARCH_PKG_CONFIG_PATH}")
pkg_search_module(EXTRA_ARCH_FLUIDSYNTH REQUIRED IMPORTED_TARGET fluidsynth>=2)
set(EXTRA_ARCH_FLUIDSYNTH_TARGET "PkgConfig::EXTRA_ARCH_FLUIDSYNTH${TARGET_STATIC_QUALIFIER}")
endif (EXTRA_ARCH_PKG_CONFIG_PATH)

set(VST_COPY_DIR "${JUCE_VST_COPY_DIR}" CACHE STRING "VST2 installation dir")
set(VST3_COPY_DIR "${JUCE_VST3_COPY_DIR}" CACHE STRING "VST3 installation dir")
set(AU_COPY_DIR "${JUCE_AU_COPY_DIR}" CACHE STRING "AU installation dir")

# If you are building a VST2 or AAX plugin, CMake needs to be told where to find these SDKs on your
# system. This setup should be done before calling `juce_add_plugin`.

if (VST2_SDK_PATH)
set(HAS_VST2_SDK_PATH 1)
juce_set_vst2_sdk_path(${VST2_SDK_PATH})
else (VST2_SDK_PATH)
set(HAS_VST2_SDK_PATH 0)
endif (VST2_SDK_PATH)

if (VST3_SDK_PATH)
juce_set_vst3_sdk_path(${VST3_SDK_PATH})
endif (VST3_SDK_PATH)

# juce_set_aax_sdk_path(...)

# `juce_add_plugin` adds a static library target with the name passed as the first argument
# (AudioPluginExample here). This target is a normal CMake target, but has a lot of extra properties set
# up by default. As well as this shared code static library, this function adds targets for each of
# the formats specified by the FORMATS arguments. This function accepts many optional arguments.
# Check the readme at `docs/CMake API.md` in the JUCE repo for the full list.

# building of AUv3 requires -DCMAKE_GENERATOR=Xcode or -GXcode
# and your "XCode > Preferences > Locations > Command Line Tools" set to "XCode"
# otherwise you'll get error:
# Run Build Command(s):/usr/bin/xcodebuild -project CMAKE_TRY_COMPILE.xcodeproj build -target cmTC_33f26 -parallelizeTargets -configuration Debug -hideShellScriptEnvironment && xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

# we almost support sandboxing (com.apple.security.files.user-selected.read-only is sufficient for picking a soundfont),
# but when you re-open the plugin we fail to re-open the file (whose path we saved).
# the correct way to support Sandboxing is to create a security-scoped bookmark after the user selects a file, and then load soundfont from that location in future.
# but I don't know how to do this from C++ (and don't know how we would serialize the bookmark to save it for next use).
# you could solve this by requesting temporary-exception.files.all.read entitlement,
# but then XCode asks you to provide a provisioning profile (I don't have one; haven't purchased an Apple Developer account).
# https://developer.apple.com/library/archive/technotes/tn2247/_index.html
# https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html

# https://github.com/juce-framework/JUCE/blob/master/docs/CMake%20API.md
juce_add_plugin(JuicySFPlugin
# VERSION ... # Set this if the plugin version is different to the project version
ICON_BIG resources/Logo512.png # ICON_* arguments specify a path to an image file to use as an icon for the Standalone
# ICON_SMALL ...
COMPANY_NAME Birchlabs # Specify the name of the plugin's author
COMPANY_WEBSITE "https://birchlabs.co.uk"
DESCRIPTION "Audio plugin to play soundfonts"
IS_SYNTH TRUE # Is this a synth or an effect?
NEEDS_MIDI_INPUT TRUE # Does the plugin need midi input?
NEEDS_MIDI_OUTPUT FALSE # Does the plugin need midi output?
IS_MIDI_EFFECT FALSE # Is this plugin a MIDI effect?
EDITOR_WANTS_KEYBOARD_FOCUS TRUE # Does the editor need keyboard focus?
COPY_PLUGIN_AFTER_BUILD TRUE # Should the plugin be installed to a default location after building?
APP_SANDBOX_ENABLED TRUE
APP_SANDBOX_OPTIONS com.apple.security.files.user-selected.read-only
HARDENED_RUNTIME_ENABLED TRUE
VST2_CATEGORY kPlugCategSynth
VST3_CATEGORIES Instrument Synth
AU_MAIN_TYPE kAudioUnitType_MusicDevice
AU_SANDBOX_SAFE TRUE
PLUGIN_MANUFACTURER_CODE Blbs # A four-character manufacturer id with at least one upper-case character
PLUGIN_CODE Jsfp # A unique four-character plugin id with exactly one upper-case character
# GarageBand 10.3 requires the first letter to be upper-case, and the remaining letters to be lower-case
FORMATS AU AUv3 VST VST3 Standalone # The formats to build. Other valid formats are: AAX Unity VST AU AUv3
VST_COPY_DIR "${VST_COPY_DIR}"
VST3_COPY_DIR "${VST3_COPY_DIR}"
AU_COPY_DIR "${AU_COPY_DIR}"
PRODUCT_NAME "juicysfplugin") # The name of the final executable, which can differ from the target name

# https://cmake.org/cmake/help/latest/guide/tutorial/Selecting%20Static%20or%20Shared%20Libraries.html
set_target_properties(JuicySFPlugin PROPERTIES
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS})

# `juce_generate_juce_header` will create a JuceHeader.h for a given target, which will be generated
# into your build tree. This should be included with `#include <JuceHeader.h>`. The include path for
# this header will be automatically added to the target. The main function of the JuceHeader is to
# include all your JUCE module headers; if you're happy to include module headers directly, you
# probably don't need to call this.

# juce_generate_juce_header(JuicySFPlugin)

# `target_sources` adds source files to a target. We pass the target that needs the sources as the
# first argument, then a visibility parameter for the sources which should normally be PRIVATE.
# Finally, we supply a list of source files that will be built into the target. This is a standard
# CMake command.

add_subdirectory(Source)

# `target_compile_definitions` adds some preprocessor definitions to our target. In a Projucer
# project, these might be passed in the 'Preprocessor Definitions' field. JUCE modules also make use
# of compile definitions to switch certain features on/off, so if there's a particular feature you
# need that's not on by default, check the module header for the correct flag to set here. These
# definitions will be visible both to your code, and also the JUCE module code, so for new
# definitions, pick unique names that are unlikely to collide! This is a standard CMake command.

target_compile_definitions(JuicySFPlugin
PUBLIC
# JUCE_WEB_BROWSER and JUCE_USE_CURL would be on by default, but you might not need them.
JUCE_WEB_BROWSER=0 # If you remove this, add `NEEDS_WEB_BROWSER TRUE` to the `juce_add_plugin` call
JUCE_USE_CURL=0 # If you remove this, add `NEEDS_CURL TRUE` to the `juce_add_plugin` call
# JUCE_CORE_INCLUDE_OBJC_HELPERS=1
DONT_SET_USING_JUCE_NAMESPACE=1
JUCE_VST3_CAN_REPLACE_VST2=${HAS_VST2_SDK_PATH})

# If your target needs extra binary assets, you can add them here. The first argument is the name of
# a new static library target that will include all the binary resources. There is an optional
# `NAMESPACE` argument that can specify the namespace of the generated binary data class. Finally,
# the SOURCES argument should be followed by a list of source files that should be built into the
# static library. These source files can be of any kind (wav data, images, fonts, icons etc.).
# Conversion to binary-data will happen when your target is built.

# juce_add_binary_data(AudioPluginData SOURCES ...)

# `target_link_libraries` links libraries and JUCE modules to other libraries or executables. Here,
# we're linking our executable target to the `juce::juce_audio_utils` module. Inter-module
# dependencies are resolved automatically, so `juce_core`, `juce_events` and so on will also be
# linked automatically. If we'd generated a binary data target above, we would need to link to it
# here too. This is a standard CMake command.

target_link_libraries(JuicySFPlugin
PRIVATE
# AudioPluginData # If we'd created a binary data target, we'd link to it here
juce::juce_audio_basics
juce::juce_audio_devices
juce::juce_audio_formats
juce::juce_audio_plugin_client
juce::juce_audio_processors
juce::juce_audio_utils
juce::juce_core
juce::juce_data_structures
juce::juce_events
juce::juce_graphics
juce::juce_gui_basics
juce::juce_gui_extra
${FLUIDSYNTH_TARGET}
${EXTRA_ARCH_FLUIDSYNTH_TARGET}
PUBLIC
juce::juce_recommended_config_flags
juce::juce_recommended_lto_flags
juce::juce_recommended_warning_flags)
77 changes: 64 additions & 13 deletions JuceLibraryCode/JuceHeader.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/*

IMPORTANT! This file is auto-generated each time you save your
project - if you alter its contents, your changes may be overwritten!
IMPORTANT! This file is auto-generated.
If you alter its contents, your changes may be overwritten!

This is the header file that your files should include in order to get all the
JUCE library headers. You should avoid including the JUCE headers directly in
Expand All @@ -12,34 +11,86 @@

#pragma once

#include "AppConfig.h"

#include <juce_audio_basics/juce_audio_basics.h>
#include <juce_core/juce_core.h>
#include <juce_audio_devices/juce_audio_devices.h>
#include <juce_events/juce_events.h>
#include <juce_audio_formats/juce_audio_formats.h>
#include <juce_audio_plugin_client/juce_audio_plugin_client.h>
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_audio_utils/juce_audio_utils.h>
#include <juce_core/juce_core.h>
#include <juce_data_structures/juce_data_structures.h>
#include <juce_events/juce_events.h>
#include <juce_graphics/juce_graphics.h>
#include <juce_gui_basics/juce_gui_basics.h>
#include <juce_gui_extra/juce_gui_extra.h>
#include <juce_gui_basics/juce_gui_basics.h>
#include <juce_graphics/juce_graphics.h>
#include <juce_data_structures/juce_data_structures.h>
#include <juce_audio_utils/juce_audio_utils.h>


#if JUCE_TARGET_HAS_BINARY_DATA
#include "BinaryData.h"
#endif

#if ! DONT_SET_USING_JUCE_NAMESPACE
// If your code uses a lot of JUCE classes, then this will obviously save you
// a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE.
using namespace juce;
#endif

using juce::AudioBuffer;
using juce::AudioChannelSet;
using juce::AudioParameterInt;
using juce::AudioProcessor;
using juce::AudioProcessorEditor;
using juce::AudioProcessorParameterWithID;
using juce::AudioProcessorValueTreeState;
using juce::BorderSize;
using juce::Button;
using juce::Colour;
using juce::Component;
using juce::dontSendNotification;
using juce::File;
using juce::FilenameComponent;
using juce::FilenameComponentListener;
using juce::Font;
using juce::Graphics;
using juce::GroupComponent;
using juce::Identifier;
using juce::jmax;
using juce::Justification;
using juce::KeyPress;
using juce::Label;
using juce::ListBox;
using juce::Logger;
using juce::LookAndFeel_V4;
using juce::LookAndFeel;
using juce::MemoryBlock;
using juce::MessageManagerLock;
using juce::MidiBuffer;
using juce::MidiKeyboardState;
using juce::MidiMessage;
using juce::NotificationType;
using juce::RangedAudioParameter;
using juce::Rectangle;
using juce::ResizableWindow;
using juce::Slider;
using juce::String;
using juce::StringArray;
using juce::StringRef;
using juce::Synthesiser;
using juce::TableHeaderComponent;
using juce::TableListBox;
using juce::TableListBoxModel;
using juce::TextButton;
using juce::Value;
using juce::ValueTree;
using juce::var;
using juce::XmlElement;

#if ! JUCE_DONT_DECLARE_PROJECTINFO
namespace ProjectInfo
{
const char* const projectName = "juicysfplugin";
const char* const companyName = "Birchlabs";
const char* const versionString = "1.0.0";
const int versionNumber = 0x10000;
const char* const versionString = "3.0.0";
const int versionNumber = 0x30000;
}
#endif
12 changes: 12 additions & 0 deletions Source/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
target_sources(JuicySFPlugin
PRIVATE
FilePicker.cpp
FluidSynthModel.cpp
MyColours.cpp
Pills.cpp
PluginEditor.cpp
PluginProcessor.cpp
SlidersComponent.cpp
SurjectiveMidiKeyboardComponent.cpp
TableComponent.cpp
TablesComponent.cpp)
38 changes: 37 additions & 1 deletion Source/FilePicker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
#include "MyColours.h"
#include "Util.h"

// #ifdef __APPLE__
// #include <CoreFoundation/CFURL.h>
// #endif
#if JUCE_MAC || JUCE_IOS
#include <juce_core/native/juce_mac_CFHelpers.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFData.h>
#include <CoreFoundation/CFError.h>
using juce::CFUniquePtr;
#endif

FilePicker::FilePicker(
AudioProcessorValueTreeState& valueTreeState
// FluidSynthModel& fluidSynthModel
Expand All @@ -22,6 +33,9 @@ FilePicker::FilePicker(
, valueTreeState{valueTreeState}
// , fluidSynthModel{fluidSynthModel}
// , currentPath{}
#if JUCE_MAC || JUCE_IOS
, bookmarkCreationOptions{kCFURLBookmarkCreationWithSecurityScope}
#endif
{
// faster (rounded edges introduce transparency)
setOpaque (true);
Expand All @@ -33,6 +47,10 @@ FilePicker::FilePicker(
fileChooser.addListener (this);
valueTreeState.state.addListener(this);
// valueTreeState.state.getChildWithName("soundFont").sendPropertyChangeMessage("path");

#if JUCE_MAC || JUCE_IOS
bookmarkCreationOptions |= kCFURLBookmarkCreationSecurityScopeAllowOnlyReadAccess;
#endif
}
FilePicker::~FilePicker() {
fileChooser.removeListener (this);
Expand All @@ -49,10 +67,28 @@ void FilePicker::resized() {
*/
void FilePicker::paint(Graphics& g)
{
g.fillAll(MyColours::getUIColourIfAvailable(LookAndFeel_V4::ColourScheme::UIColour::windowBackground, Colours::lightgrey));
g.fillAll(MyColours::getUIColourIfAvailable(LookAndFeel_V4::ColourScheme::UIColour::windowBackground, juce::Colours::lightgrey));
}

void FilePicker::filenameComponentChanged (FilenameComponent*) {
#if JUCE_MAC || JUCE_IOS
CFUniquePtr<CFStringRef> fileExtensionCF{fileChooser.getCurrentFile().getFullPathName().toCFString()};
CFUniquePtr<CFURLRef> cfURL{CFURLCreateWithFileSystemPath(NULL, fileExtensionCF.get(), CFURLPathStyle::kCFURLPOSIXPathStyle, false)};
CFErrorRef* cfError;

// CFURLCreateBookmarkData causes this error:
// cannot open file at line 45340 of [d24547a13b]
// os_unix.c:45340: (0) open(/var/db/DetachedSignatures) - Undefined error: 0
CFUniquePtr<CFDataRef> cfData{CFURLCreateBookmarkData(NULL, cfURL.get(), bookmarkCreationOptions, NULL, NULL, cfError)};

const UInt8 * cfDataBytePtr{CFDataGetBytePtr(cfData.get())};
CFIndex cfDataByteLength{CFDataGetLength(cfData.get())};
{
Value value{valueTreeState.state.getChildWithName("soundFont").getPropertyAsValue("bookmark", nullptr)};
var var{static_cast<const void*>(cfDataBytePtr), static_cast<size_t>(cfDataByteLength)};
value.setValue(var);
}
#endif
// currentPath = fileChooser.getCurrentFile().getFullPathName();
// fluidSynthModel.onFileNameChanged(fileChooser.getCurrentFile().getFullPathName(), -1, -1);
Value value{valueTreeState.state.getChildWithName("soundFont").getPropertyAsValue("path", nullptr)};
Expand Down
Loading