GithubHelp home page GithubHelp logo

ohmtech-rdi / eurorack-blocks Goto Github PK

View Code? Open in Web Editor NEW
282.0 14.0 18.0 82.61 MB

Software to Hardware Prototyping for Eurorack using C++, Max/Gen~ or Faust

License: Other

Python 52.08% C++ 24.85% C 4.08% Shell 0.04% Max 18.75% JavaScript 0.19% Faust 0.01%
eurorack eurorack-blocks audio embedded sound daisy stm32 hardware maxmsp faust

eurorack-blocks's People

Contributors

eliottparis avatar erichvk5 avatar ohmtech-rdi avatar ricardomatias 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

eurorack-blocks's Issues

Fix kivu12 rev2 hardware issues

A number of issues were present while testing kivu12 board revision 2.

  • We had to use our stock 4.9K instead of 4.7K for I2C. Since we didn't order them, they must have been missing from the BOM
  • Header sockets can't be put next to each others, we had to sand them
  • Pots were not working because we forgot to solder GND and 3V3 header, probably make this more clear somehow
  • LEDs are not connected to the LED driver chip in the same way as the datasheet. This makes the logic inverted, plus there were some glitches on some pins when animating (though most likely not related to that?)
  • CV level shift circuit is plain wrong
  • 1N4148 doesn't protect gate input to 4051 against our of negative absolute ratings because of its forward voltage
  • 4051 is powered in 12V, and thus require address in that range, 3V3 logic for addresses won't work

