Giter VIP home page Giter VIP logo

soul's People

Contributors

cesaref avatar julianstorer avatar olilarkin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

soul's Issues

libcurl linked by SOUL_PatchLoader.so incompatible with default libcurl on Arch, Debian, Ubuntu?

Running the SOULPatchHostDemo, I always get the message "Failed to correctly load the patch DLL." I am compiling and running on Arch Linux 5.7.7, so I had to hard code the path to the shared library, but I'm reasonably sure this is not the source of the issue.

I wrote a minimal program to reproduce the behavior I'm seeing, which looks like this:

#include <path/to/soul_patch.h>

int main ()
{
	const char * soul_patch_library_path = "/path/to/libSOUL_PatchLoader.so";
	auto lib = soul::patch::SOULPatchLibrary(soul_patch_library_path);
	if (!lib.loadedSuccessfully())
	{
		return 1;
	}
	return 0;
}

I compile with g++ test.cpp -ldl, and running ./a.out; echo $? always prints 1.

Compiling the same program (after changing libSOUL_PatchLoader.so to SOUL_PatchLoader.dylib) on macOS 10.14 with clang test.cpp -lc++ works fine, and ./a.out; echo $? prints 0.

I am using the header and binary library from the latest release at the time of writing (0.9.33).

Win-x64 binaries do not run patches with "soul play" as of 0.9.59

Steps to reproduce:
soul create newpatch --output=./
soul play newpatch.soulpatch

Result:
Opens window, shows a loading spinner with label "newpatch"

Running:
Windows 10 Pro OS build 19041.572

I've also tried the binaries for the previous version, same result. Am I just missing something?

Using processor.frequency as buffer or vector size should be allowed but raises error

Using the soul command line version 0.9.53, the following minimum example fails to compile with the error:

example.soul:6:11: error: An array size must be a constant
    float[processor.frequency] buffer;

example.soul:

processor example  [[main]]
{
    input stream float audioIn;
    output stream float audioOut;

    float[processor.frequency] buffer; // <<< error occurs here

    void run()
    {
        loop
        {
            audioOut << audioIn;
            advance();
        }
    }
}

Since processor.frequency is described as a compile-time constant in the syntax guide (here), it seems like this should work.

Similarly, changing float[processor.frequency] buffer to float<processor.frequency> buffer also fails, with the error:

simple_delay.soul:6:10: error: Cannot resolve vector size expression in this context
    float<processor.frequency> buffer;

I suppose the sizes should technically be converted to int; doing so doesn't change the errors produced.

I would like to use this in order to have a buffer for delays with a maximum delay time specified (at compile time) in seconds. This requires the buffer size to be an expression using processor.frequency.

SOUL Language Guide: unused variable audioSum in ExampleGraph

We studied the documentation and the examples yesterday and found an unused / incorrectly named variable audioSum in an example. If we understood the example correctly, it should be named myOutput .

`

graph ExampleGraph
{
    output stream float audioSum;
    output stream float voiceOut[8];

let
{
    voices = SynthesiserVoice[8];   // 8 voices
    delays = Delay[4];              // 4 delays
}

connection
{
    voices[0].audioOut -> delays[0].audioIn;   // 1-to-1 first element of voices array feeds first delay
    voices[1].audioOut -> delays.audioIn;      // 1-to-many second voice feeds all delays
    delays.audioOut    -> myOutput;            // many-to-1 sum of all delay output feeds myOutput
    voices.audioOut    -> voiceOut;            // many-to-many each voice output feeds exactly one voiceOut stream

    voices.audioOut    -> delays.audioIn;      // ERROR - voices has 8 elements, delays has 4 elements
}

}

`

One off processor in graph connection declaration throws error with specialization parameters

The language guide says here:

"If you only want a single instance of a particular type of processor in the graph, you may omit the let declaration and just refer to the processor type in the connection section"

and it works perfectly unless I try to use a processor that has specialization parameters. Here's a contrived minimal example:

// example.soul
graph example  [[main]]
{
    input event soul::midi::Message midiIn;
    output stream float audioOut;

    connection
    {
        audioIn -> Offset(0.1) -> audioOut;
    }
}

processor Offset(float offset)
{
    input stream float audioIn;
    output stream float audioOut;
    void run() 
    {
        loop
        { 
            audioOut << offset + audioIn; 
            advance(); 
        }
    }
}
example.soul:8:20: error: Unknown function: 'Offset'
        audioIn -> Offset(0.1) -> audioOut;

                   ^

[FR] Shorthand for mapping event input values

I wasn't sure if this is the right place to put a feature request, if not let me know.

Since processors can potentially have a lot of event inputs, I thought there may be a way we could reduce boilerplate. From my understanding this is the current best practice for adding an input and mapping it to a value:

