Skip to content

Commit 5befa53

Browse files
author
Martin Klang
committed
adding SOUL patch compilation support
1 parent 7e14b85 commit 5befa53

5 files changed

Lines changed: 126 additions & 14 deletions

File tree

Makefile

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ else ifdef TEST
4444
PATCHNAME ?= $(TEST)
4545
PATCHCLASS ?= $(PATCHNAME)Patch
4646
PATCHFILE ?= $(PATCHNAME)Patch.hpp
47+
else ifdef SOUL
48+
# options for SOUL patch compilation
49+
PATCHNAME ?= $(SOUL)
50+
PATCHCLASS ?= SoulPatch
51+
PATCHFILE ?= SoulPatch.hpp
52+
SOULCLASS ?= $(SOUL)
53+
SOULFILE ?= $(SOUL).soul
54+
SOULHPP ?= $(SOUL).hpp
55+
DEPS += soul
4756
else
4857
# options for C++ compilation
4958
PATCHNAME ?= "Template"
@@ -65,14 +74,15 @@ export BUILD BUILDROOT TARGET
6574
export PATCHNAME PATCHCLASS PATCHSOURCE
6675
export PATCHFILE PATCHIN PATCHOUT
6776
export HEAVYTOKEN HEAVYSERVICETOKEN HEAVY
77+
export SOUL SOULCLASS SOULFILE SOULHPP
6878
export LDSCRIPT CPPFLAGS EMCCFLAGS ASFLAGS
6979
export CONFIG PLATFORM
7080

7181
DEPS += $(BUILD)/registerpatch.cpp $(BUILD)/registerpatch.h $(BUILD)/Source/startup.s
7282

7383
all: patch
7484

75-
.PHONY: .FORCE clean realclean run store docs help
85+
.PHONY: .FORCE patch libs faust gen heavy web minify clean realclean run store docs help
7686

7787
.FORCE:
7888
@mkdir -p $(BUILD)/Source
@@ -114,6 +124,9 @@ heavy: .FORCE
114124
gen: .FORCE
115125
@$(MAKE) -s -f gen.mk gen
116126

127+
soul: .FORCE
128+
@$(MAKE) -s -f soul.mk soul
129+
117130
sysex: patch $(BUILD)/$(TARGET).syx ## package patch binary as MIDI sysex
118131
@echo Built sysex $(PATCHNAME) in $(BUILD)/$(TARGET).syx
119132