Tasks:

  • Double check 4.7K resistors for I2C data lines have the right value
  • Use proper inverting adder amplifier for CV level shift and implement level inversion in software
  • Make space between socket headers, or even remove them. Make sure to keep a 2.54mm distance between headers
  • Change LED code match PCA9685 3V3 connection
  • Update DaisyPatchSM pin out
  • Adapt codec gain input/output levels
  • Put 3V3 and GND labels on front PCB to suggest header soldering
  • Update libDaisy (needed by ADC fix)
  • Fix ADC pin order
    • kivu12
    • daisy_field
  • Fix Buttons/Gates order (last 8 inputs not checked)
  • Fix gate out order (DPSM bug most likely)
  • Test CD4051B with 10V on inputs through a 100kΩ resistance (doesn't work)
  • Clip input using a dual-package schottky diode
  • Add new revision number (rev3) on PCB

Add SD support

Add SD support to ERB.

  • Update erbui DSL
  • Add PJS008U to kicad-libs submodule and front PCB generator
  • Update micropatch board
  • Update field board
  • Add filesystem abstraction
  • Add SD support to simulator
  • Test using field board

Note: eMMC is not supported yet.

Gyp actions are missing inputs

Generated gyp file from erbb are missing some actions inputs:

  • The data generator is missing the erbb file itself
  • All actions are missing the script that generates outputs themselves

How to reproduce:

  • Add an audio sample to the project and try to build, it will fail to create this new resource, and running configure doesn't help either.

SDRAM write/read failure

We have a problem with SDRAM in general. When soft or hard resetting the board, the SDRAM will return a different value than the one written for some portion of memories. Turning off the system and on again "correct" this problem. We don't yet whether this is caused by:

  • Some sort of faulty board,
  • A problem when setting up the SDRAM,
  • Some other unknown problem.

For now, we consider that we can merge this PR, as this SDRAM problem doesn't seem to be related to the SDRAM implementation. What was tried and failed:

  • We made sure to zero the entire SDRAM section at start, even if it is not needed,
  • In the case of audio, when reading a NaN value, we return a 0 instead (this introduces a lot of noise, but this seems to "work", and somehow seems to indicate there are problems only over a certain number of addresses)
  • We copied the ValidateSDRAM function from Daisy to give it a test. It seems it always find failures, somehow of a magnitude of 1 million words.

Current Status 23 Dec 2021

Most likely a faulty board. Progress is paused until the manufacturer gets back to us.

Current Status 06 Feb 2022

The board was faulty. The new board works perfectly.

Tasks

  • Clone DaisyExample
  • Build all libraries and patch_sm/HardwareTest
  • Open project in VS Code
  • Run project and report
  • Rerun patch_sm/HardwareTest after a power cycle and with a serial monitor and report
  • While we are at it, check that SD works on kivu12
  • Mitigate

Having two VCV Rack plug-ins generated from erbb crashes VCV Rack

Steps to reproduce:

  • configure.py and build.py the test/vcvrack integration tests,
  • configure.py and build.py the samples/drop example code,
  • Launch VCV Rack.

VCV Rack will crash when trying to add the model for the vcvrack integration test plugin.

Analysis:

  • The affected plug-in is following the filesystem file order. If the VcvRack plugin is called Ahh and therefore is instantiated before Drop, Drop will crash VCV Rack,
  • The crash happens when trying to add the model to the plug-in. For some reason, the model is already populated,
  • Changing the extern global value plugin instance and model names (and so linkage and how dynamic libraries are loaded on Unix), doesn't have any beneficial effects.

Workaround:

  • Always have only one erbb generated plug-in inside the VCV Rack plug-in folder.

The crash is completely similar to #92 and we believe they are related somehow.

Add AudioSample mono/planar/interleaved template specialisation

Currently, when using mono samples, we have an extra channels member that doesn't make so much sense.

Currently also, FAUST integration would require a planar representation of samples. For now this is not completely known how much performance impact has reading interleaved samples linearly, compared to reading them from 2 different planes.

Nevertheless, we can add an option to the data in erbb that accounts for that, when the data type is AudioSample

  • mode mono: if the file is mono, skip the channels member
  • mode planar: start with channels followed by samples
  • mode interleaved: what we have now

Show platform target and build configuration when building

For now, running configure.py and then build.py will compile for the daisy target, not the vcvrack target. This can be confusing for the first minutes of evaluation, as people would prefer to build for vcvrack.

Though, building for the simulator should be done in the IDE.

To mitigate that, build.py should show which erb target and build configuration it is using.

dsp/ shouldn't be in samples/

dsp/ shouldn't be in samples/, because it is not a sample, and that creates confusion in the first minutes of project discovery and associated mental representation.

Using large amount of data slows down the development iteration process

The declaration and definition of data is done in the *Data.h module artifacts file. Since this one is included from the main module file, it gets recompiled every time there is a change to the main module file, which starts to be quite long with big pieces of data.

Move the definition to a new compilation unit to avoid that problem.

Hardware kivu12 testing

After the first kivu12 board is assembled, make a first round of hardware test, before we test the software as in #180.

Stage 1

  • DPSM is not connected
  • No front panel connected
  • Lab supply: max 100mA for all outputs

Tasks:

  • Proper ±12V with small current consumption
  • Connect kivu12/CI1 and kivu12/CI2 to 0V, 2.5V, -2.5V, 5V, -5V, Jumpers on position ±5V
    DPSM/C4 and DPSM/C5 are 0V, 2.5V, -2.5V, 5V, -5V
  • ❌ Connect kivu12/CI1 and kivu12/CI2 to 0V, 4V, 8V, Jumpers on position 0..10V
    DPSM/C4 and DPSM/C5 are -5V, -1V, 3V
  • Connect DPSM/A2/A3/A9 to GND, kivu12/B2 to xV, DPSM/B9 is xV
  • Connect DPSM/A2/A3/A9 to GND, kivu12/B10 to xV, DPSM/B10 is xV

Stage 2

  • DPSM is connected
  • No front panel connected
  • Lab supply: max 200mA for all outputs

Tasks:

  • Proper ±12V with small current consumption
  • Proper 3V3 on kivu12/3V3

Interactive kivu12 testing

Interactive kivu12 testing

Make an interactive kivu12 board test suite by using USB CDC.

  • Write USB CDC receive/transmit base
  • Make interactive test firmware
  • Make script to instrument test firmware

On the firmware side, the USB receives data to change scenarios, and to transmit data relevant to a specific scenario.

Scenarios:

  • (default) Print hello world with animation to test \b
  • Cycle through each LX, one every 2 seconds, and print number on serial
    • Check for correct order
  • Blink L1 with slow linear ramp
    • Check for perceptual linear intensity
  • Print values of all BX
    • Check for correct order
  • Print values of all PX
    • Check for correct order
  • Output 440kHz ±1.f sine wave on each AOX
    • Check for ±5V level on oscilloscope
    • Check for noise and non-linearity
  • Forward AIX to AOX with unit gain
    • Check for same level on oscilloscope
    • Check for noise and non-linearity
  • Cycle through each GOX, one every 2 seconds, and print number on serial
    • Check for level on oscilloscope
  • Output 1Hz normalized saw wave on each COX
    • Check for 0..5V level on oscilloscope
  • Print state of all CIX
    • Check for level on oscilloscope
    • Check level shift for CI1/2 with pitch generator (Beatstep Pro)
  • Load test file on SD and send it to serial (depends on #181)

FAUST integration

Our users expressed the need to have different language integration, and FAUST is one of them.

Overview

Faust (Functional Audio Stream) is a functional programming language for sound synthesis and audio processing with a strong focus on the design of synthesizers, musical instruments, audio effects, etc. Faust targets high-performance signal processing applications.

Epics

From Scratch

Avery has an idea of a new Eurorack module. They want to develop it in FAUST, because they are familiar with it, and they can leverage quickly the big standard library of dsp blocks available at their fingertips.

They started to draw the layout of the module on a piece of paper and a quick schematic of the audio flow. They use the GUI editor to make a first sketch of their idea and write the dsp code.

They iterate over the sketch by usually first modify the GUI to add or remove a control, and then update the dsp file accordingly.

From Existing

Brooklyn has been working for 10 years with FAUST and as a result has a big collection of dsp modules, some of which they would want to have as real Eurorack modules.

For each dsp code, They use the GUI editor to make a first sketch, that they will iterate on.

Workflow

FAUST code have presentation and model mixed into the source code. The faust program can be used to generate C++ code as well as declarative structured data representing some static properties of the DSP code (such as number of input/outputs, or parameters' description), for example in JSON.

faust -json -o plugin_faust.cpp ../Kick.dsp

Will generate:

  • A JSON file that tells us about the number of audio inputs and outputs, parameters with their associated widgets (from which we can deduce a type), as well as minimum, maximum values, when applicable,
  • A C++ file that can be instrumented with the use of an Architecture file.

Bindings considerations

Like the erbui/C++ bindings, we need to be able to map a erbui name to a corresponding C++ name.

This is done in C++ by making sure that a mismatched mapping will fail at build time rather than at runtime.

Since we can extract a static representation of the FAUST dsp code, we could apply the same principle as in C++, that is an unused erbui name in C++ would be silently ignored, but a name in C++ not defined on the erbui side would trigger an error.

However, using C++ allows a strict control about parameters of the DSP.

In the case of FAUST, including libraries may add widgets primitives to the generated DSP code, that the user wouldn't want to have visible in the erbui UI.

For this reason:

  • A parameter in FAUST dsp code that wouldn't match its counterpart in erbui will be either silently ignored or at most emit a warning,
  • A control in erbui code that wouldn't match its counterpart in FAUST code will be silently ignored.

Compound types

ERB has the concept of compound types, for example:

  • A 3-state or 2-state switch is made of 2 contacts,
  • A dichromatic LED has 2 pins for each color,
  • More complex compounds will come like a fader with associated LED.

FAUST doesn't have this concept for its widgets. Furthermore, widgets are classified as passive or active whether they respectively take or provide a scalar value.

To remedy this, since the label is a string, we will use dot notation to bind a scalar to a compound element.

For example, considering the following erbui code:

module MyModule {
   control led LedBi { ... }
}

To access red and green components of the physical LED, we could use the same notation
as in C++, that is led.r and led.g, but from within the primitive label:

... : vbargraph("led.r",min,max);
... : vbargraph("led.g",min,max);

Name mapping

On one side, erbui defines a name of a control as an identifier. Such an identifier matches the regex ([a-zA-Z]\w*), so that it needs to start with a letter, and then be followed a letter, number of underscore.

On the other side, labels are arbitrary. They can start with a number, contain spaces, and all sorts of other different characters.

Also, due the recursive nested structure with *group primitives, the same label may appear multiple times, but with a different group.

Given that OSC paths must be unique, "fully qualified labels" are unique for a given FAUST top-level source code.

Instead of breaking the isomorphism to match names between erbui and FAUST by applying some sort of normalisation of the name, which would also be very ugly for the user in some case, we will allow to create a string literal that aliases the erbui control name.
This string literal will be the "address" of the widget, as defined by FAUST and available in the JSON description of the dsp code:

module Guitar {
   control attack Pot {
      faust { bind { address "/Distortion Effect/0x00/Compressor/Attack" } }
   }
}

When the faust address is not present, it will be crafted by taking the control name prefixed with a /:

module Guitar {
   control attack Pot {
      // would be implicitely: faust { bind { address "/attack" } }
   }
}

In the case of compound types, the control property identifier needs to be specified in the binding:

module Guitar {
   control led LedBi {
      faust {
         bind { property r address "/Distortion Effect/0x00/Compressor/Level X" }
         bind { property g address "/Distortion Effect/0x00/Compressor/Level Y" }
      }
   }
}

When the faust address is not present, it will be crafted with dot notation by taking the control and property names prefixed with a /:

module Guitar {
   control led LedBi {
      /* would be implicitely:
      faust {
         bind { property r address "/led.r" }
         bind { property g address "/led.g" }
      }
      */
   }
}

We consider that the order in which widgets are defined in the FAUST JSON generated file follows the same order in which widgets functions are called in the C++ generated buildUserInterface function: this allows for a very straightforward mapping.

Initial value

It is worth noting that a non-erbui-mapped name is valid, but the underlying parameter will stay to the FAUST defined default "init" value, which is probably not always good.

Also in this case, the generator issues a warning:

warning: non mapped hslider /PHASER2/0x00/Notch Depth (Intensity)

Those warnings are nice, because it allows to fetch easily the address of a FAUST widget, when using already made dsp, and when the widgget is buried deep into the dsp hierarchy.

But leaving warnings can be unsatisfactory, so we need a way to solve that nicely.

To solve those 2 problems (silenting a warning, and providing an initial value different from the FAUST defined one),
we can simply add a syntax for this, for non-mapped active components:

module Guitar {
   faust {
      init { address "/PHASER2/0x00/Notch Depth (Intensity)" value 0 }
      init { address "/PHASER2/0x00/Vibrato Mode" value 0 }
   }
}

Finally for completion, we can do the same for the equivalent "passive widgets" (in FAUST terms) for an erbui control like a LED:

module Guitar {
   control led_bi LedBi {
      faust {
         bind { property r address "/Distortion/0x00/Output Gain" }
         init { property g value 0.5 }
      }
   }
}

Generator specifics

Sample data binding is done through the UI adapter, rather than being an adapter on its own.

Thought our adapter declaration and definition can be splitted, so that we have 2 definition files (one for the UI, one for the sample data).

This allows the erbui generator to only generate UI adapter functions, and the erbb generator to only generate audio sample adapter functions.

Parameters

All parameters (inputs or outputs), are represented as floating-point numbers.

Input parameters like sliders are associated to a function defining the minimum and maximum value as well as a mapping function defined for example as a meta/scale function. Since ERB considers only normalized or bipolar numbers, some sort of adaptation needs to be done there.

Conversely, output parameters are associated to a function defining the minimum and maximum value, and a mapping function. Since ERB LEDs are normalized, the inverse function will need to be done there as well.

The mapping functions are implemented in C++, but we will generate a flattened version of this C++ code from python.

The numerical entries widget nentry doesn't have an equivalent in the hardware world, but it is considered as a scalar value.

Audio inputs/outputs

We don't have labels for audio inputs and outputs, so we will rely on the order in which they are declared in the erbui file to bind them with the FAUST dsp code.

Audio files mapping

Since we don't have the concept of a filesystem, we need a system to match the erbb AudioSample definition to the corresponding FAUST soundfile expression.

To reuse the same concepts, we can use the name mapping defined for the erbui Language, but in the erbb language, since Data is generated from erbb, not erbui:

resources {
   data sample AudioSample {
      file "sample.wav"
      faust { bind { address "/Drum/0x00/Kick/sound" } }
   }

for the corresponding FAUST dsp code (in a library Kick.dsp):

process = 0,_~+(1):soundfile("sound[url:{'kick.wav'}]",2):!,!,_,_;

In particular, should there be a url option like "foo[url:{'foo.wav'}]", then the url information is either ignored or an error or warning is emitted if the file names do not match. At first, we will just ignore it.

As for name mappings with erbui, we will keep the same nice features, for example:

  • A non-mapped sample will emit a warning
  • If a faust binding is not done, then it is implicitely deduced from the module name and data name:
module Kick {
   resources {
      data sample AudioSample {
         file "sample.wav"
         // implicitely:
         // faust { bind { address "/Kick/sample" } }
      }
}

Audio files stream format

FAUST only supports for now planar (ie non-interleaved) sample formats.

Eurorack-blocks support this stream mode, and will use mode planar automatically for every multi-channel samples when using FAUST.

Planar representation most probably suffers from cache cohenrency on embedded platforms, as well as using SIMD instructions more difficult and less efficient, but we will leave this for now until we have collected execution performance data, and a interleaved mode would be supported in FAUST.

Audio files "parts"

FAUST has some sort of convenience system which allows to assemble multiple audio files into one consolidated file.

We don't have such a convenience system, and don't plan to use it. Rather we could use standard markers (such as "cue"/"splice" markers for WAV format), to detect parts in an audio sample file.

The current latest brew/apt release of FAUST doesn't include the number of parts in the SoundFile structure, so that the later structure is not closed (ie the information it provides are not sufficient to use it). But work has been already done to include this number in the SoundFile, and should be therefore available after version 2.39.1.

Memory management

Ideally the generated code should be portable for both the simulator and the embedded daisy platform.

However "allocating" big portions of memory, such as delay lines, are going to be handled differently on both platforms:

  • On the desktop dynamic allocation can be used,
  • On daisy the portion of memory needs to have a special section attribute to be placed in the SDRAM section.

Such "allocations" (the amount of memory is actually known at build time) appear when a @ time expression is used, for example.

For reference, FAUST has a custom memory manager, but it is only meant for rdtable primitives.

It is still unclear how to handle that, but it might be out of scope for this integration. The generated FAUST code will need somehow to place large amount of memories in the SDRAM section, and ERB should just make sure that enough space is available in SDRAM by decreasing the erb_SDRAM_MEM_POOL_SIZE to just what is needed for ERB (which is currently nothing).

In the worst case, provided the compiled code would need to be different for each platforms, we could wrap the code underlying target specific implementations:

// faust.cpp
#if defined (erb_TARGET_SIMULATOR)
   #include "faust_simulator.cpp"
#else if defined (erb_TARGET_DAISY)
   #include "faust_daisy.cpp"
#endif

Unsupported features

Layout informations, as this is already done by erbui, are ignored.
This includes all "box" primitives, that is hgroup, vgroup and tgroup UI primitives.

While layout informations are ignored, the label of a group is used for name mapping as described above.

Tasks

  • Make a PoC manually
    • Audio inputs/outputs
    • Active parameters
    • Passive parameters
    • Parameter scaling
    • Name mapping
    • Compound types
    • Sound files
    • Memory management
  • Update documentation
  • Make Erbb FAUST generator
  • Make Erbui FAUST generator
  • Add sample code

Add sample code to illustrate usage of audio samples in code as well as using QSPI

We don't have sample code to show the usage of data foo AudioSample construct.
Related to that, the use of audio samples will almost immediately go past the 128K Flash memory limit, so QSPI support is needed in this case.

Make a Kick, which illustrates both of those technics:

  • Having a kick body and selectable kick transients,
  • Having enough samples so we are way past the internal Flash limit, and QSPI is mandatory.

Add background thread abstraction

Add a "background thread" abstraction, for tasks that are not suited to the audio realtime task, like loading a sample from SD.

The abstraction would allow to run on both the Daisy and simulator ERB targets.

  • Add "background thread" abstraction to Daisy ERB target, using "main thread"
  • Add "background thread" abstraction to Simulator ERB target, using std::thread

Note: any kind of synchronisation is out of the scope of this feature.

Add sampler sample

Add asampler sample, to illustrate the use of the SD filesystem abstraction, and synchronisation primitives with the audio realtime thread.

sampler mimics Simpler built-in from Ableton Live but without time-stretching and globally less options (no enveloppe, no LFOs, etc.)

Because of the current limitation in libDaisy to detect SD, only one sample would be supported for now, and loaded when inserting a SD card and pressing the LOAD button. This should be enough to demonstrate how to walk the filesystem and filter the files to load.

Front panel:

  • SD card
  • LOAD button
  • LOAD LED loading fast blinking progress
  • PLAY button
  • PLAY gate
  • PLAY feedback LED
  • Playback MODE(one-shot, loop)
  • TRIGGER/GATE switch
  • START sample start Pot, CV, Attenuverter
  • SIZE sample length Pot, CV, Attenuverter
  • FADE IN Pot
  • FADE OUT Pot
  • LP low pass filter Pot, CV, Attenuverter
  • OUT L/R audio outputs

Tasks:

  • Layout front panel
  • Implement WAV decoder
  • Implement DSP

Nothing from the eurorack-blocks project does build on Windows

Steps to reproduce:

  • No hardware or software github workflows are building properly.

Analysis:

  • There seem to be problems with python scripts, but we don't understand why,
  • Cross-compiling with ninja fails, but we don't understand why.

Workaround:

  • None.

State as of December 2021

  • Hardware job fails because KiCad package for chocolatey seems to be broken. The download URL doesn't exist
  • Software job fails for the same reasons as before: for some reason libdaisy.a is not produced. This might be because of cross compiling.
  • Unit Tests job fails because of gyp software erosion. Visual Studio can't be found, but do we need to support this IDE? Is our VS Code generator good enough?
  • Erbb tests job fails, most likely because of a wrong python3 path (the one used now seems to come from Travis-ci)

Benchmark cmath functions compared to their "fast math" equivalent

Our future integrations use "fast math" to replace parts of the standard library with a "faster" equivalent.

Sometimes for example, std::sin is replaced with the CMSIS equivalent, but the implementation doesn't seem to be faster than the one in glibc, unless we are looking at the wrong implementation.

To make sure those are relevant, benchmark them:

  • The time they take compared to the standard library one
  • The ULP they have compared to the standard library one

AudioSample ignores sample type template parameter

The AudioSample* ignore sample type template parameter:

For example:

template <class T, size_t Length, size_t NbrChannels>
struct AudioSampleInterleaved
{
   struct Frame
   {
      std::array <float, NbrChannels> channels;
   };

   float          sample_rate;
   std::array <Frame, Length>
                  frames;
};

T is not used in the declaration of AudioSampleInterleaved

Max integration

Our users expressed the need to have different language integrations, and Max is the most used of them.

Overview

Max, also known as Max/MSP/Jitter, is a visual programming language for music and multimedia developed and maintained by the software company Cycling '74.

Epic

Avery has an idea of a new Eurorack module. They want to develop it in Max gen~, because they are familiar with it, and they can leverage quickly the big standard library of dsp blocks available at their mouse clicks.

They started to draw the layout of the module on a piece of paper and a quick schematic of the audio flow. They use the GUI editor to make a first sketch of their idea and visually create the dsp code.

They iterate over the sketch by modifying the GUI to add or remove a control, and then update the Max patch accordingly, or the other way around.

State of Art

An implementation exists already for the Daisy platform, in the form of oopsy.

However this implementation does not fit our needs:

  • It relies on the fact that the hardware is available before the software is produced, which is not our case (the hardware is produced very late in our workflow),
  • It focuses solely on the Daisy platform, while we need to provide support for both the Daisy platform and our simulator running in VCV Rack.

However, oopsy is a working implementation of gen~ targetted at the Daisy platform, and the learnings from it are important for our project, and have been collected in this paper.

Licensing

While our project has its own very permissive open-source license, the code exported by gen~ has a different license, and this needs to be very clear for the end-user, since the Eurorack-blocks abstracts so many things away, a user might not see they are violating a license, especially if they intend to sell their Eurorack-blocks module, which we will facilitate in the future. For enthousiast hobbyists, that shouldn't be a problem though.

At least we should:

  • Make a clear statement about it on the front page of our repository,
  • Have a way to make sure that companies above $200k of revenue know that they need to pay a fee, and that in any case, all users with a commercial usage will contact [email protected].

Workflow

Starting up

One maybe conceptual issue is that Max users probably expect their patch to be the "center" of what they do. In that sense, they would expect some template patches as starting points for their module.
The only problem with this approach is that we need the erbb and erbui file to get started, and the erbb references the Max patch (rather than the other way around). Changing the way this work would probably increase the amount of work needed, as everything would need to be done the "reversed way", and this could have severe impact on the ecosystem of tools we are trying to bring (such as the GUI editor).

So for now, we will consider the erbb meta-build-system file to be the "center". Only when we will know in practice which impact would be to have the Max patch at the "center" of everything, and a proper long-term strategy for it, then we would revise the current strategy.

Users will first call erbb max init which will create a skeleton of a max patch to start with, with:

  • An embedded gen~ patch,
  • The 1 audio input and output already mapped out in this gen~ patch,
    • Configured as a bypass by default,
  • Saving the Max patch shall trigger a gen~ code generation, using a savebang (see error early), and the generation (configure + build) of the simulator
  • Unlike oopsy, the patch won't be able to either build or install the firmware. This will be done using the erbb command.

Package

The Max package will contain:

  • The gen code + build patch to import as a bpatcher
  • The associated javascript code
  • Some gendsp functions which mimics what we have in the C++ API (button pressed, held, released, LED animation system, etc.)
  • Some help files

Using a Max package has the advantage to be a search path for the javascript code we have, so that the ERB project stays clean and upgrading the repository updates as well all the user patches accordingly.

Name mapping

Thanks to its recursive structure, we should only consider a flat name space, so that name mapping should be direct.

Compound Types

Since param names should contains only characters that matches C++ identifiers, we can't use dot notation to refer to a property in the compound, so we will use a _ instead.

We can't use an attribute for the history, as this would give the same value.

Not sure if there are really other nice solutions. It seems possible to use buffer or data for those types, or the value can be a vec, but that doesn't seem to be convenient at all. We need to assess this. A vector could be used as well for some reason, and that doesn't interfere with our "underscore notation".

Computed properties

Some controls have additional computed properties. For example a button value is the raw signal value, including electrical bouncing. But we have algos to filter that, and convenient interface like pressed () or held () on the C++ side.

Made this accessible to Max with the same technic than the one above: replace dot notation with "underscore notation".

Make a gendsp function for that.

LED animation system

Some controls like LED can animate the value they own. For example a LED has some functions like blink, pulse etc. with some arguments about timings.

Do history led_blink (using again "underscore notation"). Not sure how to pass arguments though.

Make a gendsp function for that.

Audio samples

Internal data is still accessible in generated code, with a nice setter to do the work. We just need to implement genlib_data_setbuffer

Daisy Port

The gen_dsp library doesn't compile without modifications. We have our own copy of gen_dsp and use it instead of the provided one.

Oopsy removed a lot of thing, and it seems that ARM C7 DSP functions are not used, and it's unclear why.

Memory management

Ideally the generated code should be portable for both the simulator and the embedded daisy platform.

However "allocating" big portions of memory, such as delay lines, are going to be handled differently on both platforms:

  • On the desktop dynamic allocation can be used,
  • On daisy the portion of memory needs to have a special section attribute to be placed in the SDRAM section.

Oopsy implemented an heuristic which is similar to the one we implemented on the allocate-ram-auto branch. We used this allocation strategy for FAUST, and we will reuse it for Max.

Also Oopsy is putting the module state in the (most likely) SRAM. Since they already parse the C++ code, it's unclear why they didn't go a bit further and allow to have the State on the stack to put it in DTCMRAM. After all this memory is twice as fast as the AXI SRAM, and all filters history are stored in it.

Tasks

  • Make a PoC manually
    • Audio inputs/outputs
    • Input parameters
    • Output parameters
    • Parameter scaling
    • Name mapping
    • Compound types
    • Assess if compound types can use vectors somehow: No
    • Computed properties (gendsp in code in Max package)
    • Animations (gendsp in code in Max package)
    • Sound files
    • Daisy port
    • Build rule when gen generated code changed
    • Skeleton project generation
    • Memory management
    • Build simulator from Max
  • Test
  • Figure out why Oopsy is not using DTCMRAM for State
  • Figure out why Oopsy is not using the C7 ARM math
  • Figure out why Oopsy is using out for output parameters rather than the more practical history (as seen in their paper)
  • Make Erbb Max generator
  • Make Erbui Max generator
  • Add sample code Reverb
  • Add sample code Drum
  • Update documentation
  • Integrate license

UI must be ctored before DSP

For now, the UI part of a module must be constructed before its DSP, to ensure correct initialization sequence.

For example:

struct Reverb {
   ReverbDsp dsp;
   ReverbUi ui;
};

Is most likely to crash as soon as the dsp needs to allocate in the SDRAM.

This is because the Daisy platform is inited in the board, which is done during the UI construction.

This is very error prone.

To remedy this, since we are generating a main per platform, and in particular one for Daisy, we could move the critical part of the board setup to early main.

Add sdram_ptr smart pointer for SDRAM allocation

Overview

Tackle the "allocating into SDRAM" problem, by making it explicit to the project user, while not punishing them when they come from a desktop software experience, because of lack of knowledge, as the learning curve can be quite steep.

This "allocation system", that would still help people to learn, while keeping good embedded practices, has the following properties:

  • A sdram_ptr template that allocates into SDRAM with a semantic similar to std::unique_ptr,
  • Instead of managing a memory pool and allow fragmentation, addresses would always grow until they reach the memory limit, acknowledging the embedded practices (ie. bounding resources),
  • Make the allocation algorithm concurrent,
  • Play nice with other systems using sdram_bss section attribute for the whole memory pool.

It is still unclear if destroying a owning sdram_ptr should break into the debugger (as it is leaking memory), but that could be an option.

The simulator could help to:

  • Issue a warning when a owning sdram_ptr is destroyed,
  • Break into the debugger if the consumed memory is more than available (at most 64MB for the Daisy platform).

Finally for learning, breaking into the debugger should have a link next to it to redirect to a page that explains memory "allocation" on embedded platforms, and how this differs from desktop software development.

Usage

struct ReverbSc {
   struct DelayLines {...};
   ReverbSc ();
   
   erb::sdram_ptr <DelayLines> delays;
}

void init () {
   ReverbSc reverb_sc1;
   ReverbSc reverb_sc2;
   
   // jobs done!
}

IDE generated project may look messy

The IDE generated project contains both the simulator target and daisy target. The latter won't be compiled into the IDE and is therefore some noise for the user of the framework.

However it may be important for the framework developer, to navigate the framework files conveniently.

Add an option to segregate between those two personas.

Example for contributor/maintainer:

$ ./configure.py --dev

Example for user:

$ ./configure.py

Still, the daisy ninja files are created in this case. It's just that the erb-daisy targets are hidden.
Ultimately, compiling target All shouldn't show any error.

Simulator stack size check is wrong

We were assuming incorrectly that the stack was 512K, when it is only 128K.

In the simulator version of the module, we make a check for the size of the module structure.

Adapt the check so that if the structure is more than 128K, then we know that it is too much:

  • There is also the stack use for functions anyway,
  • We can't be really precise because the memory layout on x86_64 will most likely be different than on arm 32-bit.

Data elements should be defined in erbb, not erbui

Data elements should be define in erbb, not erbui. Also be more consistent with the language:

module Kick {
   sources {
      file "Kick.cpp"
      file "Kick.h"
   }
   
   resources {
      data kick AudioSample { file "kick.wav" }
   }
}

Keep resources a separate keyword, so we can group resources logically, and more specifically when we will introduce the concept of destination section (ie qspi, flash, program, etc.)

Erbui GUI Editor

The current way to edit the UI in erbui is far from optimal. This is the feedback we have for the moment and how to address it:

Problems with erbui

  • It's hard to layout a GUI without good skills in either Inkscape or Illustrator
  • Template don't really help to layout
  • It's hard to remember all styles for each control
  • Making small adjustements is long (when not using a graphical editor)
  • It's impossible to see when a control is colliding with a pin socket
  • It's impossible to see when 2 controls are too close and:
    • Either, the underlying footprints collide
    • Or, there is not enough space for fingers between pots

What Users Want

  • They want to get started with a new project idea quickly
    • Even if the control placement is not optimal
  • They want to iterate with their project idea quickly
    • Even if the control placement is not optimal
  • They want a list of styles available for a control
    • Completion in the IDE project text editor was suggested
  • They want a check to know if a control is misplaced (too close, collision, etc.)
    • Some sort of DRC check was suggested
  • They want to be able to make small position adujstement and see the result in realtime
    • Being able to move the controls from within VCV Rack was suggested

Proposition: a GUI Editor

A GUI editor for erbui appears to be a good solution:

  • Placement or repositioning is immediate
  • Feedback is immediate
  • It's possible to have a list of styles or controls in a drop-down menu or browser
  • Have some sort of "X-ray view" which displays control footprints and board pin sockets
    • This could be done everytime a control is moved

Ideally, the editor could be bootstrapped immediately, so an implementation in Python would be a good idea.

Tasks

  • Evaluate different technologies for GUI using Python
  • Implement GUI editor
  • Add erbb gui command

Simplify erbb install usage

Currently, the erbb install command is not great:

  • As soon as openocd is installed, it is used instead of dfu-util which might be unsetting, if the user doesn't have a stlink programmer,
  • erbb install should probably use dfu-util by default,
  • openocd is probably a bad command option, since it mentions the tooling rather than was system is used. Maybe jtag or stlink would be better
  • erbb install bootloader would feel more natural than erbb bootloader

Additionally, the DFU util error is a bit misleading, so something should be done about that, to report success.

Test kivu12 rev3

Test kivu12 rev3

Tasks

  • Make Kivu12Max module?
    • Have all possible inputs/outputs in one module
    • Maybe no front plate
  • Order kivu12 PCB
  • Order drop PCB
  • Order BOM, in particular
    • BAT54SW
    • Resistor for I2C
    • All new pin sockets
  • Assemble kivu12
  • Assemble drop
  • Test

Samples/Drop will crash VCV Rack when launched from Xcode debugger with default launch option

Steps to reproduce:

  • run configure.py for samples/drop,
  • open the Xcode project drop.xcodeproj in the drop/artifacts folder,
  • Edit scheme for drop-vcvrack target in the IDE to launch the Rack application,
  • Choose Launch option to be Automatically (the default one),
  • Disable Document Versions in Option Tab (to prevent unrecognized launch argument options for VCV Rack).

When running the target from Xcode, Rack will crash.

init is called 2 times, and will assert when adding the model a second time (because it was already added).

Workarounds:

  • Either run Rack without the Xcode debugger fixes that problem,
  • Or, choosing Launch option Wait for executable to be launched fixes that problem as well.

Add QSPI deployment support

The Daisy QSPI 8MB Flash is going to be used for programs that can't fit into the small STM32 flash.

This is even more important with the addition of the data language feature, which stores small resources directly into the program, making the 128K most likely very tight when using samples like transients.

Check to see if this can be only done with USB, and generally how to manage JTAG debugging after.

Take time to see how to enhance the workflow, in particular for the first hour, when the bootloader is most likely not present.

Add the section keyword in erbb:

module Kick {
   section qspi   // or flash (default)
   
   sources {
      file "Kick.cpp"
      file "Kick.h"
   }
   
   resources {
      // section sdmmc (in the future resources could have an associated section too)
      // for now "same as module" is assumed.
      data body AudioSample { file "body.wav" }
      data transient01 AudioSample { file "transient01.wav" }
   }
}

Path to build system is wrong in generate_vcvrack script

The path to build system is wrong in the generate_vcvrack.py script.

Therefore, one cannot make changes to UI from within the IDE.

python3 artifacts/generate_vcvrack.py "KickCut24.erbui"
Traceback (most recent call last):
  File "artifacts/generate_vcvrack.py", line 20, in <module>
    import erbui
ModuleNotFoundError: No module named 'erbui'
make: *** [artifacts/deploy_vcvrack.py] Error 1

This is because the path is relative and hardcoded.

Workaround: call configure.py for each UI changes instead.

Remove erbb_flash_lds from modules gyp files

Remove the erbb_flash_lds variable from modules gyp files.

This variable was introduced to specify which linker script to use at build time, most likely because the path for the linker was a bit different, and we couldn't find a way back then to integrate it into the erb-daisy dependency.

  • Hiding this implementation detail will also help with #219

tl1105 generates an error when generating front PCB

tl1105 button style generates an error when generating front PCB.

This because the move component function is not implemented for this button.

unsupported block tl1105
Traceback (most recent call last):
  File "./build.py", line 74, in <module>
    erbui.generate_front_pcb (PATH_ARTIFACTS, ast)
  File "/Users/raf/dev/eurorack-blocks/build-system/erbui/__init__.py", line 209, in generate_front_pcb
    generate_front_pcb_kicad_pcb (path, ast)
  File "/Users/raf/dev/eurorack-blocks/build-system/erbui/__init__.py", line 221, in generate_front_pcb_kicad_pcb
    generator.generate (path, ast)
  File "/Users/raf/dev/eurorack-blocks/build-system/erbui/generators/front_pcb/kicad_pcb.py", line 27, in generate
    self.generate_module (path, module)
  File "/Users/raf/dev/eurorack-blocks/build-system/erbui/generators/front_pcb/kicad_pcb.py", line 44, in generate_module
    self.generate_control (control)
  File "/Users/raf/dev/eurorack-blocks/build-system/erbui/generators/front_pcb/kicad_pcb.py", line 211, in generate_control
    component = self.move (component, control.position)
UnboundLocalError: local variable 'component' referenced before assignment

Add support for Z shell in erbb setup

Currently erbb setup infers that bash is the current shell, and will append its path to the .bash_profile.
If the current shell is not bash, we need to mitigate this:

  • By adding support to zsh which became the default shell on a fresh installation of the latest macOS operating systems,
  • By reporting a warning if another shell is used, for which we don't have support.

AXI SRAM Allocation

The project provides SdramPtr which allows to allocate in the external SDRAM chip, but doesn't have the facility to allocate into the internal SRAM.

Add a SramPtr template class on the same model as SdramPtr which provides this feature.

Tasks:

  • Implement it
  • Test it with Reverb sample

Erbb meta-build System

The current build system is far from optimal. This is the feedback we have for the moment and how to address it:

Problems with Current Build system

  • gyp is not famous compared to cmake
  • Generated targets contain noise
    • Daisy targets are now only relevant to the erb contributor/maintainer, not the user
  • SdRam depends on erb_TARGET_XXX
  • data feature is in the erbui language but should be part of build system, because it doesn't represent a UI element
  • Boilerplate configure.py and build.py scripts in each module

What Users Want

  • They want to get started with a new project idea quickly
    • Being able to create a new module skeleton quickly is a potential solution
  • They want the project "simple"
    • Move away project commands such as configure or build which are just noise
    • Avoid the "what target should I build" IDE problem and noise
    • Target IDE subtleties is noise, so abstract it away
    • Not so much code to compile so we can put everything in one target to minimize project complexity/noise
  • They still want a concept of "library" to group sources and resources logically
    • Usually per folder, typically a DSP library
    • But they don't need to have a proper target for it, as there is no need to share targets
      • As we have only one module in a project anyway
  • They want to specify whether their code will be in Flash or QSPI
    • But this would be even better if automated, if possible
  • They want to specify where to fetch their static data
    • But this would be even better if automated, if possible

What Contributors/Maintainers Want

  • They want to be able to have all the project sources for both Daisy and simulator targets in one project

erbb Language

cmake coud be something, but we have lots of very specific things for cross-compiling that would make the syntax most likely cryptic.

Instead of that, we will roll out a small language that takes into account everything upper.

module Kick {
   location flash    // or qspi

   import "../dsp/dsp.erbb"
   
   define erb_SDRAM_MEM_POOL_SIZE=1234
   define erb_SDRAM_MEM_POOL_SIZE_SIMULATOR_CHECK=0
   
   sources {
      file "Kick.cpp"
      file "Kick.h"
   }
   
   resources {
      // for now location is the same as module
      data body AudioSample { file "body.wav" }
      data transient01 AudioSample { file "transient01.wav" }
   }
}

dsp.erbb

define SOMETHING=1

// not sure yet which term for header search path
search ".."
base ".."
origin ".."
root ".."
include ".."
directory ".."

sources {
   file "Filter2Poles.cpp"
   file "Filter2Poles.h"
}

resources {
   // resources for an oscillator for example
}

erbb Command Line Interface

We would have a command line erbb.

Usage

Create everything to be able to build (IDE project, and all genrated code/graphic resources):

$ erbb configure

This would also install all binary dependencies if needed. erbb setup could also force it.

Build the firmware:

$ erbb build

Install the bootloader:

$ erbb install bootloader
Press RESET + BOOT and hit any key to start the bootloader install
...

Install the firmware:

$ erbb install
Press RESET and hit any key to start the bootloader install
...

Install

Somehow, erbb needs to be in the PATH.

Either:

  • Make a script to source it
  • Or, gives instructions to add erbb to the PATH
  • Or, a combination of both, to source it from .profile or .bash_profile

Tasks

  • Reduce number of targets (in the gyp sense) in a project
  • Implement erbb language
  • Add erbb Xcode syntax highlighter
  • Add erbb simulator gyp generator
  • Add erbb Daisy gyp generator
  • Add erbb VSCode gyp generator
  • Add erbb command line and env init sourcing script
  • Cleanup unused scripts and gyp files
  • Add language documentation

Add front pcb autorouting

Overview

Autoroute the front PCB to save time.

For now, the front PCB exposes pads with name, and the user needs to air wire all pads with the name name. We made just a tad simpler by having planes for both GND and 3V3, which reduces the number of things to solder.

The freerouting project is the defacto autorouteur for KiCad 5, since the included autorouteur was removed from KiCad 4.

Fortunately, the freerouting autorouteur:

  • Is probably good enough given our very simple need,
  • Is free, open source, and uses Java, so works on Linux, macOS and Windows,
  • Has a command line interface.

Current Status

On branch front-pcb-autorouter.

PAUSED

KiCad 5.1 doesn't include in the python bindings the functions we need. We decided to wait for the release of KiCad 6.0 before continuing on this issue. This release should be quite imminent, has rc1 has been around since some time already.

AudioSample should have a way to behave like a polymorphic type

Because all audio samples are concrete types with template parameters already configured, it is hard to manipulate them as some sort of abstract type, for example:

  • To organise samples in an std::array, even though the concrete types are different types (because the samples length are different for example)
  • Being able to call a function which takes a sample as a parameter without having to know the type and use templates for that

This problem is quite apparent in the Kick sample, for example on how we handle transients. This leads to this weird design, where all transients need to have exactly the same length, just so that they happen to be the same type.

Fix this by making some sort of AudioSample polymorphic type. Since we are representing a 2d array, we need to acknowledge that and represents the offset to next frame, and the offset to next channel.

As for grouping samples by meaning in an std::array, we could make erbb resources have an optional name that would group elements in resources with that name and find the best class that keeps resources homogeneity (for example AudioSample if it contains only AudioSample types, at worst a Data polymorphic type). For example:

AudioSampleMono_ <float> // all are mono samples with different lengths
AudioSampleInterleaved_ <float, 2> // all are interleaved stereo samples with different lengths
AudioSample <float> // any kind of samples

Usage:

module Kick {
   resources {
      data body AudioSample { file "body.wav" }
   }

   resources transients {
      data t01 AudioSample { file "transient01.wav" }
      data t02 AudioSample { file "transient02.wav" }
      ...
      data t18 AudioSample { file "transient18.wav" }
   }
}

Generated code:

struct KickData
{
   static const erb::AudioSampleMono <float, 38320> body;

   struct ResourcesType_transients {
      static const erb::AudioSampleMono <float, 38400> t01;
      static const erb::AudioSampleMono <float, 38400> t02;
      static const erb::AudioSampleMono <float, 38400> t03;
      static const erb::AudioSampleMono <float, 38400> t04;
      static const erb::AudioSampleMono <float, 38400> t05;
      static const erb::AudioSampleMono <float, 38400> t06;
      static const erb::AudioSampleMono <float, 38400> t07;
      static const erb::AudioSampleMono <float, 38400> t08;
      static const erb::AudioSampleMono <float, 20100> t09; // different length
      static const erb::AudioSampleMono <float, 38400> t10;
      static const erb::AudioSampleMono <float, 38400> t11;
      static const erb::AudioSampleMono <float, 38400> t12;
      static const erb::AudioSampleMono <float, 38400> t13;
      static const erb::AudioSampleMono <float, 38400> t14;
      static const erb::AudioSampleMono <float, 38400> t15;
      static const erb::AudioSampleMono <float, 38400> t16;
      static const erb::AudioSampleMono <float, 38400> t17;
      static const erb::AudioSampleMono <float, 38400> t18;

      using value_type = erb::AudioSampleMono_ <float>; // AudioSampleMono_ is the best common type
      constexpr size_t size () const { return 18; }
      const value_type & operator [] (size_t index);
   } transients;
};

Usage:

// static
do_something (data.transients.t10);

// dynamic
do_something (data.transients [9]); // can throw on simulator, clamp bounds on daisy, or break if DEBUG is activated

Update reverb documentation

Reverb documentation still references the old make_sdram_object method, and doesn't explain how to use erb::SdramPtr instead.

Project doesn't build on Xcode 13

Some files from VCV Rack and erb have errors, for example:

submodules/vcv-rack-sdk/include/midi.hpp:152:2: '~Input' overrides a destructor but is not marked 'override'

Show help when build system script encounter an import error

When a configure, build or deploy script python import is failing, this most likely indicates an install problem, which in most cases could be related to the user not finding the documentation about setting up the project.

If we detect an import error, then we should display at least the link to the setup documentation.

This is very important, as this most likely will appear in the first minute of the user's evaluation.

SD/MMC data support

Add SD and MMC support for data location in memory.

Current State

  • This overlaps with #238 so pause this feature for a bit

Overview

data represents an immutable piece of data, available as soon as the module is started.
For now the data itself was stored as static data in the program itself, but realistically, we need QSPI support (#219) to support this feature fully.

Alternatively, we can use the SD feature to provide basically the same thing, except the data is loaded from SD to SDRAM when the module is started.

Implementation

For now we have the following scheme, where the data is stored into the program.

data sample {
   file "bla.wav"
   type AudioSample
}

We can extend the data attributes with location which dictates where data is stored:

data sample {
   file "foo.wav"
   type AudioSample
   location program  // default if not specified
}

data sample2 {
   file "bar.wav"
   type AudioSample
   location sdmmc    // in SD or "back MMC" on board
}

For the sdmmc location, no program is generated. Instead we create a .bin file which is a byte per byte representation of what the program location does.

When starting the module, the data location in SDRAM is filled with the content of the .bin file. The data is either truncated or complemented with zeros if the file size doesn't match.

For this feature to work, the current types (like AudioSample) must have at most one dynamic length. As a result for AudioSample for example, we need to go from a planar representation to an interleaved one.

Finally, because the data is stored in SDRAM, we need to play nice with the system we already have in place, by either:

  • Calculating the amount of space needed for data (and aligning appropriately) and remove it from the amount available from our SdRamPtr system,
  • Use our SdramPtr system.

Tasks

  • Make AudioSample type interleaved
  • Figure out how to integrate nicely with current SdramPtr system
  • Add location attribute to language
  • Add location attribute documentation
  • Add location generator support
  • Test in simulator
  • Test on target hardware

Make an overview video and "Getting Started" guide

The current state of the project doesn't include a call-to-action that would lead to a successful feeling in the 5-minutes and first-hour of evaluation milestones.

  • Direct the user to first watch an overview video and then read the "Getting Started" guide,
  • Add a less than 5 minutes overview video to show the end-to-end process of making a Eurorack module from conception to use in a Eurorack system,
  • Add a less than 1 hour complete guide, to show in details the end-to-end process of making a Eurorack module from conception to use in a Eurorack system, with at least text and pictures, video at most.

As for strategy, first start by writing the guide and getting feedback about it, before we get into shooting the video, as it will be easier to integrate feedback for some text and pictures rather than a video edit.

Chapters

  • Overview
  • Setting up dev environment
  • Developing the software and testing in the simulator
  • Ordering PCB/BOM and assembling kivu12
  • Ordering PCB/BOM and assembling the module

Tasks

  • Write "Getting Started" guide
  • Get feedback for "Getting Started" guide
  • Iterate "Getting Started" guide
  • Write overview video script
  • Get feedback for overview video script
  • Shoot overview video draft
  • Review draft & script
  • Shoot overview video
  • Integrate to project

Add erbui data keyword

Overview

Provide a way to access conveniently and in a portable way (for both the Daisy and simulator platform), user-defined and immutable pieces of data, typically small samples for oscillators, transients or wave tables.

Usage

module Sampler {
   board kivu12
   
   data sample01 {
      file "data/sample01.wav"
      type AudioSample
   }

   control audio_out AudioOut {
      pin AO1
   }
}
struct Sampler {
   SamplerDsp dsp { erb_SAMPLE_RATE };
   SamplerUi ui;
   SamplerData data;
   
   void  process () {
      auto pos = ...;
      ui.audio_out [pos] = data.sample01.samples [pos];
   }
}

Implementation

Based on the type, a dispatcher is used to generate a C++ file in the artifacts folder.
Typically the script will take an input file path, the data name, the type used with its arguments, and an output file path.
It will populate the output file with C++ so that it can be used directly. For example it would generate:

// artifacts/SamplerData.h

#include "erb/erb.h"

struct SamplerData {
   static constexpr erb::AudioSample <float, 14938> sample01 = {
      .sample_rate = 48000,
      .samples = { 0x123456789p0f, ... }
   };
};

This will be done by implementing a new code generator. For now, only framework provided type will be supported. ie., it won't be possible to provide custom user types.

When type is not specified, the raw data is used instead, using an std::array <uint8_t, size_of_the_file>.

The implementation relies on the fact that we will transition our programs to the QSPI flash soon.

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.