processor Synth
{
	input event float inputOne;

	float inputOneValue = 0.0f;

	event inputOne(float v)
	{
		inputOneValue = v;
	}
}

When you add a lot of different inputs, this requires a lot more code and reduces clarity. What if we could map the value in two lines:

float inputOneValue;
input event float inputOne => inputOneValue;

Or add a getter function (.getValue()) to the event identifier so you don't have to create a separate variable:

processor Gain
{
	input stream float in;
	output stream float out;
	input event float gain = 1.0f; // initial value

	void run()
	{
		loop
		{
			out << in * gain.getValue();
			
			advance();
		}
	}
}

Rand

Can I have it please? rand(). If we have rand then we need srand() - srand (time(NULL));
Thank you.

Example of distortion

hello everyone, do you have a example of distortion? I have interest in develop a distortion for electric guitar.

Thank you

play --output-devices="" argument won't run if there are spaces in the output device name

I tried running this command:

soul play --output-device="Speakers (USB Audio CODEC )" newpatch.soulpatch

With the latest release but I get the following error:

Unrecognised command-line argument: newpatch.soulpatch

After playing around with it a bit, it appears it just doesn't like spaces in the output device name. "Speakers (USB Audio CODEC )" is what is listed in the --list-devices command. I'm using Powershell on Windows 10 Pro x64.

soul.dev playground performance

Hi Jules',

I just read about SOUL and HEART. Reading the example .soul programs without any prior knowledge of SOUL felt super comfy for me -- I did understood most of the code right away.

I think it's an amazing concept -- also to compile it into a low-level instruction set like HEART and generate WASM. I also played with soul.dev and ran into some stuttering in the sound using the ElectricPiano.soul (TX81Z)... while debugging the code I noticed, that it looks like the performer (I hope I got the terminology right ;) is not running inside of a Service Worker -- and thus maybe not multi-threaded -- yet?

If so... how about letting the WASM run in a service worker and just transfer buffers of audio data forth and back for processing and playback using the service worker / messaging API? I did something like that before... for doing having DSP / analyzing with FFT and everything on live recorded audio in a web app. It did help with the performance a lot. Just saying... :)

Love the whole thing... If there is a way to get involved and help out, let me know.

Best,
Aron

PatchInstance::createNewPlayer throws unhandled exception

My first attempty to wrap SOUL into HISE led me to an unhandled exception deep in the SOUL's secret sauce:

Exception thrown at 0x00007FFDCCE69159 in HISE Debug.exe: Microsoft C++ exception: soul::ParseErrorIgnoringMessageHandler::ErrorWasIgnoredException at memory location 0x0000003A66FFA310.
Exception thrown at 0x00007FFDCCE69159 in HISE Debug.exe: Microsoft C++ exception: soul::ParseErrorIgnoringMessageHandler::ErrorWasIgnoredException at memory location 0x0000003A66FF9FF0.
Exception thrown at 0x00007FFDCCE69159 in HISE Debug.exe: Microsoft C++ exception: soul::AbortCompilationException at memory location 0x0000003A66FFCB18.

It happens when I called PatchInstance::createNewPlayer() with the Reverb example patch. The Delay loads just fine.

I am sure I did some mistake during wrapping the code anywhere, but shouln't the most top level compile call catch any parsing errors and convert it into a debug message?

Build of tools fails under Linux

I use gcc-10.2.1 under Fedora 32 to build SOUL.
I met an error during compilation:

$ make
Compiling include_juce_audio_plugin_client_VST3.cpp
Compiling PatchLoaderPlugin.cpp
Dans le fichier inclus depuis ../../Source/../../../include/soul/patch/helper_classes/../../common/soul_ProgramDefinitions.h:21,
                 depuis ../../Source/../../../include/soul/patch/helper_classes/../../soul_patch.h:36,
                 depuis ../../Source/../../../include/soul/patch/helper_classes/soul_patch_LoaderPlugin.h:16,
                 depuis ../../Source/PatchLoaderPlugin.cpp:11:
../../Source/../../../include/soul/patch/helper_classes/../../common/../3rdParty/choc/containers/choc_Value.h: Dans la fonction membre ยซย choc::value::StringDictionary::Handle choc::value::ValueView::deserialise(choc::value::InputData&, Handler&&, choc::value::Allocator*)::SerialisedStringDictionary::getHandleForString(std::string_view)ย ยป:
../../Source/../../../include/soul/patch/helper_classes/../../common/../3rdParty/choc/containers/choc_Value.h:929:26: erreur: il n'y a pas d'argument pour ยซย assertย ยป qui dรฉpend d'un paramรจtre du patron, aussi une dรฉclaration de ยซย assertย ยป doit รชtre disponible [-fpermissive]
  929 |  #define CHOC_ASSERT(x)  assert(x);
      |                          ^~~~~~