README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ It is used to build, run and store patches written in PD, FAUST, Max Gen and C++
1313
* emcc (to make web) [[3]](#ref3)
1414
* faust2owl (to compile FAUST patches) [[4]](#ref4)
1515
* The heavy hvcc compiler (to compile PD patches) [[5]](#ref5)
16+
* The soul compiler (to compile SOUL patches) [[6]](#ref6)
1617

17-
* On Windows, you'll need a MAKE utility [[6]](#ref6). You'll also need to open common.mk and point TOOLROOT to your gcc installation directory, using a path string without spaces (such as using 8.3 filenames).
18+
* On Windows, you'll need a MAKE utility [[7]](#ref7). You'll also need to open common.mk and point TOOLROOT to your gcc installation directory, using a path string without spaces (such as using 8.3 filenames).
1819

1920
## Preparing the environment
2021
This has been done on a Ubuntu server 18.04
@@ -36,9 +37,7 @@ to compile puredata patches you need hvcc
3637

3738
compile FirmwareSender
3839

39-
FirmwareSender makes possible to use `run` and `store` make targets or by
40-
invoking it directly to run/store a compiled patch to the device using sysex
41-
codes.
40+
FirmwareSender makes it possible to use `run` and `store` make targets, or by invoking FirmwareSender directly to run/store a compiled patch to the device using sysex codes.
4241

4342
$ sudo apt install libasound2-dev libcurl4-openssl-dev pkg-config
4443
$ git clone https://github.com/pingdynasty/FirmwareSender
@@ -107,8 +106,6 @@ Note: assign OWL parameters with slider metadata: `[OWL:A]`, `[OWL:B]` et c. For
107106

108107
* put your PD patch file (e.g. `Foo.pd`) into `PatchSource`
109108
* `make HEAVY=Foo run`
110-
111-
Note: assign OWL parameters with PD receivers called `Channel-A`, `Channel-B`, etc.
112109

113110
## Building Max Gen patches
114111
Requires the `.cpp` and `.h` files of a Gen patch generated by Max Gen.
@@ -119,6 +116,11 @@ To compile and run a Gen patch called `Foo`:
119116

120117
Note: use OWL parameters in Gen with parameter names: `A`, `B`, `C`, `D`, `Exp`, and `Push`.
121118

119+
## Building SOUL patches
120+
121+
* put your SOUL patch file (e.g. 'Foo.soul') into `PatchSource`
122+
* `make SOUL=Foo run`
123+
122124
## Using FirmwareSender
123125

124126
If you prefer to build the patch first and send it later to the device you can
@@ -128,16 +130,15 @@ do it like this from the main directory of OwlProgram (this will store in slot 6
128130

129131
# Examples
130132

131-
Compile the puredata file owl_hypersaw.pd[[7]](#ref7):
133+
Compile the puredata file owl_hypersaw.pd[[8]](#ref8):
132134

133135
make HEAVY=owl_hypersaw clean patch
134136

135-
136137
Compile puredata file owl_hypersaw.pd and send to device to be run immediately:
137138

138139
make HEAVY=owl_hypersaw clean run
139140

140-
Compile KickBox[[8]](#ref8) C++ patch:
141+
Compile KickBox[[9]](#ref9) C++ patch:
141142

142143
make PATCHNAME=KickBox clean patch
143144

@@ -153,9 +154,11 @@ Compile KickBox[[8]](#ref8) C++ patch:
153154

154155
<a name="ref5">[5]</a> https://github.com/enzienaudio/hvcc
155156

156-
<a name="ref6">[6]</a> http://sourceforge.net/projects/mingw/
157+
<a name="ref6">[6]</a> https://github.com/soul-lang/SOUL
158+
159+
<a name="ref7">[7]</a> http://sourceforge.net/projects/mingw/
157160

158-
<a name="ref7">[7]</a> https://www.rebeltech.org/patch-library/patch/4_saw
161+
<a name="ref8">[8]</a> https://www.rebeltech.org/patch-library/patch/4_saw
159162

160-
<a name="ref8">[8]</a> https://github.com/marsus/MyPatches (AudioDisplay.hpp, BassDrum.hpp, Cymbal.hpp, Drum.hpp, KickBoxPatch.hpp, Oscillators.hpp, Sequence.h, SynthVoice.hpp, bjorklund.h)
163+
<a name="ref9">[9]</a> https://github.com/marsus/MyPatches (AudioDisplay.hpp, BassDrum.hpp, Cymbal.hpp, Drum.hpp, KickBoxPatch.hpp, Oscillators.hpp, Sequence.h, SynthVoice.hpp, bjorklund.h)
161164

SoulSource/SoulPatch.hpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#ifndef __SoulPatch_hpp__
2+
#define __SoulPatch_hpp__
3+
4+
#include "Patch.h"
5+
6+
#undef min
7+
#undef max
8+
#undef sin
9+
#undef cos
10+
#undef exp
11+
#undef sqrt
12+
#undef pow
13+
#undef log
14+
#undef log10
15+
16+
#define SOUL_CPP_ASSERT(x)
17+
18+
#include "soul.hpp"
19+
20+
namespace std {
21+
void __throw_bad_alloc (void) { error(PROGRAM_ERROR_STATUS, "bad alloc"); while(1); }
22+
void __throw_bad_function_call() { error(PROGRAM_ERROR_STATUS, "bad func"); while(1); }
23+
void __throw_length_error (const char *) { error(PROGRAM_ERROR_STATUS, "bad len"); while(1); }
24+
}
25+
26+
#define MAX_MIDI_MESSAGES 32
27+
class SoulPatch : public Patch {
28+
private:
29+
SOULPATCH soulpatch;
30+
std::vector<SOULPATCH::Parameter> params;
31+
AudioBuffer* outputBuffer;
32+
SOULPATCH::MIDIMessage midiBuffer[32];
33+
size_t numMIDIMessages = 0;
34+
public:
35+
SoulPatch(){
36+
soulpatch.init(getSampleRate(), 0);
37+
params = soulpatch.createParameterList();
38+
for(size_t i=0; i<params.size(); ++i){
39+
registerParameter(PatchParameterId(PARAMETER_A+i), params[i].properties.name);
40+
}
41+
ASSERT(getNumberOfChannels() >= SOULPATCH::numAudioInputChannels, "Too many input channels in SOUL patch");
42+
ASSERT(getNumberOfChannels() >= SOULPATCH::numAudioOutputChannels, "Too many output channels in SOUL patch");
43+
outputBuffer = AudioBuffer::create(SOULPATCH::numAudioOutputChannels, getBlockSize());
44+
}
45+
void processMidi(MidiMessage msg){
46+
if(numMIDIMessages < MAX_MIDI_MESSAGES){
47+
midiBuffer[numMIDIMessages] = {0, msg.data[1], msg.data[2], msg.data[3]};
48+
numMIDIMessages++;
49+
}
50+
}
51+
void processAudio(AudioBuffer &buffer){
52+
SOULPATCH::RenderContext<float> ctx;
53+
for(size_t i=0; i<params.size(); ++i){
54+
float min = params[i].properties.minValue;
55+
float max = params[i].properties.maxValue;
56+
float value = getParameterValue(PatchParameterId(PARAMETER_A+i));
57+
params[i].setValue(value * (max-min) + min);
58+
}
59+
for(size_t i=0; i<ctx.inputChannels.size(); ++i)
60+
ctx.inputChannels[i] = buffer.getSamples(i);
61+
for(size_t i=0; i<ctx.outputChannels.size(); ++i){
62+
outputBuffer->clear();
63+
ctx.outputChannels[i] = outputBuffer->getSamples(i);
64+
// ctx.outputChannels[i] = buffer.getSamples(i); // in-place
65+
}
66+
// debugMessage("xruns", (int)soulpatch.getNumXRuns());
67+
ctx.numFrames = buffer.getSize();
68+
ctx.incomingMIDI.messages = &midiBuffer[0];
69+
// ctx.incomingMIDI.numMessages = 0;
70+
ctx.incomingMIDI.numMessages = numMIDIMessages;
71+
soulpatch.render(ctx);
72+
numMIDIMessages = 0;
73+
for(size_t i=0; i<ctx.outputChannels.size(); ++i){
74+
buffer.getSamples(i).copyFrom(outputBuffer->getSamples(i));
75+
}
76+
}
77+
};
78+
79+
#endif // __SoulPatch_hpp__

gen.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
GENSRC ?= $(BUILDROOT)/GenSource
22

3-
.PHONY: .FORCE
3+
.PHONY: .FORCE gen
44

55
$(BUILD)/Source/gen.h: .FORCE
66
@echo "#include \"$(GEN).h\"" > $@

soul.mk

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
SOULSRC ?= $(BUILDROOT)/SoulSource
2+
SOULCC ?= Tools/soul
3+
SOULINC = $(BUILD)/Source/soul.hpp
4+
5+
vpath %.soul $(PATCHSOURCE)
6+
7+
.PHONY: .FORCE soul
8+
9+
$(SOULINC): .FORCE
10+
@echo "#include \"$(SOULHPP)\"" > $@
11+
@echo "#define SOULPATCH $(SOULCLASS)" >> $@
12+
13+
$(BUILD)/Source/$(SOULHPP): $(SOULFILE)
14+
@$(SOULCC) generate --cpp $< --output=$@
15+
16+
soul: $(SOULINC) $(BUILD)/Source/$(SOULHPP)
17+
@cp $(SOULSRC)/* $(BUILD)/Source

0 commit comments

Comments
 (0)