../../Source/../../../include/soul/patch/helper_classes/../../common/../3rdParty/choc/containers/choc_Value.h:2268:69: note: dans l'expansion de la macro ยซย CHOC_ASSERTย ยป
 2268 |         Handle getHandleForString (std::string_view) override     { CHOC_ASSERT (false); return {}; }
      |                                                                     ^~~~~~~~~~~
../../Source/../../../include/soul/patch/helper_classes/../../common/../3rdParty/choc/containers/choc_Value.h:929:26: note: (si vous utilisez ยซย -fpermissiveย ยป, G++ acceptera votre code, mais permettre l'utilisation d'un nom non dรฉclarรฉ est obsolรจte)
  929 |  #define CHOC_ASSERT(x)  assert(x);
      |                          ^~~~~~
../../Source/../../../include/soul/patch/helper_classes/../../common/../3rdParty/choc/containers/choc_Value.h:2268:69: note: dans l'expansion de la macro ยซย CHOC_ASSERTย ยป
 2268 |         Handle getHandleForString (std::string_view) override     { CHOC_ASSERT (false); return {}; }
      |                                                                     ^~~~~~~~~~~
../../Source/../../../include/soul/patch/helper_classes/../../common/../3rdParty/choc/containers/choc_Value.h: Dans la fonction membre ยซย void choc::value::Value::serialise(OutputStream&) constย ยป:
../../Source/../../../include/soul/patch/helper_classes/../../common/../3rdParty/choc/containers/choc_Value.h:929:26: erreur: il n'y a pas d'argument pour ยซย assertย ยป qui dรฉpend d'un paramรจtre du patron, aussi une dรฉclaration de ยซย assertย ยป doit รชtre disponible [-fpermissive]
  929 |  #define CHOC_ASSERT(x)  assert(x);
      |                          ^~~~~~
../../Source/../../../include/soul/patch/helper_classes/../../common/../3rdParty/choc/containers/choc_Value.h:2625:13: note: dans l'expansion de la macro ยซย CHOC_ASSERTย ยป
 2625 |             CHOC_ASSERT (dictionary.strings.back() == 0);
      |             ^~~~~~~~~~~
make: *** [Makefile:172: build/intermediate/Debug/PatchLoaderPlugin_3359ebef.o] Error 1

Command Line Util `soul play` not closing soul process

Windows x64 10.0.17763 Build 17763
Scarlett 2i2
SOUL master branch
Command Line Utils v0.8.875

I just pulled the repo's master branch and installed 0.8.875 of the command line tools to mess around with the standalone example .soul files. When using soul play [soul file] the first time, the program spawns a soul process, outputs execution info to my terminal, and outputs the audio. However, the soul process never closes. Running another soul play command yields another spawned soul process, command line output, but no audio. By repeating this you can spawn keep spawning new soul processes that will never close or output any audio.

Killing all of the soul processes fixes the audio issue allowing the soul play command to output audio, but the process still has to be killed manually.

Can anyone else replicate this issue?

Generating a Dplug plugin

Would it be possible to export to a plugin in another langage than C++? (and another framework than JUCE)
Curious about what the possibilities of SOULLang are, and what another backend entails.

SOUL Language Server

Hello everyone,

I've been working on a language server for SOUL, and I just published it to GitHub. My repository is here https://github.com/simonhochrein/soul-lsp

I currently have diagnostics implemented, and other features will be added soon.

It would be great to have this incorporated into the main organization at some point.

Any contributions would be greatly appreciated.

How to debug internal compiler errors?

Trying to figure out how to handle this internal compiler error:

error: Internal compiler error: ""canBeArrayElementType()" failed at createArray:262"

Documentation on HEART intermediate format

Hi guys, I've been following the SOUL development for a while, and first off just want to say thanks for providing this project!

I've been reading the SOUL Project Overview, and this pretty much outlines a couple of strong points for SOUL that rely on SOUL at some point being able to run on bare-metal or a "SOUL-processor". What I grasp from this is the idea that SOUL could eventually run on hardware platforms through a software VM/JIT, or who knows at some point, a hardware VM or "SOUL-chip".

From what I can gather, SOUL code gets compiled into an intermediate language called HEART, which I assume is similar to other intermediate representations such as JVM bytecode, LLVM IR, or NVIDIA PTX. I'm assuming this IR currently gets translated into whatever supported target platform, e.g. C/C++ or WebAssembly.

Now, I'm pretty interested in trying to find out how one would go from SOUL to actual (embedded) bare-metal, and which routes would be feasible. I am therefore trying to find out more about the design and structure of the HEART intermediate format, so am looking for a specification or design document of some kind.

However, I cannot seem to find any documentation on HEART. Is the format not fixed yet, or is it perhaps proprietary? Perhaps I'm looking in the wrong place, or is this documentation simply not available yet?

Would love to hear more about HEART :)

P.S. If it would be better to repost this at the JUCE forum instead, I'd of course be happy to do so.

link error in code generated by SOUL 1.0.82

I'm getting a link error when compiling with clang/osx for the DiodeClipper example.

Undefined symbols for architecture x86_64:
  "Diode::parameters", referenced from:
      Diode::createParameterList() in CAudioKit.o

When I move the definition of Diode::parameters to a cpp file, it links. Diode::parameters is a constexpr so I would have expected it to only need a definition in the class, unlike a normal static variable.

Also, the code generated by 1.0.82 says 0.9.0 at the top. I've double-checked that I'm running 1.0.82:

% ~/bin/soul | head

   _____ _____ _____ __ 
  |   __|     |  |  |  |     SOUL toolkit
  |__   |  |  |  |  |  |__   (C)2020 ROLI Ltd.
  |_____|_____|_____|_____|

  SOUL version 1.0.82
  Build date: Feb  5 2021 18:44:37
  LLVM version: 9.0.1

% ~/bin/soul generate --cpp DiodeClipper.soul | head
Building: /Users/holliday/AudioKit/Sources/CAudioKit/Nodes/Effects/Distortion/DiodeClipper.soul
Building: /Users/holliday/AudioKit/Sources/CAudioKit/Nodes/Effects/Distortion/DiodeClipper.soul
//      _____ _____ _____ __
//     |   __|     |  |  |  |        Auto-generated C++
//     |__   |  |  |  |  |  |__      SOUL Version 0.9.0
//     |_____|_____|_____|_____|     https://soul.dev
//

#include <array>
#include <functional>
#include <cmath>
#include <cstddef>

SOULPatchHostDemo not working on macOS

JUCE v5.4.5
macOS v10.15.2

Building and running SOULPatchHostDemo via the Projucer then Xcode isn't working. The GUI states:

Can't find the SOUL patch DLL!
You'll need to put the DLL (or a symlink) next to this executable so that it can be loaded. (Or hard-code some app logic to make sure it gets loaded from wherever you want to keep it.)

I searched the root folder SOUL-master and didn't find any DLL files. How do I proceed?

Thanks,
GW

Soul.exe commandline utility (0.8.947) not working on Windows (10)

Running MonoSynth.soul as an example.

image

As seen in the attached picture, it seems that on the GUI-side the utility does not render correctly. It doesn't respond to code which should not be able to compile, nor is it possible to get any audio output (although this could be the result of me not being able to configure my midi-device, or audio output).

Edit: I did manage to get it working in Waveform though. Confirmed that SOUL_PatchLoader.dll works just fine, by replacing the bundled DLL with the one from the 0.8.947 release (and thus having the examples working)

Bracketed array access wraps index

The Syntax Guide says that array access like arr[index] should raise an error if index is out of range.
But the current behavior (as of 0.9.16) is that arr[index] wraps index before accessing elements.

Bug or feature?

Assigning variables to array elements

I've made some very simple changes to the beep example, this code worked on a previous version in the beginning of January.

The assignment of variables to array elements using .at() or [], although not syntactically incorrect and with no compilation errors, don't seem to work

Here is my previous code:

processor Beep
{
    output stream float out;

    let beepLengthSamples  = int (processor.frequency * 1);
    let beepVolume         = 0.1f;
    let oscNumber          = 10;
    let gain               = 1.0f/oscNumber;
    let frequency          = 110.0f;
    
    struct simpleOSC
    {
        float frequency;
        float phaseIncrement;
        float phase;
    }

    void run()
    {
        simpleOSC[oscNumber] osc;

        for (var i = 0; i<oscNumber; i++){
            simpleOSC thisOsc = osc.at(i);
            thisOsc.phaseIncrement = float (frequency * (i+1) * twoPi * processor.period);
            thisOsc.phase = 0.0;
        }

        loop (beepLengthSamples)
        {
            var result = 0.0f;
            for (var i = 0; i<oscNumber; i++){
                simpleOSC thisOsc = osc.at(i);
                result += sin(thisOsc.phase);
                thisOsc.phase = addModulo2Pi (thisOsc.phase, thisOsc.phaseIncrement);
            }
            out << result * gain;
            advance();
        }
    }
}

And here's a version of the code (no assignment) that does works:

processor Beep
{
    output stream float out;

    let beepLengthSamples  = int (processor.frequency * 1);
    let beepVolume         = 0.1f;
    let oscNumber          = 10;
    let gain               = 1.0f/oscNumber;
    let frequency          = 110.0f;
    
    struct simpleOSC
    {
        float frequency;
        float phaseIncrement;
        float phase;
    }

    void run()
    {
        simpleOSC[oscNumber] osc;

        for (var i = 0; i<oscNumber; i++){
            osc.at(i).phaseIncrement = float (frequency * (i+1) * twoPi * processor.period);
            osc.at(i).phase = 0.0;
        }

        loop (beepLengthSamples)
        {
            var result = 0.0f;
            for (var i = 0; i<oscNumber; i++){
                result += sin(osc.at(i).phase);
                osc.at(i).phase = addModulo2Pi (osc.at(i).phase, osc.at(i).phaseIncrement);
            }
            out << result * gain;
            advance();
        }
    }
}

using AUParameterEvent::rampDurationSampleFrames with generated soul code

I'm on macOS/iOS. An AUParameterEvent (see https://developer.apple.com/documentation/audiotoolbox/auparameterevent) has rampDurationSampleFrames. The soul-generated code's ParameterProperties only has void setValue (float f).

How can I accomplish this sort of ramping of parameters?

I could run the soul code one sample at a time, ramping my own parameters, but that seems inefficient, plus it seems soul does its own ramping.

Thanks!

C++ code generator: Compiler errors on gcc-arm-none-eabi

Applies to:

  • Reverb Example patch
  • SOUL 0.9.41
  • compiler: gcc-arm-none-eabi-9-2020-q2-update

When building generated code, I get the following errors:

Error 1

template <typename Type, int size> struct Vector;
template <typename Type, int size> struct FixedArray;

Is later implemented as

template <typename Type, int32_t size> struct Vector { /**/ };
template <typename Type, int32_t size> struct FixedArray { /**/ };

which throws an error with this compiler.

Error 2

SOUL/reverb.cpp: In instantiation of 'static void Reverb::copyFromInterleaved(DestFloatType* const*, uint32_t, const SourceFloatType*, uint32_t) [with SourceFloatType = Reverb::Vector<float, 2>; DestFloatType = float; uint32_t = long unsigned int]':
SOUL/reverb.cpp:175:33:   required from 'void Reverb::render(Reverb::RenderContext<FloatType>) [with FloatType = float]'
main.cpp:81:20:   required from here
SOUL/reverb.cpp:582:23: error: invalid static_cast from type 'const Reverb::Vector<float, 2>' to type 'float'
  582 |             dest[i] = static_cast<DestFloatType> (monoSource[i]);

This happens because the compiler picks the copyFromInterleaved for mono sources instead of the vector source one.
If I comment out the mono source one, I get this error:

SOUL/reverb.cpp:175:33: error: no matching function for call to 'Reverb::copyFromInterleaved(float**, uint32_t&, Reverb::FixedArray<Reverb::Vector<float, 2>, 1024>::ElementType [1024], long unsigned int&)'
  175 |             copyFromInterleaved (&context.outputChannels[0], startFrame, _getOutputFrameArrayRef_audioOut (state).elements, numFramesToDo);
      |             ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SOUL/reverb.cpp:586:24: note: candidate: 'template<class SourceFloatType, class DestFloatType, int numChannels> static void Reverb::copyFromInterleaved(DestFloatType* const*, uint32_t, const Reverb::Vector<SourceFloatType, numChannels>*, uint32_t)'
  586 |     static inline void copyFromInterleaved (DestFloatType* const* destChannels, uint32_t destStartFrame, const Vector<SourceFloatType, numChannels>* vectorSource, uint32_t numFrames)
      |                        ^~~~~~~~~~~~~~~~~~~
SOUL/reverb.cpp:586:24: note:   template argument deduction/substitution failed:
SOUL/reverb.cpp:175:33: note:   mismatched types 'int' and 'long int'
  175 |             copyFromInterleaved (&context.outputChannels[0], startFrame, _getOutputFrameArrayRef_audioOut (state).elements, numFramesToDo);
      |             ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It is fixed by changing the copyFromInterleaved() template arguments to

template <typename SourceFloatType, typename DestFloatType, int32_t numChannels>

Warning

warning: 'void* memset(void*, int, size_t)' clearing an object of non-trivial type 'struct Reverb::_State'; use assignment or value-initialization instead [-Wclass-memaccess]
  115 |         memset (&state, 0, sizeof (state));

(in init())
Solution:

memset ((void*) &state, 0, sizeof (state));

Add INSTALL file

An INSTALL file describing how to compile the command line tool and the JUCE plugin should be added.

DSL vs API

Let me know if there's a better forum for this kind of feedback - and consider this an offer to help, if you're open to community involvement.

I'm pretty excited about this project. As I was perusing the language documentation, I could see where you're borrowing heavily from other languages and also introducing some of your own constructs. As good as the language itself is, I couldn't help feeling that you might see faster adoption if developers were writing in the languages they already know. Maybe there's an opportunity for language bindings to be written on top of SOUL?

I could see some potential barriers to that approach - JavaScript has no int type, for example - but with the right API, those shortcomings could be worked around.

As an aside, many JavaScript devs would have no idea why you would use an int vs a float (as just one example) so if spreading audio programming to the masses is one of the project aims, it might be worthwhile to consider some syntactic sugar as part of the recipe. An API could help guide devs to make the right choices.

Cheers!

License confusion

1.2. All of the Code, including the two JUCE modules, soul_core and soul_patch_loader, and the soul_patch API is governed by the permissive ISC License.

What do you mean by governed?

Because if the software is released under the ISC License it seems that the other restrictions in the EULA are incompatible,

WASM example

Hey guys! Great project here. Would really love to implement it over at https://synthia.app

I'm a little stuck on how to use the WASM functions. Can you setup an example of how JS can call the functions with the WebAudioContext? (Please forgive my noobiness of WASM)

Thanks!

More complete documentation

Playing around a bit with the playground, the following is currently undocumented:

  • sin, cos, tan
  • asin, acos, atan, atan2
  • sinh, cosh, tanh
  • exp, pow, sqrt
  • log, log10 (no log2?)
  • ceil, floor, abs, fmod
  • pi, twoPi (any other global constants?)
  • soul::NoteEvents (only what is seen in the examples?)
  • anything else?

w.r.t the <cmath> equivalents, will those remain in a "global" namespace or will they be a part of the soul namespace?

I understand you're hard at work on the API, but it would be nice to know what the API is so we can help contribute!

can getParameterProperties be static?

I'm doing some initial integration of SOUL into AudioKit via soul generate --cpp

PR here if curious: AudioKit/AudioKit#2225

It would be helpful to be able to query as much information as possible without having to instantiate the DSP object. This would assist us in populating things on the Swift side.

To be specific, it seems getParameterProperties could be declared static except for applyValue. Suggest that applyValue be moved to a separate array (perhaps returned by getApplyValueFunctions).

I can't seem to find the code that generates getParameterProperties in this repo. Perhaps it's in the closed-source backend.

Let me know if/how I can help ๐Ÿ˜€

Questions / comments 2019/02/25

In section "Reserved keywords", "const" is not listed as a keyword, but I couldn't tell if that was an error or if you treat "const" similar to C++ "override" ... a non-keyword identifier that acts as a keyword in certain contexts only.

Similarly for "clamp" and "wrap", are these keywords or not? (They are not currently listed as keywords).

"import" is listed as a keyword, but not mentioned again. If this is intentional, I suggest adding "import is a keyword that is reserved for future use."

I note there is float32, float64, and float which is at least 32 bits, but only int (which is exactly 32 bits) and no explicitly sized versions. This asymmetry is clearly intentional, but it is deserving as an explanation/rationale as it is a rather surprising decision.

"If the run() function returns at any point, this essentially puts it into an inert state where it continues to emit silence on all its inputs and outputs."
What does it mean to emit silence on inputs? Does that mean it consumes and discards inputs?

Section "Variables", bullet "State Variables" partially duplicates section "Processor state variables".
This redundancy creates potential for divergence in the future. I suggest just placing a forward reference at "Variables" and putting all the normative content at "Processor state variables", or moving section "Processor state variables" into a subsection of "Variables".

"stream - a continuous stream of values"
Sorry to be pedantic, but "continuous" has a very specific meaning in math,
and it repeats the word "stream", so perhaps "stream - a sequence of values" would be clearer?

Section "Processor oversampling and undersampling" lists examples, but does not specify the syntax. For example, what are the allowed types for the values after "/" and "*", and do they have to be literals?

Section "Built-in intrinsics and constants", I assume these are not keywords, but it might be worth mentioning that explicitly.

In section "Reading and writing to streams", it might be worth mentioning the rationale for using "<<" for outputs but not a similar operator for inputs, as that lack of symmetry is somewhat surprising. Also, should describe what happens if you don't read an input, or read it multiple times (does it consume multiple). Likewise, describe what happens if you don't write to an output, or write to it multiple times.

p.s. see a few more typo fixes at gkasten@29b9b9f
Is there a better way that I could offer these, since I know you can't accept pull requests yet?

Question about web suport

Hello and thank you for such a cool project.

I am interested in music and javascript so I thought that maybe there is source code for playground part of soul.dev web-site.

To play around with UI and to look closer on integration with WebAudio and WebWorkers.

It is considered closed source and priority for near future?

Thank you and have a nice day.

Proposal: graph fan-in using multiplication

The current fan-in syntax for connections is as follows:

connection source1, source2, source3 -> target1

This proposal concerns making the mixing operation explicit:

connection source1 + source2 + source3 -> target1
connection source1 * source2 * source3 -> target1

For example, supposing target1 is a frequency/phase input, addition would be used for FM/PM while multiplication would be used for envelope/LFO control (after mapping those controls using exp). A similar principle applies when combining volume/amplitude controls using addition/multiplication respectively.

It's possible to simulate multiplication for fanned inputs by mapping each input using log, but this becomes tricky with values like phase which can be positive/negative.

jassert in SOULPatchAudioProcessor::injectMIDIMessage

Calling soul::patch::SOULPatchAudioProcessor::injectMIDIMessage leads to a jassert in juce::MidiMessageCollector::addMessageToQueue

https://github.com/juce-framework/JUCE/blob/b8206e3604ebaca64779bf19f1613c373b9adf4f/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp#L59

because the MIDI message timestamp is set to 0.0.

midiCollector.addMessageToQueue (juce::MidiMessage (message.data, message.length(), 0.0));

Should a double timeStamp argument be added to injectMIDIMessage?

Question: Visual editor

Hi,

I'm interested in developing a "Visual Editor" for SOUL but I have a few questions:

  • I understood from this talk that you are already thinking about some tool to visually edit SOUL code. Is this an on-going project ?
  • If not, are you willing to let this part be developed by someone else and be fully open sourced ?

I was thinking about something looking like Unity shader graphs as a modern web app (React, WebAssembly...).

For the context, I'm a software engineer from France and with the current covid situation I happen to have some "free time" (partial unemployment). Being passionate about programming I want to start a side/pet project. One of the main goal driving my choice is creativity. From there I went to music, discovering all the amazing live coding and DSP languages stuff to finally discover SOUL. I do not have an audio background but I professionally develop C++ (particularly for signal processing) and JavaScript (for the UIs).

Document twoPi constant

twoPi seems to be an internal constant, but it isn't mentioned anywhere in the syntax guide. It could be documented alongside other built in constants like processor.frequency and the like, for example.

Doc for functions

Hello all!
please make inline documentation for functions (objects, built-in variables and others ...) in Soul commandline utility, for example how it works in Python.
For example:
soul help(audioin)
soul help(namespace)

Thanks for you cool project!

Improving the memory model for embedded devices

I'm considering to use SOUL for an embedded project but I found a couple of key issues that greatly hinder the use of SOUL on embedded devices. These issues apply to embedded targets in general. As I understand, SOUL wants to specifically target these devices so I think it may be helpful to consider some of the problems early on.

My main issue is the memory model - or the lack thereof.
Here's the reality on all embedded devices that I worked with so far:

  1. Memory is limited
  2. Memory is split across discontinous blocks which each have their own use, speed penalty, access requirements, etc
  3. Often there's no dynamic memory allocation available.

SOUL so far pays no attention to the memory it uses. Each buffer or variable is equal and that is a flaw that must be adressed if compatibility with embedded hardware is a priority. I don't understand the inner workings well enough to make pull requests, but I have a couple of suggestions. You may very well already have solutions for all of this coming, but I didn't find any info so I figured it might be worth writing my thoughts down here.

Regarding the SOUL language itself

  1. A SOUL compiler needs to know the use of a piece of memory in the SOUL code so that it can place that piece of memory where it fits best. While the compiler could in theory use the size of arrays, number of accesses, etc. as a way to determine the memory location, this will always end up in edge cases where the automatic placement produces suboptimal results. Moreso, it leaves the decision to the compiler which must be very smart to understand the performance impacts which I think will take a lot of development before it reaches a good state. I think a good solution would be annotations to give some guidance to the compiler. Memory could be annotated in SOUL code as bulkMem or fastMem where the former would indicate to the compiler that this piece of memory should be placed in a slower bulk storage if required. This should be "indicative" not "imperative" so that in the future, smarter compilers can start to make their own decisions.

  2. When I code delay buffers, I need to specify the size in samples. I want to stay flexible WRT the samplerate, yet I would like to get the maximum performace WRT cache misses. It would be great it the SOUL language had an internal constant "processor.maxSampleRate" that would allow me to scale my arrays accordingly. When SOUL code is compiled without knowledge about the actual samplerate, this could be some large value defined by the runtime environment/compiler. When the patch is compiled for a specific samplerate, that can be equal to the actual samplerate so that the memory footprint is as small as possible. Of course this would have to take into account any up/downsampling but these things are known at compile time as well.

Regarding the current C++ code generator

Right now for me the only way to get SOUL code onto an embedded target is the C++ generator. I think even in the future [SOUL -> C++ ] + platform specific startup/glue code may be a great option for many platforms.
However, the whole SOUL patch is right now created as one huge class which doesn't work with the segmented memory on an embedded device.

Here are my wishes for that:

  1. I would like to specify to the C++ generator, how my memory is laid out. This could be akin to a linker script. I would specify which memory segments are available, their size and speed (abstracted. e.g. 1-5 or simply "fast"/"slow"). Then the generated C++ code would contain my main class (which will sit in fast memory and directly contain everything that sits in fast memory) as well as some nested classes (or just size_t constants) - one for each memory segment. I would then allocate one of each in the corresponding memory segment and hand them over to the main class in a constructor. Something like this:
class CppCodeGeneratedFromSoulPatch 
{
public:
    struct MemSegment1Data 
    {
        // ...
    };
    struct MemSegment2Data 
    {
        // ...
    };
    // ctor takes preallocated memory for each section
    CppCodeGeneratedFromSoulPatch(std::aligned_storage<MemSegment1Data> mem1, 
                                  std::aligned_storage<MemSegment1Data> mem2)
    {
        // uses placement new() to allocate the MemSegmentXData objects.
    };
};

Not sure if this particular model would work, but SOUL could also use some sort of "pseudo-dynamic" memory allocation internally, where the C++ code for each processor/graph of the patch would get a pointer to the available memory regions, use whatever memory it needs and return a new pointer to the remaining memory for use in the next processor/graph.

  1. I would like to be able to generate C++ code for one single samplerate, making use of as much optimization as I can. I would like to be able to have filter coefficients pre-calculated, etc. without hindering code portability to other samplerates and without loosing the possibility to develop my SOUL patch in a DAW on my computer.

I think SOUL is an amazing project that could really change the audio industry.
I would love to hear your thoughts on these topics and I'm looking forward to the future developments.

Standalone Win-x64 binary crashes if syntax error is introduced to code while app is running

Steps to reproduce:

  • soul create newpatch --output=./
  • soul play newpatch.soulpatch
  • Add a syntax error to the code

Result:

  • After syntax error is added it closes the app with no error logged to shell.
  • When I re-run the "soul play" command it opens fine showing the syntax error. After correcting the syntax error, live-reload goes to the working application.

Running:
Windows 10 Pro (I've tried this on two computers running the same OS, same result)

This does not happen with the Waveform plugin, which live-reloads showing the syntax error.

soul::DFT::forward output is half as long as it should be

Hi!

I think there is an issue with the soul::DFT::forward function in soul_library_frequency.soul. Normally DFT is supposed to create two arrays of length N, one for the real component and one for the imaginary component, where N is the number of samples. This gives us N frequency bins.

In the soul::DFT::forward, you are taking the results from soul::DFT::performComplex, which are two arrays of length N as I described earlier, and you are copying half of each of them into the outputData array, which is also length N. This means you are getting rid of half of the frequency bins.

I could fix this problem myself as a pull request, but I wanted to first raise it as an issue to get your opinion and make sure this actually is a problem. If I am just making a mistake, please let me know.

Thanks so much!

soul to juce, compilation errors

I'm trying soul's ClassicRingtone example with the soul to juce command line workflow, and when trying to compile the project in xcode I get a bunch of errors as seen below.

I've been trying to make sense of these errors and for example in the first one, for GeneratedClass::UID, I can't find UID in the ClassicRingtone struct other than in

struct IDs
{
    const juce::Identifier UID      { GeneratedClass::UID }...

full error log:

ClassicRingtone - Shared Code Group
Apple LLVM 9.0 Warning Group
Unknown warning option '-Wzero-as-null-pointer-constant'; did you mean '-Wint-to-void-pointer-cast'?
Unknown warning option '-Winconsistent-missing-destructor-override'; did you mean '-Winconsistent-missing-override'?
Semantic Issue Group
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:687:43: No member named 'UID' in 'soul_import::SOUL_ClassicRingtone'; did you mean simply 'UID'?
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:687:32: 'UID' declared here
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:687:59: Field 'UID' is uninitialized when used here
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:685:12: During field initialization in the implicit default constructor
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:795:52: No member named 'name' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:796:52: No member named 'description' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:798:52: No member named 'category' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:799:52: No member named 'manufacturer' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:800:52: No member named 'version' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:804:72: No member named 'UID' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:805:52: No member named 'isInstrument' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:808:88: No member named 'name' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:813:35: No member named 'name' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:815:32: No member named 'description' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:816:39: No member named 'description' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:
.../20_05_20_ClassicRingtoneTest/juceOutput/ClassicRingtone.cpp:1164:67: No member named 'version' in 'soul_import::SOUL_ClassicRingtone'
.../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:10: In file included from .../20_05_20_ClassicRingtoneTest/juceOutput/Main.cpp:14:

Arithmetic functions only work with const variables

Hi there!

I am having some issues with performing arithmetic functions on non-const variables.

    let a = 10.0f;
    let sqrtTest1 = sqrt(a);  // OK: a is constant
    let powTest1 = pow(a, 2); // OK: a is constant

    var b = 20.0f;
    let sqrtTest2 = sqrt(b);  // error: Found an expression when expecting a constant
    let powTest2 = pow(b, 2); // error: Found an expression when expecting a constant

    const float c = 30.0f;
    let sqrtTest3 = sqrt(c);  // OK: c is constant
    let powTest3 = pow(c, 2); // OK: c is constant

I only tested this with sqrt() and pow(), but I suppose the same goes for other arithmetic functions. Is this done on purpose?

Thanks in advance!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.