Mercurial > hg > beaglert
changeset 464:8fcfbfb32aa0 prerelease
Examples reorder with subdirectories. Added header to each project. Moved Doxygen to bottom of render.cpp.
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/01-Basics/minimal/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,120 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <Bela.h> + + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. +bool setup(BelaContext *context, void *userData) +{ + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. +void render(BelaContext *context, void *userData) +{ + +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** + +\example 01-minimal + +The bare bones +---------------------- + +The structure of a render.cpp file +---------------------------------- +A render.cpp file has three functions: `setup()`, `render()` and `cleanup()`. + +`setup()` is an initialisation function which runs before audio rendering begins. +It is called once when the project starts. Use it to prepare any memory or +resources that will be needed in `render()`. + +`render()` is a function that is regularly called, over and over continuously, at +the highest priority by the audio engine. It is used to process audio and +sensor data. This function is called regularly by the system every time there +is a new block of audio and/or sensor data to process. + +`cleanup()` is a function that is called when the program stops, to finish up any +processes that might still be running. + +Here we will briefly explain each function and the structure of the render.cpp + +Before any of the functions +--------------------------- +At the top of the file, include any libraries you might need. + +Additionally, declare any global variables. In these tutorial sketches, all +global variables are preceded by a `g` so we always know which variables are +global - `gSampleData`, for example. It's not mandatory but is a really good way +of keeping track of what's global and what's not. + +Sometimes it's necessary to access a variable from another file, such as +main.cpp. In this case, precede this variable with the keyword `extern`. + +Function arguments +------------------ +`setup()`, `render()` and `cleanup()` each take the same arguments. These are: + +`0ext *context` +`void *userData` + +These arguments are pointers to data structures. The main one that's used is +`context`, which is a pointer to a data structure containing lots of information +you need. + +Take a look at what's in the data structure [here] +(https://code.soundsoftware.ac.uk/projects/beaglert/embedded/structBeagleRTContext.html). + +You can access any of these bits of information about current audio and sensor +settings and pointers to data buffers that are contained in the data structure +like this: `context->name_of_item`. + +For example, `context->audioChannels` returns the number of audio channels. +`context->audioSampleRate` returns the audio sample rate. +`context->audioIn[n]` would give you the current input sample (assuming that +your input is mono - if it's not you will have to account for multiple channels). + +Note that `audioIn`, `audioOut`, `analogIn`, `analogOut` are all arrays (buffers). + +*/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/01-Basics/passthrough/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,107 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "h", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, 0) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/01-Basics/passthrough/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,119 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <Bela.h> +#include <rtdk.h> + +bool setup(BelaContext *context, void *userData) +{ + // Nothing to do here... + return true; +} + +void render(BelaContext *context, void *userData) +{ + // Simplest possible case: pass inputs through to outputs + for(unsigned int n = 0; n < context->audioFrames; n++) { + for(unsigned int ch = 0; ch < context->audioChannels; ch++){ + // Two equivalent ways to write this code + + // The long way, using the buffers directly: + // context->audioOut[n * context->audioChannels + ch] = + // context->audioIn[n * context->audioChannels + ch]; + + // Or using the macros: + audioWrite(context, n, ch, audioRead(context, n, ch)); + } + } + + // Same with analog channelss + for(unsigned int n = 0; n < context->analogFrames; n++) { + for(unsigned int ch = 0; ch < context->analogChannels; ch++) { + // Two equivalent ways to write this code + + // The long way, using the buffers directly: + // context->analogOut[n * context->analogChannels + ch] = context->analogIn[n * context->analogChannels + ch]; + + // Or using the macros: + analogWrite(context, n, ch, analogRead(context, n, ch)); + } + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 01-passthrough + +Audio and analog passthrough: input to output +----------------------------------------- + +This sketch demonstrates how to read from and write to the audio and analog input and output buffers. + +In `render()` you'll see a nested for loop structure. You'll see this in all Bela projects. +The first for loop cycles through `audioFrames`, the second through +`audioChannels` (in this case left 0 and right 1). + +You can access any information about current audio and sensor settings you can do the following: +`context->name_of_item`. For example `context->audioChannels` returns current number of channels, +`context->audioFrames` returns the current number of audio frames, +`context->audioSampleRate` returns the audio sample rate. + +You can look at all the information you can access in ::BeagleRTContext. + +Reading and writing from the audio buffers +------------------------------------------ + +The simplest way to read samples from the audio input buffer is with +`audioRead()` which we pass three arguments: context, current audio +frame and current channel. In this example we have +`audioRead(context, n, ch)` where both `n` and `ch` are provided by +the nested for loop structure. + +We can write samples to the audio output buffer in a similar way using +`audioWrite()`. This has a fourth argument which is the value of the output. +For example `audioWrite(context, n, ch, value_to_output)`. + +Reading and writing from the analog buffers +------------------------------------------- + +The same is true for `analogRead()` and `analogWrite()`. + +Note that for the analog channels we write to and read from the buffers in a separate set +of nested for loops. This is because the they are sampled at half audio rate by default. +The first of these for loops cycles through `analogFrames`, the second through +`analogChannels`. + +By setting `audioWriteFrame(context, n, ch, audioReadFrame(context, n, ch))` and +`analogWrite(context, n, ch, analogReadFrame(context, n, ch))` we have a simple +passthrough of audio input to output and analog input to output. + + +It is also possible to address the buffers directly, for example: +`context->audioOut[n * context->audioChannels + ch]`. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/01-Basics/scope/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,102 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <Bela.h> +#include <Scope.h> +#include <cmath> + +// set the frequency of the oscillators +float gFrequency = 110.0; +float gPhase; +float gInverseSampleRate; + +// instantiate the scope +Scope scope; + +bool setup(BelaContext *context, void *userData) +{ + // tell the scope how many channels and the sample rate + scope.setup(3, context->audioSampleRate); + + gPhase = 0; + gInverseSampleRate = 1.0f/context->audioSampleRate; + + return true; +} + +float lastOut = 0.0; +float lastOut2 = 0.0; +void render(BelaContext *context, void *userData) +{ + // iterate over the audio frames and create three oscillators, seperated in phase by PI/2 + for (unsigned int n=0; n<context->audioFrames; n++){ + float out = 0.8f * sinf(gPhase); + float out2 = 0.8f * sinf(gPhase - M_PI/2); + float out3 = 0.8f * sinf(gPhase + M_PI/2); + gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; + if(gPhase > 2.0 * M_PI) + gPhase -= 2.0 * M_PI; + + // log the three oscillators to the scope + scope.log(out, out2, out3); + + // optional - tell the scope to trigger when oscillator 1 becomes less than oscillator 2 + // note this has no effect unless trigger mode is set to custom in the scope UI + if (lastOut >= lastOut2 && out < out2){ + scope.trigger(); + } + + lastOut = out; + lastOut2 = out2; + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 01-scope + +Oscilloscope in-browser +----------------------- + +This example demonstrates the scope feature of the IDE. + +The scope is instantiated at the top of the file via `Scope scope;` + +In `setup()` we define how many channels the scope should have and the sample +rate that it should run at via `scope.setup(3, context->audioSampleRate)`. + +In `render()` we choose what the scope log via `scope.log(out, out2, out3)`. +In this example the scope is logging three sine waves with different phases. To see +the output click on the <b>Open Scope</b> button. + +An additional option is to set the trigger of the oscilloscope from within `render()`. +In this example we are triggering the scope when oscillator 1 becomes less than +oscillator 2 via `scope.trigger()`. Note that this functionality only takes effect +when the triggering mode is set to custom in the scope UI. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/01-Basics/sinetone/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,114 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <unistd.h> +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + float frequency = 440.0; // Frequency of oscillator + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"frequency", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + frequency = atof(optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &frequency) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/01-Basics/sinetone/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,86 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <Bela.h> +#include <cmath> + +float gFrequency = 440.0; +float gPhase; +float gInverseSampleRate; + +bool setup(BelaContext *context, void *userData) +{ + // Retrieve a parameter passed in from the initAudio() call + if(userData != 0) + gFrequency = *(float *)userData; + + gInverseSampleRate = 1.0 / context->audioSampleRate; + gPhase = 0.0; + + return true; +} + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + float out = 0.8f * sinf(gPhase); + gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; + if(gPhase > 2.0 * M_PI) + gPhase -= 2.0 * M_PI; + + for(unsigned int channel = 0; channel < context->audioChannels; channel++) { + // Two equivalent ways to write this code + + // The long way, using the buffers directly: + // context->audioOut[n * context->audioChannels + channel] = out; + + // Or using the macros: + audioWrite(context, n, channel, out); + } + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 01-sinetone + +Producing your first bleep! +--------------------------- + +This sketch is the hello world of embedded interactive audio. Better known as bleep, it +produces a sine tone. + +The frequency of the sine tone is determined by a global variable, `gFrequency` +(line 12). The sine tone is produced by incrementing the phase of a sin function +on every audio frame. + +In render() you'll see a nested for loop structure. You'll see this in all Bela projects. +The first for loop cycles through 'audioFrames', the second through 'audioChannels' (in this case left 0 and right 1). +It is good to familiarise yourself with this structure as it's fundamental to producing sound with the system. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/02-Digital/digital-input/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,82 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> +#include <rtdk.h> +#include <stdlib.h> + + +bool setup(BelaContext *context, void *userData) +{ + pinMode(context, 0, P8_08, INPUT); + pinMode(context, 0, P8_07, OUTPUT); + return true; +} + + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n=0; n<context->digitalFrames; n++){ + int status=digitalRead(context, 0, P8_08); //read the value of the button + digitalWriteOnce(context, n, P8_07, status); //write the status to the LED + float out = 0.1 * status * rand() / (float)RAND_MAX * 2 - 1; //generate some noise, gated by the button + for(unsigned int j = 0; j < context->audioChannels; j++){ + audioWrite(context, n, j, out); //write the audio output + } + } +} + + +void cleanup(BelaContext *context, void *userData) +{ + // Nothing to do here +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 02-digital-input + +Switching an LED on and off +--------------------------- + +This example brings together digital input and digital output. The program will read +a button and turn the LED on and off according to the state of the button. + +- connect an LED in series with a 470ohm resistor between P8_07 and ground. +- connect a 1k resistor to P9_03 (+3.3V), +- connect the other end of the resistor to both a button and P8_08 +- connect the other end of the button to ground. + +You will notice that the LED will normally stay on and will turn off as long as +the button is pressed. This is due to the fact that the LED is set to the same +value read at input P8_08. When the button is not pressed, P8_08 is `HIGH` and so +P8_07 is set to `HIGH` as well, so that the LED conducts and emits light. When +the button is pressed, P8_08 goes `LOW` and P8_07 is set to `LOW`, turning off the LED. + +As an exercise try and change the code so that the LED only turns on when +the button is pressed. +*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/02-Digital/digital-output/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,89 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> +#include <rtdk.h> + +bool setup(BelaContext *context, void *userData) +{ + pinMode(context, 0, P8_07, OUTPUT); + return true; +} + +void render(BelaContext *context, void *userData) +{ + static int count=0; //counts elapsed samples + float interval=0.5; //how often to toggle the LED (in seconds) + static int status=GPIO_LOW; + for(unsigned int n=0; n<context->digitalFrames; n++){ + if(count==context->digitalSampleRate*interval){ //if enough samples have elapsed + count=0; //reset the counter + // status=digitalRead(context, 0, P8_07); + if(status==GPIO_LOW) { //toggle the status + digitalWrite(context, n, P8_07, status); //write the status to the LED + status=GPIO_HIGH; + } + else { + digitalWrite(context, n, P8_07, status); //write the status to the LED + status=GPIO_LOW; + } + } + count++; + } +} + +void cleanup(BelaContext *context, void *userData) +{ + // Nothing to do here +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 02-digital-output + +Blinking an LED +--------------- + +This sketch shows the simplest case of digital out. + +- Connect an LED in series with a 470ohm resistor between P8_07 and ground. + +The led is blinked on and off by setting the digital pin `HIGH` and `LOW` every interval seconds which is set in +`render()`. + +In `setup()` the pin mode must be set to output mode via `pinMode()`. For example: +`pinMode(context, 0, P8_07, OUTPUT)`. +In `render()` the output of the digital pins is set by `digitalWrite()`. For example: +`digitalWrite(context, n, P8_07, status)` where `status` can be equal to +either `HIGH` or `LOW`. When set `HIGH` the pin will give 3.3V, when set to +`LOW` 0V. + +To keep track of elapsed time we have a sample counter count. When the count reaches +a certain limit it switches state to either `HIGH` or `LOW` depending on its current +value. In this case the limit is `context->digitalSampleRate*interval` which +allows us to write the desired interval in seconds, stored in `interval`. +*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/02-Digital/level-meter/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,138 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> + +#define NUMBER_OF_SEGMENTS 10 + +// Two levels of audio: one follows current value, the other holds +// peaks for longer +float gAudioLocalLevel = 0, gAudioPeakLevel = 0; + +// Decay rates for detecting levels +float gLocalDecayRate = 0.99, gPeakDecayRate = 0.999; + +// Thresholds for LEDs: set in setup() +float gThresholds[NUMBER_OF_SEGMENTS + 1]; +int gSamplesToLight[NUMBER_OF_SEGMENTS]; + +// High-pass filter on the input +float gLastX[2] = {0}; +float gLastY[2] = {0}; + +// These coefficients make a high-pass filter at 5Hz for 44.1kHz sample rate +double gB0 = 0.99949640; +double gB1 = -1.99899280; +double gB2 = gB0; +double gA1 = -1.99899254; +double gA2 = 0.99899305; + +bool setup(BelaContext *context, void *userData) +{ + // This project makes the assumption that the audio and digital + // sample rates are the same. But check it to be sure! + if(context->audioFrames != context->digitalFrames) { + rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n"); + return false; + } + + // Initialise threshold levels in -3dB steps. One extra for efficiency in render() + // Level = 10^(dB/20) + for(int i = 0; i < NUMBER_OF_SEGMENTS + 1; i++) { + gThresholds[i] = powf(10.0f, (-1.0 * (NUMBER_OF_SEGMENTS - i)) * .05); + } + + for(int i = 0; i < NUMBER_OF_SEGMENTS; i++) { + gSamplesToLight[i] = 0; + pinMode(context, 0, i, OUTPUT); + } + + return true; +} + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + // Get average of audio input channels + float sample = 0; + for(unsigned int ch = 0; ch < context->audioChannels; ch++) { + context->audioOut[n * context->audioChannels + ch] = + context->audioIn[n * context->audioChannels + ch]; + sample += context->audioIn[n * context->audioChannels + ch]; + } + + // Do DC-blocking on the sum + float out = gB0 * sample + gB1 * gLastX[0] + gB2 * gLastX[1] + - gA1 * gLastY[0] - gA2 * gLastY[1]; + + gLastX[1] = gLastX[0]; + gLastX[0] = sample; + gLastY[1] = gLastY[0]; + gLastY[0] = out; + + out = fabsf(out / (float)context->audioChannels); + + // Do peak detection: fast-responding local level + if(out > gAudioLocalLevel) + gAudioLocalLevel = out; + else + gAudioLocalLevel *= gLocalDecayRate; + + // Do peak detection: slow-responding peak level + if(out > gAudioPeakLevel) + gAudioPeakLevel = out; + else { + // Make peak decay slowly by only multiplying + // every few samples + if(((context->audioFramesElapsed + n) & 31) == 0) + gAudioPeakLevel *= gPeakDecayRate; + } + // LED bargraph on digital outputs 0-9 + for(int led = 0; led < NUMBER_OF_SEGMENTS; led++) { + // All LEDs up to the local level light up. The LED + // for the peak level also remains lit. + int state = LOW; + + if(gAudioLocalLevel > gThresholds[led]) { + state = HIGH; + gSamplesToLight[led] = 1000; + } + /*else if(gAudioPeakLevel > gThresholds[led] && gAudioPeakLevel <= gThresholds[led + 1]) { + state = HIGH; + gSamplesToLight[led] = 1000; + }*/ + else if(--gSamplesToLight[led] > 0) + state = HIGH; + + // Write LED + digitalWriteOnce(context, n, led, state); + } + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/03-Analog/analog-input/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,133 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +int gSensorInputFrequency = 0; +int gSensorInputAmplitude = 1; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --frequency [-f] input: Choose the analog input controlling frequency (0-7; default 0)\n"; + cerr << " --amplitude [-a] input: Choose the analog input controlling amplitude (0-7; default 1)\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"frequency", 1, NULL, 'f'}, + {"amplitude", 1, NULL, 'a'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:a:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + gSensorInputFrequency = atoi(optarg); + if(gSensorInputFrequency < 0 || gSensorInputFrequency > 7) { + usage(basename(argv[0])); + exit(0); + } + break; + case 'a': + gSensorInputAmplitude = atoi(optarg); + if(gSensorInputAmplitude < 0 || gSensorInputAmplitude > 7) { + usage(basename(argv[0])); + exit(0); + } + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, 0) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + if(settings.verbose) { + cout << "--> Frequency on input " << gSensorInputFrequency << endl; + cout << "--> Amplitude on input " << gSensorInputAmplitude << endl; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/03-Analog/analog-input/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,114 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <rtdk.h> +#include <cmath> + +float gPhase; +float gInverseSampleRate; +int gAudioFramesPerAnalogFrame; + +// These settings are carried over from main.cpp +// Setting global variables is an alternative approach +// to passing a structure to userData in setup() + +extern int gSensorInputFrequency; +extern int gSensorInputAmplitude; + +bool setup(BelaContext *context, void *userData) +{ + if(context->analogFrames == 0 || context->analogFrames > context->audioFrames) { + rt_printf("Error: this example needs analog enabled, with 4 or 8 channels\n"); + return false; + } + + gAudioFramesPerAnalogFrame = context->audioFrames / context->analogFrames; + gInverseSampleRate = 1.0 / context->audioSampleRate; + gPhase = 0.0; + + return true; +} + +void render(BelaContext *context, void *userData) +{ + float frequency = 440.0; + float amplitude = 0.8; + + // There are twice as many audio frames as matrix frames since audio sample rate + // is twice as high + + for(unsigned int n = 0; n < context->audioFrames; n++) { + if(!(n % gAudioFramesPerAnalogFrame)) { + // Even audio samples: update frequency and amplitude from the matrix + frequency = map(analogRead(context, n/gAudioFramesPerAnalogFrame, gSensorInputFrequency), 0, 1, 100, 1000); + amplitude = analogRead(context, n/gAudioFramesPerAnalogFrame, gSensorInputAmplitude); + } + + float out = amplitude * sinf(gPhase); + + for(unsigned int channel = 0; channel < context->audioChannels; channel++) + context->audioOut[n * context->audioChannels + channel] = out; + + gPhase += 2.0 * M_PI * frequency * gInverseSampleRate; + if(gPhase > 2.0 * M_PI) + gPhase -= 2.0 * M_PI; + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 03-analog-input + +Connecting potentiometers +------------------------- + +This sketch produces a sine tone, the frequency and amplitude of which are +affected by data received on the analog pins. Before looping through each audio +frame, we declare a value for the frequency and amplitude of our sine tone +(line 55); we adjust these values by taking in data from analog sensors +(for example potentiometers) with `analogRead()`. + +- connect a 10K pot to 3.3V and GND on its 1st and 3rd pins. +- connect the 2nd middle pin of the pot to analogIn 0. +- connect another 10K pot in the same way but with the middle pin connected to analogIn 1. + +The important thing to notice is that audio is sampled twice as often as analog +data. The audio sampling rate is 44.1kHz (44100 frames per second) and the +analog sampling rate is 22.05kHz (22050 frames per second). On line 62 you might +notice that we are processing the analog data and updating frequency and +amplitude only on every second audio sample, since the analog sampling rate is +half that of the audio. + +Note that the pin numbers are stored in the variables `gAnalogInputFrequency` and +`gAnalogInputAmplitude`. These are declared in the main.cpp file; if you look in +that file you will see that they have the values of 0 and 1. Bear in mind that +these are analog input pins which is a specific header! +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/03-Analog/analog-output/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,121 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --frequency [-f] frequency: Set the frequency of the LED fade (default: 1.0)\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + float frequency = 1.0; // Frequency of LED fades + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"frequency", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // In this example, audio isn't used so might as well leave speaker muted + settings.beginMuted = 1; + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + frequency = atof(optarg); + if(frequency < 0) + frequency = 0; + if(frequency > 11025.0) + frequency = 11025.0; + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &frequency) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/03-Analog/analog-output/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,109 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <rtdk.h> +#include <cmath> + +// Set range for analog outputs designed for driving LEDs +const float kMinimumAmplitude = (1.5 / 5.0); +const float kAmplitudeRange = 1.0 - kMinimumAmplitude; + +float gFrequency; +float gPhase; +float gInverseSampleRate; + +bool setup(BelaContext *context, void *userData) +{ + // Retrieve a parameter passed in from the initAudio() call + gFrequency = *(float *)userData; + + if(context->analogFrames == 0) { + rt_printf("Error: this example needs the matrix enabled\n"); + return false; + } + + gInverseSampleRate = 1.0 / context->analogSampleRate; + gPhase = 0.0; + + return true; +} + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->analogFrames; n++) { + // Set LED to different phase for each matrix channel + float relativePhase = 0.0; + for(unsigned int channel = 0; channel < context->analogChannels; channel++) { + float out = kMinimumAmplitude + kAmplitudeRange * 0.5f * (1.0f + sinf(gPhase + relativePhase)); + + analogWrite(context, n, channel, out); + + // Advance by pi/4 (1/8 of a full rotation) for each channel + relativePhase += M_PI * 0.25; + } + + gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; + if(gPhase > 2.0 * M_PI) + gPhase -= 2.0 * M_PI; + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 03-analog-output + +Fading LEDs +----------- + +This sketch uses a sine wave to drive the brightness of a series of LEDs +connected to the eight analog out pins. Again you can see the nested `for` loop +structure but this time for the analog output channels rather than the audio. + +- connect an LED in series with a 470ohm resistor between each of the analogOut pins and ground. + +Within the first for loop in render we cycle through each frame in the analog +output matrix. At each frame we then cycle through the analog output channels +with another for loop and set the output voltage according to the phase of a +sine tone that acts as an LFO. The analog output pins can provide a voltage of +~4.092V. + +The output on each pin is set with `analogWrite()` within the for loop that +cycles through the analog output channels. This needs to be provided with +arguments as follows `analogWrite(context, n, channel, out)`. Channel is +where the you give the address of the analog output pin (in this case we cycle +through each pin address in the for loop), out is the variable that holds the +desired output (in this case set by the sine wave). + +Notice that the phase of the brightness cycle for each led is different. This +is achieved by updating a variable that stores a relative phase value. This +variable is advanced by pi/4 (1/8 of a full rotation) for each channel giving +each of the eight LEDs a different phase. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/03-Analog/scope-analog/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,102 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> +#include <Scope.h> + +Scope scope; + +float gInverseSampleRate; +float gPhase; + +bool setup(BelaContext *context, void *userData) +{ + + // setup the scope with 3 channels at the audio sample rate + scope.setup(3, context->audioSampleRate); + + gInverseSampleRate = 1.0 / context->audioSampleRate; + gPhase = 0.0; + + return true; +} + +void render(BelaContext *context, void *userData) +{ + + for(unsigned int n = 0; n < context->audioFrames; n++) { + + // read analogIn channels 0 and 1 + float in1 = analogRead(context, n, 0); + float in2 = analogRead(context, n, 1); + + // map in1 to amplitude and in2 to frequency + float amplitude = in1 * 0.8f; + float frequency = map(in2, 0, 1, 100, 1000); + + // generate a sine wave with the amplitude and frequency + float out = amplitude * sinf(gPhase); + gPhase += 2.0 * M_PI * frequency * gInverseSampleRate; + if(gPhase > 2.0 * M_PI) + gPhase -= 2.0 * M_PI; + + // log the sine wave and sensor values on the scope + scope.log(out, in1, in2); + + // pass the sine wave to the audio outputs + for(unsigned int channel = 0; channel < context->audioChannels; channel++) + context->audioOut[n * context->audioChannels + channel] = out; + + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 03-scope-analog + +Connecting potentiometers +------------------------- + +This example reads from analogue inputs 0 and 1 via `analogReadFrame()` and +generates a sine wave with amplitude and frequency determined by their values. +It's best to connect a 10K potentiometer to each of these analog inputs. Far +left and far right pins of the pot go to 3.3V and GND, the middle should be +connected to the analog in pins. + +The sine wave is then plotted on the oscilloscope. Click the Open Scope button to +view the results. As you turn the potentiometers you will see the amplitude and +frequency of the sine wave change. + +This project also shows as example of `map()` which allows you to re-scale a number +from one range to another. Note that `map()` does not constrain your variable +within the upper and lower limits. If you want to do this use the `constrain()` +function. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/FFT-audio-in/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,116 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --fftsize [-s] size: Set the fSize of the FFT, in samples\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + int fftSize = 64; // Size of the FFT, in samples + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"fftsize", 1, NULL, 's'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + +// settings.useAnalog = 0; // No matrix usage by default + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hs:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 's': + fftSize = atof(optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &fftSize) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/FFT-audio-in/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,111 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <rtdk.h> +#include <ne10/NE10.h> // neon library +#include <cmath> + +int gFFTSize; + +int gReadPointer = 0; +int gWritePointer = 0; + +// FFT vars +static ne10_fft_cpx_float32_t* timeDomainIn; +static ne10_fft_cpx_float32_t* timeDomainOut; +static ne10_fft_cpx_float32_t* frequencyDomain; +static ne10_fft_cfg_float32_t cfg; + +bool setup(BelaContext *context, void *userData) +{ + // Retrieve a parameter passed in from the initAudio() call + gFFTSize = *(int *)userData; + + timeDomainIn = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); + timeDomainOut = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); + frequencyDomain = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); + cfg = ne10_fft_alloc_c2c_float32_neon (gFFTSize); + + memset(timeDomainOut, 0, gFFTSize * sizeof (ne10_fft_cpx_float32_t)); + + return true; +} + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + timeDomainIn[gReadPointer].r = (ne10_float32_t) ((context->audioIn[n*context->audioChannels] + + context->audioIn[n*context->audioChannels+1]) * 0.5); + timeDomainIn[gReadPointer].i = 0; + + if(++gReadPointer >= gFFTSize) + { + //FFT + ne10_fft_c2c_1d_float32_neon (frequencyDomain, timeDomainIn, cfg, 0); + + //Do frequency domain stuff + + //IFFT + ne10_fft_c2c_1d_float32_neon (timeDomainOut, frequencyDomain, cfg, 1); + + gReadPointer = 0; + gWritePointer = 0; + } + + for(unsigned int channel = 0; channel < context->audioChannels; channel++) + context->audioOut[n * context->audioChannels + channel] = (float) timeDomainOut[gWritePointer].r; + gWritePointer++; + } +} + +void cleanup(BelaContext *context, void *userData) +{ + NE10_FREE(timeDomainIn); + NE10_FREE(timeDomainOut); + NE10_FREE(frequencyDomain); + NE10_FREE(cfg); +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 04-FFT-audio-in + +Fast Fourier Transform +---------------------- + +This sketch performs an FFT (Fast Fourier Transform) on incoming audio. It uses +the NE10 library, included at the top of the file. + +Read the documentation on the NE10 library [here](http://projectne10.github.io/Ne10/doc/annotated.html). + +The variables `timeDomainIn`, `timeDomainOut` and `frequencyDomain` are +variables of the struct `ne10_fft_cpx_float32_t` [http://projectne10.github.io/Ne10/doc/structne10__fft__cpx__float32__t.html](http://projectne10.github.io/Ne10/doc/structne10__fft__cpx__float32__t.html). +These are declared at the top of the file, and memory is allocated +for them in `setup()`. + +In `render()` a `for` loop performs the FFT which is performed on each sample, +and the resulting output is placed on each channel. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/FFT-phase-vocoder/SampleData.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,19 @@ +/* + * SampleData.h + * + * Created on: Nov 5, 2014 + * Author: Victor Zappi + */ + +#ifndef SAMPLEDATA_H_ +#define SAMPLEDATA_H_ + +// User defined structure to pass between main and rendere complex data retrieved from file +struct SampleData { + float *samples; // Samples in file + int sampleLen; // Total nume of samples +}; + + + +#endif /* SAMPLEDATA_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/FFT-phase-vocoder/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,212 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <cstdio> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <unistd.h> +#include <sys/time.h> +#include <sndfile.h> // to load audio files +#include "SampleData.h" +#include <Bela.h> + +using namespace std; + +// Global variables used by getCurrentTime() +unsigned long long gFirstSeconds, gFirstMicroseconds; + +// Load samples from file +int initFile(string file, SampleData *smp)//float *& smp) +{ + SNDFILE *sndfile ; + SF_INFO sfinfo ; + + if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { + cout << "Couldn't open file " << file << endl; + return 1; + } + + int numChan = sfinfo.channels; + if(numChan != 1) + { + cout << "Error: " << file << " is not a mono file" << endl; + return 1; + } + + smp->sampleLen = sfinfo.frames * numChan; + smp->samples = new float[smp->sampleLen]; + if(smp == NULL){ + cout << "Could not allocate buffer" << endl; + return 1; + } + + int subformat = sfinfo.format & SF_FORMAT_SUBMASK; + int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); + + // Pad with zeros in case we couldn't read whole file + for(int k = readcount; k <smp->sampleLen; k++) + smp->samples[k] = 0; + + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { + double scale ; + int m ; + + sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; + if (scale < 1e-10) + scale = 1.0 ; + else + scale = 32700.0 / scale ; + cout << "File samples scale = " << scale << endl; + + for (m = 0; m < smp->sampleLen; m++) + smp->samples[m] *= scale; + } + + sf_close(sndfile); + + return 0; +} + + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --help [-h]: Print this menu\n"; +} + +/* Function which returns the time since start of the program + * in (fractional) seconds. + */ +double getCurrentTime(void) { + unsigned long long result; + struct timeval tv; + + gettimeofday(&tv, NULL); + result = (tv.tv_sec - gFirstSeconds) * 1000000ULL + (tv.tv_usec - gFirstMicroseconds); + return (double)result / 1000000.0; +} +extern SampleData gSampleData; +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + struct timeval tv; + string fileName; // Name of the sample to load + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"file", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + gSampleData.samples = 0; + gSampleData.sampleLen = -1; + + // Set default settings + Bela_defaultSettings(&settings); + + settings.periodSize = 32; // Larger period size by default, for testing + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + fileName = string((char *)optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + if(fileName.empty()){ + fileName = "sample.wav"; + } + + + // Load file + if(initFile(fileName, &gSampleData) != 0) + { + cout << "Error: unable to load samples " << endl; + return -1; + } + + if(settings.verbose) + cout << "File contains " << gSampleData.sampleLen << " samples" << endl; + + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &gSampleData) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Initialise time + gettimeofday(&tv, NULL); + gFirstSeconds = tv.tv_sec; + gFirstMicroseconds = tv.tv_usec; + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/FFT-phase-vocoder/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,309 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <rtdk.h> +#include <ne10/NE10.h> // NEON FFT library +#include <cmath> +#include "SampleData.h" +#include <Midi.h> + +#define BUFFER_SIZE 16384 + +// TODO: your buffer and counter go here! +float gInputBuffer[BUFFER_SIZE]; +int gInputBufferPointer = 0; +float gOutputBuffer[BUFFER_SIZE]; +int gOutputBufferWritePointer = 0; +int gOutputBufferReadPointer = 0; +int gSampleCount = 0; + +float *gWindowBuffer; + +// ----------------------------------------------- +// These variables used internally in the example: +int gFFTSize = 2048; +int gHopSize = 512; +int gPeriod = 512; +float gFFTScaleFactor = 0; + +// FFT vars +ne10_fft_cpx_float32_t* timeDomainIn; +ne10_fft_cpx_float32_t* timeDomainOut; +ne10_fft_cpx_float32_t* frequencyDomain; +ne10_fft_cfg_float32_t cfg; + +// Sample info +SampleData gSampleData; // User defined structure to get complex data from main +int gReadPtr = 0; // Position of last read sample from file + +// Auxiliary task for calculating FFT +AuxiliaryTask gFFTTask; +int gFFTInputBufferPointer = 0; +int gFFTOutputBufferPointer = 0; + +void process_fft_background(); + + +int gEffect = 0; // change this here or with midi CC +enum{ + kBypass, + kRobot, + kWhisper, +}; + +float gDryWet = 1; // mix between the unprocessed and processed sound +float gPlaybackLive = 0.5f; // mix between the file playback and the live audio input +float gGain = 1; // overall gain +float *gInputAudio = NULL; +Midi midi; + + +void midiCallback(MidiChannelMessage message, void* arg){ + if(message.getType() == kmmNoteOn){ + if(message.getDataByte(1) > 0){ + int note = message.getDataByte(0); + float frequency = powf(2, (note-69)/12.f)*440; + gPeriod = (int)(44100 / frequency + 0.5); + printf("\nnote: %d, frequency: %f, hop: %d\n", note, frequency, gPeriod); + } + } + + bool shouldPrint = false; + if(message.getType() == kmmControlChange){ + float data = message.getDataByte(1) / 127.0f; + switch (message.getDataByte(0)){ + case 2 : + gEffect = (int)(data * 2 + 0.5); // CC2 selects an effect between 0,1,2 + break; + case 3 : + gPlaybackLive = data; + break; + case 4 : + gDryWet = data; + break; + case 5: + gGain = data*10; + break; + default: + shouldPrint = true; + } + } + if(shouldPrint){ + message.prettyPrint(); + } +} + +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. +bool setup(BelaContext* context, void* userData) +{ + midi.readFrom(0); + midi.setParserCallback(midiCallback); + // Retrieve a parameter passed in from the initAudio() call + gSampleData = *(SampleData *)userData; + + gFFTScaleFactor = 1.0f / (float)gFFTSize; + gOutputBufferWritePointer += gHopSize; + + timeDomainIn = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); + timeDomainOut = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); + frequencyDomain = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); + cfg = ne10_fft_alloc_c2c_float32_neon (gFFTSize); + + memset(timeDomainOut, 0, gFFTSize * sizeof (ne10_fft_cpx_float32_t)); + memset(gOutputBuffer, 0, BUFFER_SIZE * sizeof(float)); + + // Allocate buffer to mirror and modify the input + gInputAudio = (float *)malloc(context->audioFrames * context->audioChannels * sizeof(float)); + if(gInputAudio == 0) + return false; + + // Allocate the window buffer based on the FFT size + gWindowBuffer = (float *)malloc(gFFTSize * sizeof(float)); + if(gWindowBuffer == 0) + return false; + + // Calculate a Hann window + for(int n = 0; n < gFFTSize; n++) { + gWindowBuffer[n] = 0.5f * (1.0f - cosf(2.0 * M_PI * n / (float)(gFFTSize - 1))); + } + + // Initialise auxiliary tasks + if((gFFTTask = Bela_createAuxiliaryTask(&process_fft_background, 90, "fft-calculation")) == 0) + return false; + rt_printf("You are listening to an FFT phase-vocoder with overlap-and-add.\n" + "Use Midi Control Change to control:\n" + "CC 2: effect type (bypass/robotization/whisperization)\n" + "CC 3: mix between recorded sample and live audio input\n" + "CC 4: mix between the unprocessed and processed sound\n" + "CC 5: gain\n" + ); + return true; +} + +// This function handles the FFT processing in this example once the buffer has +// been assembled. +void process_fft(float *inBuffer, int inWritePointer, float *outBuffer, int outWritePointer) +{ + // Copy buffer into FFT input + int pointer = (inWritePointer - gFFTSize + BUFFER_SIZE) % BUFFER_SIZE; + for(int n = 0; n < gFFTSize; n++) { + timeDomainIn[n].r = (ne10_float32_t) inBuffer[pointer] * gWindowBuffer[n]; + timeDomainIn[n].i = 0; + + pointer++; + if(pointer >= BUFFER_SIZE) + pointer = 0; + } + + // Run the FFT + ne10_fft_c2c_1d_float32_neon (frequencyDomain, timeDomainIn, cfg, 0); + + switch (gEffect){ + case kRobot : + // Robotise the output + for(int n = 0; n < gFFTSize; n++) { + float amplitude = sqrtf(frequencyDomain[n].r * frequencyDomain[n].r + frequencyDomain[n].i * frequencyDomain[n].i); + frequencyDomain[n].r = amplitude; + frequencyDomain[n].i = 0; + } + break; + case kWhisper : + for(int n = 0; n < gFFTSize; n++) { + float amplitude = sqrtf(frequencyDomain[n].r * frequencyDomain[n].r + frequencyDomain[n].i * frequencyDomain[n].i); + float phase = rand()/(float)RAND_MAX * 2 * M_PI; + frequencyDomain[n].r = cosf(phase) * amplitude; + frequencyDomain[n].i = sinf(phase) * amplitude; + } + break; + case kBypass: + //bypass + break; + } + + // Run the inverse FFT + ne10_fft_c2c_1d_float32_neon (timeDomainOut, frequencyDomain, cfg, 1); + // Overlap-and-add timeDomainOut into the output buffer + pointer = outWritePointer; + for(int n = 0; n < gFFTSize; n++) { + outBuffer[pointer] += (timeDomainOut[n].r) * gFFTScaleFactor; + if(isnan(outBuffer[pointer])) + rt_printf("outBuffer OLA\n"); + pointer++; + if(pointer >= BUFFER_SIZE) + pointer = 0; + } +} + +// Function to process the FFT in a thread at lower priority +void process_fft_background() { + process_fft(gInputBuffer, gFFTInputBufferPointer, gOutputBuffer, gFFTOutputBufferPointer); +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. +void render(BelaContext* context, void* userData) +{ + float* audioOut = context->audioOut; + int numAudioFrames = context->audioFrames; + int numAudioChannels = context->audioChannels; + // ------ this code internal to the demo; leave as is ---------------- + + // Prep the "input" to be the sound file played in a loop + for(int n = 0; n < numAudioFrames; n++) { + if(gReadPtr < gSampleData.sampleLen) + gInputAudio[2*n] = gInputAudio[2*n+1] = gSampleData.samples[gReadPtr]*(1-gPlaybackLive) + + gPlaybackLive*0.5f*(audioRead(context,n,0)+audioRead(context,n,1)); + else + gInputAudio[2*n] = gInputAudio[2*n+1] = 0; + if(++gReadPtr >= gSampleData.sampleLen) + gReadPtr = 0; + } + // ------------------------------------------------------------------- + + for(int n = 0; n < numAudioFrames; n++) { + gInputBuffer[gInputBufferPointer] = ((gInputAudio[n*numAudioChannels] + gInputAudio[n*numAudioChannels+1]) * 0.5); + + // Copy output buffer to output + for(int channel = 0; channel < numAudioChannels; channel++){ + audioOut[n * numAudioChannels + channel] = gOutputBuffer[gOutputBufferReadPointer] * gGain * gDryWet + (1 - gDryWet) * gInputAudio[n * numAudioChannels + channel]; + } + + // Clear the output sample in the buffer so it is ready for the next overlap-add + gOutputBuffer[gOutputBufferReadPointer] = 0; + gOutputBufferReadPointer++; + if(gOutputBufferReadPointer >= BUFFER_SIZE) + gOutputBufferReadPointer = 0; + gOutputBufferWritePointer++; + if(gOutputBufferWritePointer >= BUFFER_SIZE) + gOutputBufferWritePointer = 0; + + gInputBufferPointer++; + if(gInputBufferPointer >= BUFFER_SIZE) + gInputBufferPointer = 0; + + gSampleCount++; + if(gSampleCount >= gHopSize) { + //process_fft(gInputBuffer, gInputBufferPointer, gOutputBuffer, gOutputBufferPointer); + gFFTInputBufferPointer = gInputBufferPointer; + gFFTOutputBufferPointer = gOutputBufferWritePointer; + Bela_scheduleAuxiliaryTask(gFFTTask); + + gSampleCount = 0; + } + } + gHopSize = gPeriod; +} + +// cleanup_render() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in initialise_render(). + +void cleanup(BelaContext* context, void* userData) +{ + NE10_FREE(timeDomainIn); + NE10_FREE(timeDomainOut); + NE10_FREE(frequencyDomain); + NE10_FREE(cfg); + free(gInputAudio); + free(gWindowBuffer); +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 04_audio_FFT_phase_vocoder + +Phase Vocoder +---------------------- + +This sketch shows an implementation of a phase vocoder and builds on the previous FFT example. +Again it uses the NE10 library, included at the top of the file. + +Read the documentation on the NE10 library [here](http://projectne10.github.io/Ne10/doc/annotated.html). +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/bucket-brigade-chorus/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,144 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <Scope.h> +#include <cmath> + +float gPhase1, gPhase2; +float gFrequency1, gFrequency2; +float gInverseSampleRate; + +// initialise_render() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. +#include <I2c_Codec.h> +#include <PRU.h> +extern I2c_Codec *gAudioCodec; +extern PRU *gPRU; +float D=5264; +#define delayLength 256 +float delay[delayLength]; +int writePointer=0; +int readPointer=writePointer+1; +AuxiliaryTask updatePll; + +void updatePllFunction(){ +// gPRU->setGPIOTestPin(); + static int count = 0; + while(!gShouldStop){ + gAudioCodec->setPllD(D); + count++; + if((count&4095)==0) + printf("sampling rate: %f\n",gAudioCodec->getAudioSamplingRate()); + usleep(100); + } +// gPRU->clearGPIOTestPin(); +} + +bool setup(BelaContext *context, void *userData) +{ + gInverseSampleRate = 1.0/context->audioSampleRate; + + gPhase1 = 0.0; + gPhase2 = 0.0; + + gFrequency1 = 200.0; + gFrequency2 = 201.0; + updatePll=Bela_createAuxiliaryTask(&updatePllFunction, 91, "update PLL"); + for(int n=0; n<delayLength; n++){ + delay[n]=0; + } + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ +// printf("here\n"); + static bool init = false; + if(init == false){ + Bela_scheduleAuxiliaryTask(updatePll); +// gAudioCodec->setPllP(2); +// gAudioCodec->setPllR(); +// gAudioCodec->setAudioSamplingRate(43600); +// printf("samplingRate: %f, k: %f\n", gAudioCodec->getAudioSamplingRate(), gAudioCodec->getPllK()); + init = true; + } + static int count=0; + static float lfoPhase=0; + static float feedback=0; + int updateRate=1; + if((count&(updateRate-1))==0){ + float amplitude = 8000; + float rate = 2; + lfoPhase+=rate*2*M_PI*updateRate*context->analogFrames/context->audioSampleRate; + D=amplitude+amplitude*sinf(lfoPhase); + if((count&255)==0){ +// rt_printf("frequency: %f\n", gAudioCodec->getAudioSamplingRate()); +// rt_printf("D: %.0f\n", D); +// rt_printf("rate: %f\n", rate); +// rt_printf("amplitude: %.3f\n", amplitude); +// rt_printf("feedback: %.3f\n\n", feedback); + } + } + count++; + + for(unsigned int n = 0; n < context->audioFrames; n++) { + feedback = 0.4; + float input = audioRead(context, n, 0) + audioRead(context, n, 1); + delay[writePointer++] = input + delay[readPointer]*feedback; + float output = (input + 0.9*delay[readPointer++] ) * 0.5; + audioWrite(context, n, 0, output); + audioWrite(context, n, 1, output); + if(writePointer>=delayLength) + writePointer-=delayLength; + if(readPointer>=delayLength) + readPointer-=delayLength; + + gPhase1 += 2.0 * M_PI * gFrequency1 * gInverseSampleRate; + gPhase2 += 2.0 * M_PI * gFrequency2 * gInverseSampleRate; + if(gPhase1 > 2.0 * M_PI) + gPhase1 -= 2.0 * M_PI; + if(gPhase2 > 2.0 * M_PI) + gPhase2 -= 2.0 * M_PI; + } +} + +// cleanup_render() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in initialise_render(). + +void cleanup(BelaContext *context, void *userData) +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/filter-FIR/FIRfilter.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,51 @@ +/* + * FIRfilter.h + * + * Created on: Aug 5, 2014 + * Author: Victor Zappi and Andrew McPherson + */ + +#ifndef FIRFILTER_H_ +#define FIRFILTER_H_ + + +#include <ne10/NE10.h> + +#define FILTER_TAP_NUM 31 + +// Coefficients for FIR High Pass Filter at 3 KHz +ne10_float32_t filterTaps[FILTER_TAP_NUM] = { + -0.000055, + 0.000318, + 0.001401, + 0.003333, + 0.005827, + 0.007995, + 0.008335, + 0.004991, + -0.003764, + -0.018906, + -0.040112, + -0.065486, + -0.091722, + -0.114710, + -0.130454, + 0.863946, + -0.130454, + -0.114710, + -0.091722, + -0.065486, + -0.040112, + -0.018906, + -0.003764, + 0.004991, + 0.008335, + 0.007995, + 0.005827, + 0.003333, + 0.001401, + 0.000318, + -0.000055 +}; + +#endif /* FIRFILTER_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/filter-FIR/SampleData.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,19 @@ +/* + * SampleData.h + * + * Created on: Nov 5, 2014 + * Author: Victor Zappi + */ + +#ifndef SAMPLEDATA_H_ +#define SAMPLEDATA_H_ + +// User defined structure to pass between main and rendere complex data retrieved from file +struct SampleData { + float *samples; // Samples in file + int sampleLen; // Total nume of samples +}; + + + +#endif /* SAMPLEDATA_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/filter-FIR/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,196 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <string> +#include <getopt.h> +#include <sndfile.h> // to load audio files + +#include <Bela.h> +#include "SampleData.h" + +using namespace std; + +// Load samples from file +int initFile(string file, SampleData *smp)//float *& smp) +{ + SNDFILE *sndfile ; + SF_INFO sfinfo ; + + if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { + cout << "Couldn't open file " << file << endl; + return 1; + } + + int numChan = sfinfo.channels; + if(numChan != 1) + { + cout << "Error: " << file << " is not a mono file" << endl; + return 1; + } + + smp->sampleLen = sfinfo.frames * numChan; + smp->samples = new float[smp->sampleLen]; + if(smp == NULL){ + cout << "Could not allocate buffer" << endl; + return 1; + } + + int subformat = sfinfo.format & SF_FORMAT_SUBMASK; + int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); + + // Pad with zeros in case we couldn't read whole file + for(int k = readcount; k <smp->sampleLen; k++) + smp->samples[k] = 0; + + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { + double scale ; + int m ; + + sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; + if (scale < 1e-10) + scale = 1.0 ; + else + scale = 32700.0 / scale ; + cout << "File samples scale = " << scale << endl; + + for (m = 0; m < smp->sampleLen; m++) + smp->samples[m] *= scale; + } + + sf_close(sndfile); + + return 0; +} + + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + //rt_task_delete ((RT_TASK *) &gTriggerSamplesTask); + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --file [-f] filename: Name of the file to load (default is \"longsample.wav\")\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + string fileName; // Name of the sample to load + + SampleData sampleData; // User define structure to pass data retrieved from file to render function + sampleData.samples = 0; + sampleData.sampleLen = -1; + + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"file", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + fileName = string((char *)optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + if(fileName.empty()){ + fileName = "filter/longsample.wav"; + } + + if(settings.verbose) { + cout << "Loading file " << fileName << endl; + } + + // Load file + if(initFile(fileName, &sampleData) != 0) + { + cout << "Error: unable to load samples " << endl; + return -1; + } + + if(settings.verbose) + cout << "File contains " << sampleData.sampleLen << " samples" << endl; + + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &sampleData) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/filter-FIR/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,172 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#define ENABLE_NE10_FIR_FLOAT_NEON // Define needed for Ne10 library + +#include <Bela.h> +#include <cmath> +#include <ne10/NE10.h> // neon library +#include "SampleData.h" +#include "FIRfilter.h" + +SampleData gSampleData; // User defined structure to get complex data from main +int gReadPtr; // Position of last read sample from file + +// filter vars +ne10_fir_instance_f32_t gFIRfilter; +ne10_float32_t *gFIRfilterIn; +ne10_float32_t *gFIRfilterOut; +ne10_uint32_t blockSize; +ne10_float32_t *gFIRfilterState; + +void initialise_filter(BelaContext *context); + +// Task for handling the update of the frequencies using the matrix +AuxiliaryTask gTriggerSamplesTask; + +bool initialise_trigger(); +void trigger_samples(); + +bool setup(BelaContext *context, void *userData) +{ + + // Retrieve a parameter passed in from the initAudio() call + gSampleData = *(SampleData *)userData; + + gReadPtr = -1; + + initialise_filter(context); + + // Initialise auxiliary tasks + if(!initialise_trigger()) + return false; + + return true; +} + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + float in = 0; + + // If triggered... + if(gReadPtr != -1) + in += gSampleData.samples[gReadPtr++]; // ...read each sample... + + if(gReadPtr >= gSampleData.sampleLen) + gReadPtr = -1; + + gFIRfilterIn[n] = in; + } + + ne10_fir_float_neon(&gFIRfilter, gFIRfilterIn, gFIRfilterOut, blockSize); + + for(unsigned int n = 0; n < context->audioFrames; n++) { + for(unsigned int channel = 0; channel < context->audioChannels; channel++) + context->audioOut[n * context->audioChannels + channel] = gFIRfilterOut[n]; // ...and put it in both left and right channel + } + + + // Request that the lower-priority task run at next opportunity + Bela_scheduleAuxiliaryTask(gTriggerSamplesTask); +} + +// Initialise NE10 data structures to define FIR filter + +void initialise_filter(BelaContext *context) +{ + blockSize = context->audioFrames; + gFIRfilterState = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); + gFIRfilterIn = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); + gFIRfilterOut = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); + ne10_fir_init_float(&gFIRfilter, FILTER_TAP_NUM, filterTaps, gFIRfilterState, blockSize); +} + + +// Initialise the auxiliary task +// and print info + +bool initialise_trigger() +{ + if((gTriggerSamplesTask = Bela_createAuxiliaryTask(&trigger_samples, 50, "bela-trigger-samples")) == 0) + return false; + + rt_printf("Press 'a' to trigger sample, 's' to stop\n"); + rt_printf("Press 'q' to quit\n"); + + return true; +} + +// This is a lower-priority call to periodically read keyboard input +// and trigger samples. By placing it at a lower priority, +// it has minimal effect on the audio performance but it will take longer to +// complete if the system is under heavy audio load. + +void trigger_samples() +{ + // This is not a real-time task! + // Cos getchar is a system call, not handled by Xenomai. + // This task will be automatically down graded. + + char keyStroke = '.'; + + keyStroke = getchar(); + while(getchar()!='\n'); // to read the first stroke + + switch (keyStroke) + { + case 'a': + gReadPtr = 0; + break; + case 's': + gReadPtr = -1; + break; + case 'q': + gShouldStop = true; + break; + default: + break; + } +} + + +void cleanup(BelaContext *context, void *userData) +{ + delete[] gSampleData.samples; + + NE10_FREE(gFIRfilterState); + NE10_FREE(gFIRfilterIn); + NE10_FREE(gFIRfilterOut); +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 04-filter-FIR + +Finite Impulse Response Filter +------------------------------ + +This is an example of a finite impulse response filter implementation. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/filter-IIR/SampleData.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,19 @@ +/* + * SampleData.h + * + * Created on: Nov 5, 2014 + * Author: Victor Zappi + */ + +#ifndef SAMPLEDATA_H_ +#define SAMPLEDATA_H_ + +// User defined structure to pass between main and rendere complex data retrieved from file +struct SampleData { + float *samples; // Samples in file + int sampleLen; // Total nume of samples +}; + + + +#endif /* SAMPLEDATA_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/filter-IIR/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,202 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <string> +#include <getopt.h> +#include <sndfile.h> // to load audio files + +#include <Bela.h> +#include "SampleData.h" + +using namespace std; + +float gCutFreq = 100; + +// Load samples from file +int initFile(string file, SampleData *smp)//float *& smp) +{ + SNDFILE *sndfile ; + SF_INFO sfinfo ; + + if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { + cout << "Couldn't open file " << file << endl; + return 1; + } + + int numChan = sfinfo.channels; + if(numChan != 1) + { + cout << "Error: " << file << " is not a mono file" << endl; + return 1; + } + + smp->sampleLen = sfinfo.frames * numChan; + smp->samples = new float[smp->sampleLen]; + if(smp == NULL){ + cout << "Could not allocate buffer" << endl; + return 1; + } + + int subformat = sfinfo.format & SF_FORMAT_SUBMASK; + int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); + + // Pad with zeros in case we couldn't read whole file + for(int k = readcount; k <smp->sampleLen; k++) + smp->samples[k] = 0; + + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { + double scale ; + int m ; + + sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; + if (scale < 1e-10) + scale = 1.0 ; + else + scale = 32700.0 / scale ; + cout << "File samples scale = " << scale << endl; + + for (m = 0; m < smp->sampleLen; m++) + smp->samples[m] *= scale; + } + + sf_close(sndfile); + + return 0; +} + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + //rt_task_delete ((RT_TASK *) &gTriggerSamplesTask); + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --file [-f] filename: Name of the file to load (default is \"longsample.wav\")\n"; + cerr << " --cutfreq [-c] freq: Set the cut off frequency of the filter in Hz\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + string fileName; // Name of the sample to load + + SampleData sampleData; // User define structure to pass data retrieved from file to render function + sampleData.samples = 0; + sampleData.sampleLen = -1; + + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"cutfreq", 1, NULL, 'c'}, + {"file", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:c:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + fileName = string((char *)optarg); + break; + case 'c': + gCutFreq = atof(optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + if(fileName.empty()){ + fileName = "filter/longsample.wav"; + } + + if(settings.verbose) { + cout << "Loading file " << fileName << endl; + } + + // Load file + if(initFile(fileName, &sampleData) != 0) + { + cout << "Error: unable to load samples " << endl; + return -1; + } + + if(settings.verbose) + cout << "File contains " << sampleData.sampleLen << " samples" << endl; + + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &sampleData) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/filter-IIR/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,230 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> // to schedule lower prio parallel process +#include <rtdk.h> +#include <cmath> +#include <stdio.h> +#include "SampleData.h" + +SampleData gSampleData; // User defined structure to get complex data from main +int gReadPtr; // Position of last read sample from file + +// filter vars +float gLastX[2]; +float gLastY[2]; +double lb0, lb1, lb2, la1, la2 = 0.0; + +// communication vars between the 2 auxiliary tasks +int gChangeCoeff = 0; +int gFreqDelta = 0; + +void initialise_filter(float freq); + +void calculate_coeff(float cutFreq); + +bool initialise_aux_tasks(); + +// Task for handling the update of the frequencies using the matrix +AuxiliaryTask gChangeCoeffTask; + +void check_coeff(); + +// Task for handling the update of the frequencies using the matrix +AuxiliaryTask gInputTask; + +void read_input(); + + +extern float gCutFreq; + + +bool setup(BelaContext *context, void *userData) +{ + + // Retrieve a parameter passed in from the initAudio() call + gSampleData = *(SampleData *)userData; + + gReadPtr = -1; + + initialise_filter(200); + + // Initialise auxiliary tasks + if(!initialise_aux_tasks()) + return false; + + return true; +} + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + float sample = 0; + float out = 0; + + // If triggered... + if(gReadPtr != -1) + sample += gSampleData.samples[gReadPtr++]; // ...read each sample... + + if(gReadPtr >= gSampleData.sampleLen) + gReadPtr = -1; + + out = lb0*sample+lb1*gLastX[0]+lb2*gLastX[1]-la1*gLastY[0]-la2*gLastY[1]; + + gLastX[1] = gLastX[0]; + gLastX[0] = out; + gLastY[1] = gLastY[0]; + gLastY[0] = out; + + for(unsigned int channel = 0; channel < context->audioChannels; channel++) + context->audioOut[n * context->audioChannels + channel] = out; // ...and put it in both left and right channel + + } + + // Request that the lower-priority tasks run at next opportunity + Bela_scheduleAuxiliaryTask(gChangeCoeffTask); + Bela_scheduleAuxiliaryTask(gInputTask); +} + +// First calculation of coefficients + +void initialise_filter(float freq) +{ + calculate_coeff(freq); +} + + +// Calculate the filter coefficients +// second order low pass butterworth filter + +void calculate_coeff(float cutFreq) +{ + // Initialise any previous state (clearing buffers etc.) + // to prepare for calls to render() + float sampleRate = 44100; + double f = 2*M_PI*cutFreq/sampleRate; + double denom = 4+2*sqrt(2)*f+f*f; + lb0 = f*f/denom; + lb1 = 2*lb0; + lb2 = lb0; + la1 = (2*f*f-8)/denom; + la2 = (f*f+4-2*sqrt(2)*f)/denom; + gLastX[0] = gLastX [1] = 0; + gLastY[0] = gLastY[1] = 0; + +} + + +// Initialise the auxiliary tasks +// and print info + +bool initialise_aux_tasks() +{ + if((gChangeCoeffTask = Bela_createAuxiliaryTask(&check_coeff, 90, "bela-check-coeff")) == 0) + return false; + + if((gInputTask = Bela_createAuxiliaryTask(&read_input, 50, "bela-read-input")) == 0) + return false; + + rt_printf("Press 'a' to trigger sample, 's' to stop\n"); + rt_printf("Press 'z' to low down cut-off freq of 100 Hz, 'x' to raise it up\n"); + rt_printf("Press 'q' to quit\n"); + + return true; +} + +// Check if cut-off freq has been changed +// and new coefficients are needed + +void check_coeff() +{ + if(gChangeCoeff == 1) + { + gCutFreq += gFreqDelta; + gCutFreq = gCutFreq < 0 ? 0 : gCutFreq; + gCutFreq = gCutFreq > 22050 ? 22050 : gCutFreq; + + rt_printf("Cut-off frequency: %f\n", gCutFreq); + + calculate_coeff(gCutFreq); + gChangeCoeff = 0; + } +} + +// This is a lower-priority call to periodically read keyboard input +// and trigger samples. By placing it at a lower priority, +// it has minimal effect on the audio performance but it will take longer to +// complete if the system is under heavy audio load. + +void read_input() +{ + // This is not a real-time task! + // Cos getchar is a system call, not handled by Xenomai. + // This task will be automatically down graded. + + char keyStroke = '.'; + + keyStroke = getchar(); + while(getchar()!='\n'); // to read the first stroke + + switch (keyStroke) + { + case 'a': + gReadPtr = 0; + break; + case 's': + gReadPtr = -1; + break; + case 'z': + gChangeCoeff = 1; + gFreqDelta = -100; + break; + case 'x': + gChangeCoeff = 1; + gFreqDelta = 100; + break; + case 'q': + gShouldStop = true; + break; + default: + break; + } +} + + +void cleanup(BelaContext *context, void *userData) +{ + delete[] gSampleData.samples; +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 04-filter-IIR + +Infinite Impulse Response Filter +------------------------------ + +This is an example of a infinite impulse response filter implementation. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/measure-noisefloor/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,120 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +extern int gBufferSize; + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --buffer-size [-b] size Set the analysis buffer size\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"buffer-size", 1, NULL, 'b'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // By default use a longer period size because latency is not an issue + settings.periodSize = 32; + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hb:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'b': + gBufferSize = atoi(optarg); + break; + case 'h': + usage(basename(argv[0])); + exit(0); + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + if(gBufferSize < settings.periodSize) + gBufferSize = settings.periodSize; + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, 0) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/measure-noisefloor/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,178 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> + +int gBufferSize = 8192; + +// Double buffers to hold samples for noise analysis +float *gReadBuffers[10], *gWriteBuffers[10]; +float *gBuffers0[10], *gBuffers1[10]; + +int gWriteBufferPointers[10], gReadBufferPointers[10]; + +// Task to analyse and print results which would otherwise be too slow for render() +AuxiliaryTask gAnalysisTask; + +void analyseResults(); + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + +bool setup(BelaContext *context, void *userData) +{ + // Clear the filter data structures + for(int i = 0; i < 10; i++) { + gReadBufferPointers[i] = gWriteBufferPointers[i] = 0; + gBuffers0[i] = new float[gBufferSize]; + gBuffers1[i] = new float[gBufferSize]; + gWriteBuffers[i] = gBuffers0[i]; + gReadBuffers[i] = gBuffers1[i]; + if(gBuffers0[i] == 0 || gBuffers1[i] == 0) { + rt_printf("Error allocating buffer %d\n", i); + return false; + } + } + + gAnalysisTask = Bela_createAuxiliaryTask(analyseResults, 50, "bela-analyse-results"); + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + bool bufferIsFull = false; // Whether at least one buffer has filled + + for(unsigned int n = 0; n < context->audioFrames; n++) { + // Store audio inputs in buffer + for(unsigned int ch = 0; ch < context->audioChannels; ch++) { + if(gWriteBufferPointers[ch] < gBufferSize) { + gWriteBuffers[ch][gWriteBufferPointers[ch]] = + context->audioIn[n * context->audioChannels + ch]; + gWriteBufferPointers[ch]++; + if(gWriteBufferPointers[ch] >= gBufferSize) + bufferIsFull = true; + } + } + } + + if(context->analogChannels != 0) { + for(unsigned int n = 0; n < context->analogFrames; n++) { + // Store analog inputs in buffer, starting at channel 2 + for(unsigned int ch = 0; ch < context->analogChannels; ch++) { + if(gWriteBufferPointers[ch + 2] < gBufferSize) { + gWriteBuffers[ch + 2][gWriteBufferPointers[ch + 2]] = + context->analogIn[n * context->analogChannels + ch]; + gWriteBufferPointers[ch + 2]++; + if(gWriteBufferPointers[ch + 2] >= gBufferSize) + bufferIsFull = true; + } + + // Set all analog outputs to halfway point so they can be more + // easily measured for noise + context->analogOut[n * context->analogChannels + ch] = 0.5; + } + } + } + + + if(bufferIsFull) { + // Swap buffers and reset write pointers + for(int ch = 0; ch < 10; ch++) { + gReadBufferPointers[ch] = gWriteBufferPointers[ch]; + gWriteBufferPointers[ch] = 0; + + if(gReadBuffers[ch] == gBuffers0[ch]) { + gReadBuffers[ch] = gBuffers1[ch]; + gWriteBuffers[ch] = gBuffers0[ch]; + } + else { + gReadBuffers[ch] = gBuffers0[ch]; + gWriteBuffers[ch] = gBuffers1[ch]; + } + } + + Bela_scheduleAuxiliaryTask(gAnalysisTask); + } +} + +void analyseResults() +{ + rt_printf("\e[1;1H\e[2J"); // Command to clear the screen + + // Print the analysis results. channels 0-1 are audio, channels 2-9 are analog + for(int ch = 0; ch < 10; ch++) { + // Skip unused channels + if(gReadBufferPointers[ch] == 0) + continue; + + float mean = 0; + for(int n = 0; n < gReadBufferPointers[ch]; n++) { + mean += gReadBuffers[ch][n]; + } + mean /= (float)gReadBufferPointers[ch]; + + float rms = 0; + for(int n = 0; n < gReadBufferPointers[ch]; n++) { + rms += (gReadBuffers[ch][n] - mean) * (gReadBuffers[ch][n] - mean); + } + rms = sqrtf(rms / (float)gReadBufferPointers[ch]); + + if(ch == 0) + rt_printf("Audio In L: "); + else if(ch == 1) + rt_printf("Audio In R: "); + else + rt_printf("Analog In %d: ", ch - 2); + + rt_printf("Noise %6.1fdB DC offset %6.4f (%6.1fdB) window size: %d\n", + 20.0f * log10f(rms), + mean, + 20.0f * log10f(fabsf(mean)), + gReadBufferPointers[ch]); + } +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + for(int i = 0; i < 10; i++) { + delete gBuffers0[i]; + delete gBuffers1[i]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/oscillator-bank/audio_routines.S Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,161 @@ +@ +@ audio_routines.S +@ +@ NEON-based functions for time-critical audio processing +@ +@ Andrew McPherson 2014 +@ Queen Mary University of London +@ + + .syntax unified + .arch armv7-a + .fpu neon + +@ void oscillator_bank_neon(int numAudioFrames, float *audioOut, +@ int activePartialNum, int lookupTableSize, +@ float *phases, float *frequencies, float *amplitudes, +@ float *freqDerivatives, float *ampDerivatives, +@ float *lookupTable); + +@ Registers: +@ r0: numAudioFrames How many frames to render +@ r1: audioOut Buffer for audio output samples [stereo] +@ r2: activePartialNum How many active partials to render +@ r3: lookupTableSize Size of lookup table +@ ---- other arguments start on the stack and are moved: ----- +@ r4: phases Phase of each oscillator (pointer) +@ r5: frequencies Normalised frequency of each oscillator (pointer) +@ r6: amplitudes Normalised amplitude of each oscillator (pointer) +@ r7: freqDerivatives Derivative of frequency for each oscillator (pointer) +@ r8: ampDerivatives Derivative of amplitude for each oscillator (pointer) +@ r9: lookupTable Lookup table containing one oscillation +@ +@ Alignment requirements: +@ audioOut: 8-byte boundary +@ phases: 16-byte boundary +@ frequencies: 16-byte boundary +@ amplitudes: 16-byte boundary +@ freqDerivatives: 16-byte bounary +@ ampDerivatives: 16-byte boundary +@ lookupTable: 4-byte boundary (TODO: check this) + + .align 2 + .global oscillator_bank_neon + .thumb + .thumb_func + .type oscillator_bank_neon, %function +oscillator_bank_neon: + + +dSample .dn D6.F32 +qPhases .qn Q8.F32 +dPhases_0 .dn D16.F32 +dPhases_1 .dn D17.F32 +qFreqs .qn Q9.F32 +dFreqs_0 .dn D18.F32 +dFreqs_1 .dn D19.F32 +qAmps .qn Q10.F32 +dAmps_0 .dn D20.F32 +dAmps_1 .dn D21.F32 +qFreqDs .qn Q11.F32 +dFreqDs_0 .dn D22.F32 +dFreqDs_1 .dn D23.F32 +qAmpDs .qn Q12.F32 +dAmpDs_0 .dn D24.F32 +dAmpDs_1 .dn D25.F32 + +qBaseInts .qn Q13.U32 @ Base indexes: unsigned ints x4 +dBaseInts_0 .dn D26.U32 +dBaseInts_1 .dn D27.U32 +qFractions .qn Q14.F32 @ Fraction indexes: floats x4 +qTableBase .qn Q15.U32 @ Base of lookup table + + cmp r0, #0 @ Check for trivial case 1: zero frames + it eq + bxeq lr @ Return if that's the case (otherwise might have odd behaviour) + cmp r2, #4 @ Check for trivial case 2: zero oscillators + it lt + bxlt lr @ Return if that's the case + + push {r4-r11} @ Now arguments start 32 bytes above SP + add r11, sp, #32 @ Pointer to 32 bytes into the stack + ldm r11, {r4-r9} @ Load 6 arguments into registers + + vdup qTableBase, r9 @ Move lookup table base index into 4 ints + + @ Outer loop: iterate over the number of oscillators, choosing 4 at a + @ time to work with. +oscbank_oscillator_loop: + vld1 {dPhases_0, dPhases_1}, [r4] @ no increment; will store at end of sample loop + vld1 {dFreqs_0, dFreqs_1}, [r5] + vld1 {dAmps_0, dAmps_1}, [r6] + vld1 {dFreqDs_0, dFreqDs_1}, [r7]! @ increment; won't update at end of sample loop + vld1 {dAmpDs_0, dAmpDs_1}, [r8]! + + push {r0-r1,r4-r8} + @ --- inner loop: iterate over the number of samples --- +oscbank_sample_loop: + vcvt qBaseInts, qPhases @ Take floor(phases) + vmov q2.f32, #1.0 @ Load 1.0 into every slot of q2 + vshl q0.U32, qBaseInts, #2 @ Shift the indexes left 2 (*4 for float addressing) + vcvt qFractions, qBaseInts @ int back to float + vadd q0.U32, q0.U32, qTableBase @ Find memory addresses + + vmov r4, r5, d0 @ Move two indexes to ARM registers + vmov r6, r7, d1 @ Move two more indexes to ARM registers + vsub qFractions, qPhases, qFractions @ fraction = phase - floor(phase) + + vldr.64 d0, [r4] @ Load two consecutive floats at each location + vldr.64 d1, [r5] @ These hold the previous and following samples in the table + vldr.64 d2, [r6] @ TODO: check whether these work at 4-byte alignment + vldr.64 d3, [r7] + + @ Format at this point: + @ Osc0(before) Osc0(after) Osc1(before) Osc1(after) Osc2(before) Osc2(after) Osc3(before) Osc3(after) + @ We want: + @ Osc0(before) Osc1(before) Osc2(before) Osc3(before) Osc0(after) Osc1(after) Osc2(after) Osc3(after) + + vuzp.32 q0, q1 @ Now q0 contains before, q1 contains after + vsub q2.f32, q2.f32, qFractions @ q2 = 1.0 - fraction + vmul q1.f32, q1.f32, qFractions @ q1 = fraction * after + vmul q0.f32, q0.f32, q2.f32 @ q0 = (1.0 - fraction) * before + + vadd qPhases, qPhases, qFreqs @ Update phases + vadd qFreqs, qFreqs, qFreqDs @ Update frequencies + + vadd q0.f32, q0.f32, q1.f32 @ Add two interpolated components to get the final sample + vdup q2.u32, r3 @ Put lookup table size into each element of q2 + vcvt qBaseInts, qPhases @ Take floor of new phases + vmul q0.f32, q0.f32, qAmps @ Multiply samples by current amplitude + + vld1 dSample, [r1] @ Load the current stereo samples + vpadd d2.f32, d0.f32, d1.f32 @ Pairwise accumulate q0 (output sample) into d2 + + vand q2, q2, qBaseInts @ Logical AND of new phase int leaves 1 bit set only if phase >= table size + vpadd d3.f32, d2.f32, d2.f32 @ Pairwise accumulate d2 into d0 --> d0[0] and d0[1] both hold total of 4 oscillators + vadd qAmps, qAmps, qAmpDs @ Update amplitudes + vcvt q0.f32, q2.u32 @ Convert int back to float after AND operation + + vadd dSample, dSample, d3.f32 @ Add oscillator outputs to each channel + + subs r0, r0, #1 @ numFrames-- + vsub qPhases, qPhases, q0.f32 @ Keep phases in table range + vst1 dSample, [r1]! @ Store back in buffer and increment by 8 + + it gt + bgt oscbank_sample_loop @ Loop if numFrames > 0 + + @ --- end inner loop --- + pop {r0-r1,r4-r8} @ Restore registers: restores audioOut and numFrames, among others + + vst1 {dPhases_0, dPhases_1}, [r4]! @ Store phases back to array + vst1 {dFreqs_0, dFreqs_1}, [r5]! @ Store frequencies back to array + vst1 {dAmps_0, dAmps_1}, [r6]! @ Store amplitudes back to array + @ No need to update r7, r8 + + subs r2, r2, #4 @ numPartials -= 4 + it gt + bgt oscbank_oscillator_loop @ Loop if numPartials > 0 + + pop {r4-r11} + bx lr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/oscillator-bank/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,132 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +int gNumOscillators = 32; +int gWavetableLength = 1024; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --num-oscillators [-n] oscs: Set the number of oscillators to use (default: 32)\n"; + cerr << " --wavetable [-w] length: Set the wavetable length in samples (default: 1024)\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"num-oscillators", 1, NULL, 'n'}, + {"wavetable", 1, NULL, 'w'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hn:w:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'n': + gNumOscillators = atoi(optarg); + if(gNumOscillators <= 0) { + usage(basename(argv[0])); + exit(0); + } + break; + case 'w': + gWavetableLength = atoi(optarg); + if(gWavetableLength < 4) + gWavetableLength = 4; + if(gWavetableLength > 16384) + gWavetableLength = 16384; + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, 0) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + if(settings.verbose) { + cout << "--> Using " << gNumOscillators << " oscillators and wavetable of " << gWavetableLength << " samples\n"; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/oscillator-bank/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,248 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <rtdk.h> +#include <cstdlib> +#include <cmath> +#include <cstring> +#include <time.h> + +const float kMinimumFrequency = 20.0f; +const float kMaximumFrequency = 8000.0f; + +float *gWavetable; // Buffer holding the precalculated sine lookup table +float *gPhases; // Buffer holding the phase of each oscillator +float *gFrequencies; // Buffer holding the frequencies of each oscillator +float *gAmplitudes; // Buffer holding the amplitudes of each oscillator +float *gDFrequencies; // Buffer holding the derivatives of frequency +float *gDAmplitudes; // Buffer holding the derivatives of amplitude + +float gAudioSampleRate; +int gSampleCount; // Sample counter for indicating when to update frequencies +float gNewMinFrequency; +float gNewMaxFrequency; + +// Task for handling the update of the frequencies using the matrix +AuxiliaryTask gFrequencyUpdateTask; + +// These settings are carried over from main.cpp +// Setting global variables is an alternative approach +// to passing a structure to userData in setup() + +extern int gNumOscillators; +extern int gWavetableLength; + +void recalculate_frequencies(); + +extern "C" { + // Function prototype for ARM assembly implementation of oscillator bank + void oscillator_bank_neon(int numAudioFrames, float *audioOut, + int activePartialNum, int lookupTableSize, + float *phases, float *frequencies, float *amplitudes, + float *freqDerivatives, float *ampDerivatives, + float *lookupTable); +} + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. +bool setup(BelaContext *context, void *userData) +{ + srandom(time(NULL)); + + if(context->audioChannels != 2) { + rt_printf("Error: this example needs stereo audio enabled\n"); + return false; + } + + // Initialise the sine wavetable + if(posix_memalign((void **)&gWavetable, 8, (gWavetableLength + 1) * sizeof(float))) { + rt_printf("Error allocating wavetable\n"); + return false; + } + for(int n = 0; n < gWavetableLength + 1; n++) + gWavetable[n] = sinf(2.0 * M_PI * (float)n / (float)gWavetableLength); + + // Allocate the other buffers + if(posix_memalign((void **)&gPhases, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating phase buffer\n"); + return false; + } + if(posix_memalign((void **)&gFrequencies, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating frequency buffer\n"); + return false; + } + if(posix_memalign((void **)&gAmplitudes, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating amplitude buffer\n"); + return false; + } + if(posix_memalign((void **)&gDFrequencies, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating frequency derivative buffer\n"); + return false; + } + if(posix_memalign((void **)&gDAmplitudes, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating amplitude derivative buffer\n"); + return false; + } + + // Initialise buffer contents + + float freq = kMinimumFrequency; + float increment = (kMaximumFrequency - kMinimumFrequency) / (float)gNumOscillators; + + for(int n = 0; n < gNumOscillators; n++) { + gPhases[n] = 0.0; + + if(context->analogFrames == 0) { + // Random frequencies when used without matrix + gFrequencies[n] = kMinimumFrequency + (kMaximumFrequency - kMinimumFrequency) * ((float)random() / (float)RAND_MAX); + } + else { + // Constant spread of frequencies when used with matrix + gFrequencies[n] = freq; + freq += increment; + } + + // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians + gFrequencies[n] *= (float)gWavetableLength / context->audioSampleRate; + gAmplitudes[n] = ((float)random() / (float)RAND_MAX) / (float)gNumOscillators; + gDFrequencies[n] = gDAmplitudes[n] = 0.0; + } + + increment = 0; + freq = 440.0; + + for(int n = 0; n < gNumOscillators; n++) { + // Update the frequencies to a regular spread, plus a small amount of randomness + // to avoid weird phase effects + float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; + float newFreq = freq * randScale; + + // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians + gFrequencies[n] = newFreq * (float)gWavetableLength / context->audioSampleRate; + + freq += increment; + } + + // Initialise auxiliary tasks + if((gFrequencyUpdateTask = Bela_createAuxiliaryTask(&recalculate_frequencies, 85, "bela-update-frequencies")) == 0) + return false; + + //for(int n = 0; n < gNumOscillators; n++) + // rt_printf("%f\n", gFrequencies[n]); + + gAudioSampleRate = context->audioSampleRate; + gSampleCount = 0; + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + // Initialise buffer to 0 + memset(context->audioOut, 0, 2 * context->audioFrames * sizeof(float)); + + // Render audio frames + oscillator_bank_neon(context->audioFrames, context->audioOut, + gNumOscillators, gWavetableLength, + gPhases, gFrequencies, gAmplitudes, + gDFrequencies, gDAmplitudes, + gWavetable); + + if(context->analogFrames != 0 && (gSampleCount += context->audioFrames) >= 128) { + gSampleCount = 0; + gNewMinFrequency = map(context->analogIn[0], 0, 1.0, 1000.0f, 8000.0f); + gNewMaxFrequency = map(context->analogIn[1], 0, 1.0, 1000.0f, 8000.0f); + + // Make sure max >= min + if(gNewMaxFrequency < gNewMinFrequency) { + float temp = gNewMaxFrequency; + gNewMaxFrequency = gNewMinFrequency; + gNewMinFrequency = temp; + } + + // Request that the lower-priority task run at next opportunity + //Bela_scheduleAuxiliaryTask(gFrequencyUpdateTask); + } +} + +// This is a lower-priority call to update the frequencies which will happen +// periodically when the matrix is enabled. By placing it at a lower priority, +// it has minimal effect on the audio performance but it will take longer to +// complete if the system is under heavy audio load. + +void recalculate_frequencies() +{ + float freq = gNewMinFrequency; + float increment = (gNewMaxFrequency - gNewMinFrequency) / (float)gNumOscillators; + + for(int n = 0; n < gNumOscillators; n++) { + // Update the frequencies to a regular spread, plus a small amount of randomness + // to avoid weird phase effects + float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; + float newFreq = freq * randScale; + + // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians + gFrequencies[n] = newFreq * (float)gWavetableLength / gAudioSampleRate; + + freq += increment; + } +} + + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + free(gWavetable); + free(gPhases); + free(gFrequencies); + free(gAmplitudes); + free(gDFrequencies); + free(gDAmplitudes); +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 04-oscillator-bank + +Oscillator Bank +---------------------- + +These files demonstrate an oscillator bank implemented in assembly code +that is used as part of the d-box project. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/samples/SampleData.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,19 @@ +/* + * SampleData.h + * + * Created on: Nov 5, 2014 + * Author: Victor Zappi + */ + +#ifndef SAMPLEDATA_H_ +#define SAMPLEDATA_H_ + +// User defined structure to pass between main and rendere complex data retrieved from file +struct SampleData { + float *samples; // Samples in file + int sampleLen; // Total nume of samples +}; + + + +#endif /* SAMPLEDATA_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/samples/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,195 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <string> +#include <getopt.h> +#include <sndfile.h> // to load audio files + +#include <Bela.h> +#include "SampleData.h" + +using namespace std; + +// Load samples from file +int initFile(string file, SampleData *smp)//float *& smp) +{ + SNDFILE *sndfile ; + SF_INFO sfinfo ; + + if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { + cout << "Couldn't open file " << file << endl; + return 1; + } + + int numChan = sfinfo.channels; + if(numChan != 1) + { + cout << "Error: " << file << " is not a mono file" << endl; + return 1; + } + + smp->sampleLen = sfinfo.frames * numChan; + smp->samples = new float[smp->sampleLen]; + if(smp == NULL){ + cout << "Could not allocate buffer" << endl; + return 1; + } + + int subformat = sfinfo.format & SF_FORMAT_SUBMASK; + int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); + + // Pad with zeros in case we couldn't read whole file + for(int k = readcount; k <smp->sampleLen; k++) + smp->samples[k] = 0; + + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { + double scale ; + int m ; + + sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; + if (scale < 1e-10) + scale = 1.0 ; + else + scale = 32700.0 / scale ; + cout << "File samples scale = " << scale << endl; + + for (m = 0; m < smp->sampleLen; m++) + smp->samples[m] *= scale; + } + + sf_close(sndfile); + + return 0; +} + + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + //rt_task_delete ((RT_TASK *) &gTriggerSamplesTask); + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --file [-f] filename: Name of the file to load (default is \"sample.wav\")\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + string fileName; // Name of the sample to load + + SampleData sampleData; // User define structure to pass data retrieved from file to render function + sampleData.samples = 0; + sampleData.sampleLen = -1; + + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"file", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + fileName = string((char *)optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + if(fileName.empty()){ + fileName = "samples/sample.wav"; + } + + if(settings.verbose) { + cout << "Loading file " << fileName << endl; + } + + // Load file + if(initFile(fileName, &sampleData) != 0) + { + cout << "Error: unable to load samples " << endl; + return -1; + } + + if(settings.verbose) + cout << "File contains " << sampleData.sampleLen << " samples" << endl; + + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &sampleData) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/04-Audio/samples/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,147 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> +#include "SampleData.h" + +SampleData gSampleData; // User defined structure to get complex data from main +int gReadPtr; // Position of last read sample from file + +// Task for handling the update of the frequencies using the matrix +AuxiliaryTask gTriggerSamplesTask; + +bool initialise_trigger(); +void trigger_samples(); + +bool setup(BelaContext *context, void *userData) +{ + + // Retrieve a parameter passed in from the initAudio() call + gSampleData = *(SampleData *)userData; + + gReadPtr = -1; + + // Initialise auxiliary tasks + if(!initialise_trigger()) + return false; + + return true; +} + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + float out = 0; + + // If triggered... + if(gReadPtr != -1) + out += gSampleData.samples[gReadPtr++]; // ...read each sample... + + if(gReadPtr >= gSampleData.sampleLen) + gReadPtr = -1; + + for(unsigned int channel = 0; channel < context->audioChannels; channel++) + context->audioOut[n * context->audioChannels + channel] = out; // ...and put it in both left and right channel + } + + // Request that the lower-priority task run at next opportunity + Bela_scheduleAuxiliaryTask(gTriggerSamplesTask); +} + +// Initialise the auxiliary task +// and print info + +bool initialise_trigger() +{ + if((gTriggerSamplesTask = Bela_createAuxiliaryTask(&trigger_samples, 50, "bela-trigger-samples")) == 0) + return false; + + rt_printf("Press 'a' to trigger sample, 's' to stop\n"); + rt_printf("Press 'q' to quit\n"); + + return true; +} + +// This is a lower-priority call to periodically read keyboard input +// and trigger samples. By placing it at a lower priority, +// it has minimal effect on the audio performance but it will take longer to +// complete if the system is under heavy audio load. + +void trigger_samples() +{ + // This is not a real-time task! + // Cos getchar is a system call, not handled by Xenomai. + // This task will be automatically down graded. + + char keyStroke = '.'; + + keyStroke = getchar(); + while(getchar()!='\n'); // to read the first stroke + + switch (keyStroke) + { + case 'a': + gReadPtr = 0; + break; + case 's': + gReadPtr = -1; + break; + case 'q': + gShouldStop = true; + break; + default: + break; + } +} + + +void cleanup(BelaContext *context, void *userData) +{ + delete[] gSampleData.samples; +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 04-samples + +Playback WAV files +------------------ + +This sketch shows how to playback audio samples from a buffer. + +An audio file is loaded into a buffer `SampleData` as `gSampleData`. This is +accessed with a read pointer that is incremented at audio rate within the render +function: `out += gSampleData.samples[gReadPtr++]`. + +Note that the read pointer is stopped from incrementing past the length of the +`gSampleData`. This is achieved by comparing the read pointer value against the +sample length which we can access as follows: `gSampleData.sampleLen`. + +The sample is triggered by keyboard input: (a) starts sample playback, (s) +stops sample playback. The triggering is treated as a lower priority task than +the audio. You can see this at the bottom of the render function: +`Bela_scheduleAuxiliaryTask(gTriggerSamplesTask)`; +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/05-Communication/OSC/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,111 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <OSCServer.h> +#include <OSCClient.h> + +OSCServer oscServer; +OSCClient oscClient; + +// this example is designed to be run alongside resources/osc/osc.js + +// parse messages recieved by OSC Server +// msg is Message class of oscpkt: http://gruntthepeon.free.fr/oscpkt/ +void parseMessage(oscpkt::Message msg){ + + rt_printf("recieved message to: %s\n", msg.addressPattern().c_str()); + + int intArg; + float floatArg; + if (msg.match("/osc-test").popInt32(intArg).popFloat(floatArg).isOkNoMoreArgs()){ + rt_printf("recieved int %i and float %f\n", intArg, floatArg); + } + +} + +bool setup(BelaContext *context, void *userData) +{ + // setup the OSC server to recieve on port 7562 + oscServer.setup(7562); + // setup the OSC client to send on port 7563 + oscClient.setup(7563); + + // the following code sends an OSC message to address /osc-setup + // then waits 1 second for a reply on /osc-setup-reply + bool handshakeRecieved = false; + oscClient.sendMessageNow(oscClient.newMessage.to("/osc-setup").end()); + oscServer.recieveMessageNow(1000); + while (oscServer.messageWaiting()){ + if (oscServer.popMessage().match("/osc-setup-reply")){ + handshakeRecieved = true; + } + } + + if (handshakeRecieved){ + rt_printf("handshake recieved!\n"); + } else { + rt_printf("timeout!\n"); + } + + return true; +} + +void render(BelaContext *context, void *userData) +{ + // recieve OSC messages, parse them, and send back an acknowledgment + while (oscServer.messageWaiting()){ + parseMessage(oscServer.popMessage()); + oscClient.queueMessage(oscClient.newMessage.to("/osc-acknowledge").add(5).add(4.2f).add(std::string("OSC message recieved")).end()); + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 05-OSC + +Open Sound Control +------------------ + +This example shows an implementation of OSC (Open Sound Control) which was +developed at UC Berkeley Center for New Music and Audio Technology (CNMAT). + +It is designed to be run alongside resources/osc/osc.js + +The OSC server port on which to receive is set in `setup()` +via `oscServer.setup()`. Likewise the OSC client port on which to +send is set in `oscClient.setup()`. + +In `setup()` an OSC message to address `/osc-setup`, it then waits +1 second for a reply on `/osc-setup-reply`. + +in `render()` the code receives OSC messages, parses them, and sends +back an acknowledgment. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/05-Communication/basic-midi/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,182 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <Midi.h> +#include <stdlib.h> +#include <rtdk.h> +#include <cmath> + +float gFreq; +float gPhaseIncrement = 0; +bool gIsNoteOn = 0; +int gVelocity = 0; +float gSamplingPeriod = 0; + +void midiMessageCallback(MidiChannelMessage message, void* arg){ + if(arg != NULL){ + rt_printf("Message from midi port %d: ", *(int*)arg); + } + message.prettyPrint(); + if(message.getType() == kmmNoteOn){ + gFreq = powf(2, (message.getDataByte(0)-69)/12.0f) * 440; + gVelocity = message.getDataByte(1); + gPhaseIncrement = 2 * M_PI * gFreq * gSamplingPeriod; + gIsNoteOn = gVelocity > 0; + rt_printf("v0:%f, ph: %6.5f, gVelocity: %d\n", gFreq, gPhaseIncrement, gVelocity); + } +} +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. +Midi midi; +int gMidiPort0 = 0; +bool setup(BelaContext *context, void *userData) +{ + midi.readFrom(gMidiPort0); + midi.writeTo(gMidiPort0); + midi.enableParser(true); + midi.setParserCallback(midiMessageCallback, &gMidiPort0); + if(context->analogFrames == 0) { + rt_printf("Error: this example needs the analog I/O to be enabled\n"); + return false; + } + gSamplingPeriod = 1/context->audioSampleRate; + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + + +enum {kVelocity, kNoteOn, kNoteNumber}; +void render(BelaContext *context, void *userData) +{ +// one way of getting the midi data is to parse them yourself +// (you should set midi.enableParser(false) above): +/* + static midi_byte_t noteOnStatus = 0x90; //on channel 1 + static int noteNumber = 0; + static int waitingFor = kNoteOn; + static int playingNote = -1; + int message; + while ((message = midi.getInput()) >= 0){ + rt_printf("%d\n", message); + switch(waitingFor){ + case kNoteOn: + if(message == noteOnStatus){ + waitingFor = kNoteNumber; + } + break; + case kNoteNumber: + if((message & (1<<8)) == 0){ + noteNumber = message; + waitingFor = kVelocity; + } + break; + case kVelocity: + if((message & (1<<8)) == 0){ + int _velocity = message; + waitingFor = kNoteOn; + // "monophonic" behaviour, with priority to the latest note on + // i.e.: a note off from a previous note does not stop the current note + // still you might end up having a key down and no note being played if you pressed and released another + // key in the meantime + if(_velocity == 0 && noteNumber == playingNote){ + noteOn = false; + playingNote = -1; + velocity = _velocity; + } else if (_velocity > 0) { + noteOn = true; + velocity = _velocity; + playingNote = noteNumber; + f0 = powf(2, (playingNote-69)/12.0f) * 440; + phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate; + } + rt_printf("NoteOn: %d, NoteNumber: %d, velocity: %d\n", noteOn, noteNumber, velocity); + } + break; + } + } +*/ + /* + int num; + //alternatively, you can use the built-in parser (only processes channel messages at the moment). + while((num = midi.getParser()->numAvailableMessages()) > 0){ + static MidiChannelMessage message; + message = midi.getParser()->getNextChannelMessage(); + message.prettyPrint(); + if(message.getType() == kmmNoteOn){ + f0 = powf(2, (message.getDataByte(0)-69)/12.0f) * 440; + velocity = message.getDataByte(1); + phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate; + noteOn = velocity > 0; + rt_printf("v0:%f, ph: %6.5f, velocity: %d\n", f0, phaseIncrement, gVelocity); + } + } + */ + // the following block toggles the LED on an Owl pedal + // and asks the pedal to return the status of the LED + // using MIDI control changes + for(unsigned int n = 0; n < context->analogFrames; n++){ + static int count = 0; + static bool state = 0; + analogWriteOnce(context, n, 1, state); + if(count % 40000 == 0){ + state = !state; + midi_byte_t bytes[6] = {176, 30, (char)(state*127), 176, 67, 30}; // toggle the OWL led and ask for the led status + midi.writeOutput(bytes, 6); + } + count++; + } + for(unsigned int n = 0; n < context->audioFrames; n++){ + if(gIsNoteOn == 1){ + static float phase = 0; + phase += gPhaseIncrement; + if(phase > 2 * M_PI) + phase -= 2 * M_PI; + float value = sinf(phase) * gVelocity/128.0f; + audioWrite(context, n, 0, value); + audioWrite(context, n, 1, value); + } else { + audioWrite(context, n, 0, 0); + audioWrite(context, n, 1, 0); + } + } +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/05-Communication/basic-network/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,114 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <unistd.h> +#include <Bela.h> + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + float frequency = 440.0; // Frequency of oscillator + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"frequency", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + frequency = atof(optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &frequency) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/05-Communication/basic-network/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,101 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +//#include <rtdk.h> +#include <cmath> +#include <NetworkSend.h> +#include <ReceiveAudioThread.h> +#include <Utilities.h> + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + +NetworkSend networkSend; +ReceiveAudioThread receive; +float gFrequency; +float gInverseSampleRate; +float gPhase; +bool setup(BelaContext *context, void *userData) +{ + // Retrieve a parameter passed in from the initAudio() call + gFrequency = *(float *)userData; + + networkSend.setup(context->audioSampleRate, context->audioFrames, 0, 9999, "192.168.7.1"); + receive.init(10000, context->audioFrames, 0); + receive.startThread(); + gInverseSampleRate = 1.0 / context->audioSampleRate; + gPhase = 0; + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + float out = 0.7f * sinf(gPhase); + gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; + if(gPhase > 2.0 * M_PI) + gPhase -= 2.0 * M_PI; + + networkSend.log(out); + float in; + int ret = receive.getSamplesSrc(&in, 1, 1); + for(unsigned int channel = 0; channel < context->audioChannels; channel++){ + audioWrite(context, n, channel, in); + } + } +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 05-basic-network + +Networking +---------- + +This sketch allows you to send audio and sensor data over UDP to a +DAW on the host. The host needs to run Udpioplugin which you can find +[here](https://code.soundsoftware.ac.uk/projects/udpioplugin). + +Note that this sketch and the accompanying plugin are still in testing. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/06-Sensors/basic-pulseIn/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,73 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <PulseIn.h> +#include <stdlib.h> +#include <rtdk.h> +#include <cmath> + +PulseIn pulseIn; +int gPulseInPin = 0; +int gDigitalOutPin = 1; +int gPulseLength = 1234; +int gSamplesBetweenPulses = 10000; + +bool setup(BelaContext *context, void *userData) +{ + pinMode(context, 0, gDigitalOutPin, OUTPUT); + pulseIn.init(context, gPulseInPin, 1); //third parameter is direction + return true; +} + +void render(BelaContext *context, void *userData) +{ + static bool pulseOut = 0; + static int count = 0; + for(unsigned int n = 0; n < context->digitalFrames; n++){ + // detect if a pulse just ended + int duration = pulseIn.hasPulsed(context, n); + if(duration > 0){ + rt_printf("duration = %d\n", duration); + } + + // generate a rectangular waveform as a test signal. + // Connect gDigitalOutPin to gPulseInPin + // to verify that the detected pulse length is gPulseLength + if(count == gPulseLength ){ + pulseOut = false; + } + if(count == (gPulseLength + gSamplesBetweenPulses)){ + pulseOut = true; + count = 0; + } + digitalWrite(context, n, gDigitalOutPin, pulseOut); + count++; + } +} + +void cleanup(BelaContext *context, void *userData) +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/06-Sensors/mpr121/I2C_MPR121.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,176 @@ +/* + * I2C_MPR121.cpp + * + * Created on: Oct 14, 2013 + * Author: Victor Zappi + */ + + +#include "I2C_MPR121.h" + +I2C_MPR121::I2C_MPR121() { + +} + +boolean I2C_MPR121::begin(uint8_t bus, uint8_t i2caddr) { + _i2c_address = i2caddr; + + if(initI2C_RW(bus, i2caddr, 0) > 0) + return false; + + // soft reset + writeRegister(MPR121_SOFTRESET, 0x63); + usleep(1000); + //delay(1); + for (uint8_t i=0; i<0x7F; i++) { + // Serial.print("$"); Serial.print(i, HEX); + // Serial.print(": 0x"); Serial.println(readRegister8(i)); + } + + + writeRegister(MPR121_ECR, 0x0); + + uint8_t c = readRegister8(MPR121_CONFIG2); + + if (c != 0x24) { + rt_printf("MPR121 read 0x%x instead of 0x24\n", c); + return false; + } + + setThresholds(12, 6); + writeRegister(MPR121_MHDR, 0x01); + writeRegister(MPR121_NHDR, 0x01); + writeRegister(MPR121_NCLR, 0x0E); + writeRegister(MPR121_FDLR, 0x00); + + writeRegister(MPR121_MHDF, 0x01); + writeRegister(MPR121_NHDF, 0x05); + writeRegister(MPR121_NCLF, 0x01); + writeRegister(MPR121_FDLF, 0x00); + + writeRegister(MPR121_NHDT, 0x00); + writeRegister(MPR121_NCLT, 0x00); + writeRegister(MPR121_FDLT, 0x00); + + writeRegister(MPR121_DEBOUNCE, 0); + writeRegister(MPR121_CONFIG1, 0x10); // default, 16uA charge current + writeRegister(MPR121_CONFIG2, 0x20); // 0.5uS encoding, 1ms period + +// writeRegister(MPR121_AUTOCONFIG0, 0x8F); + +// writeRegister(MPR121_UPLIMIT, 150); +// writeRegister(MPR121_TARGETLIMIT, 100); // should be ~400 (100 shifted) +// writeRegister(MPR121_LOWLIMIT, 50); + // enable all electrodes + writeRegister(MPR121_ECR, 0x8F); // start with first 5 bits of baseline tracking + + return true; +} + +void I2C_MPR121::setThresholds(uint8_t touch, uint8_t release) { + for (uint8_t i=0; i<12; i++) { + writeRegister(MPR121_TOUCHTH_0 + 2*i, touch); + writeRegister(MPR121_RELEASETH_0 + 2*i, release); + } +} + +uint16_t I2C_MPR121::filteredData(uint8_t t) { + if (t > 12) return 0; + return readRegister16(MPR121_FILTDATA_0L + t*2); +} + +uint16_t I2C_MPR121::baselineData(uint8_t t) { + if (t > 12) return 0; + uint16_t bl = readRegister8(MPR121_BASELINE_0 + t); + return (bl << 2); +} + +uint16_t I2C_MPR121::touched(void) { + uint16_t t = readRegister16(MPR121_TOUCHSTATUS_L); + return t & 0x0FFF; +} + +/*********************************************************************/ + + +uint8_t I2C_MPR121::readRegister8(uint8_t reg) { + unsigned char inbuf, outbuf; + struct i2c_rdwr_ioctl_data packets; + struct i2c_msg messages[2]; + + /* + * In order to read a register, we first do a "dummy write" by writing + * 0 bytes to the register we want to read from. This is similar to + * the packet in set_i2c_register, except it's 1 byte rather than 2. + */ + outbuf = reg; + messages[0].addr = 0x5A; + messages[0].flags = 0; + messages[0].len = sizeof(outbuf); + messages[0].buf = &outbuf; + + /* The data will get returned in this structure */ + messages[1].addr = 0x5A; + messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/; + messages[1].len = sizeof(inbuf); + messages[1].buf = &inbuf; + + /* Send the request to the kernel and get the result back */ + packets.msgs = messages; + packets.nmsgs = 2; + if(ioctl(i2C_file, I2C_RDWR, &packets) < 0) { + rt_printf("Unable to send data"); + return 0; + } + + return inbuf; +} + +uint16_t I2C_MPR121::readRegister16(uint8_t reg) { + unsigned char inbuf[2], outbuf; + struct i2c_rdwr_ioctl_data packets; + struct i2c_msg messages[2]; + + /* + * In order to read a register, we first do a "dummy write" by writing + * 0 bytes to the register we want to read from. This is similar to + * the packet in set_i2c_register, except it's 1 byte rather than 2. + */ + outbuf = reg; + messages[0].addr = _i2c_address; + messages[0].flags = 0; + messages[0].len = sizeof(outbuf); + messages[0].buf = &outbuf; + + /* The data will get returned in this structure */ + messages[1].addr = _i2c_address; + messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/; + messages[1].len = sizeof(inbuf); + messages[1].buf = inbuf; + + /* Send the request to the kernel and get the result back */ + packets.msgs = messages; + packets.nmsgs = 2; + if(ioctl(i2C_file, I2C_RDWR, &packets) < 0) { + rt_printf("Unable to send data"); + return 0; + } + + return (uint16_t)inbuf[0] | (((uint16_t)inbuf[1]) << 8); +} + +/**************************************************************************/ +/*! + @brief Writes 8-bits to the specified destination register +*/ +/**************************************************************************/ +void I2C_MPR121::writeRegister(uint8_t reg, uint8_t value) { + uint8_t buf[2] = { reg, value }; + + if(write(i2C_file, buf, 2) != 2) + { + cout << "Failed to write register " << (int)reg << " on MPR121\n"; + return; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/06-Sensors/mpr121/I2C_MPR121.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,82 @@ +/* + * MPR121 Bela demo + * + * Andrew McPherson + * Based on Adafruit library by Limor Fried/Ladyada + */ + +#ifndef I2CTK_H_ +#define I2CTK_H_ + +#include <I2c.h> +#include "Utilities.h" + +typedef bool boolean; + +#define MPR121_I2CADDR_DEFAULT 0x5A + +#define MPR121_TOUCHSTATUS_L 0x00 +#define MPR121_TOUCHSTATUS_H 0x01 +#define MPR121_FILTDATA_0L 0x04 +#define MPR121_FILTDATA_0H 0x05 +#define MPR121_BASELINE_0 0x1E +#define MPR121_MHDR 0x2B +#define MPR121_NHDR 0x2C +#define MPR121_NCLR 0x2D +#define MPR121_FDLR 0x2E +#define MPR121_MHDF 0x2F +#define MPR121_NHDF 0x30 +#define MPR121_NCLF 0x31 +#define MPR121_FDLF 0x32 +#define MPR121_NHDT 0x33 +#define MPR121_NCLT 0x34 +#define MPR121_FDLT 0x35 + +#define MPR121_TOUCHTH_0 0x41 +#define MPR121_RELEASETH_0 0x42 +#define MPR121_DEBOUNCE 0x5B +#define MPR121_CONFIG1 0x5C +#define MPR121_CONFIG2 0x5D +#define MPR121_CHARGECURR_0 0x5F +#define MPR121_CHARGETIME_1 0x6C +#define MPR121_ECR 0x5E +#define MPR121_AUTOCONFIG0 0x7B +#define MPR121_AUTOCONFIG1 0x7C +#define MPR121_UPLIMIT 0x7D +#define MPR121_LOWLIMIT 0x7E +#define MPR121_TARGETLIMIT 0x7F + +#define MPR121_GPIODIR 0x76 +#define MPR121_GPIOEN 0x77 +#define MPR121_GPIOSET 0x78 +#define MPR121_GPIOCLR 0x79 +#define MPR121_GPIOTOGGLE 0x7A + +#define MPR121_SOFTRESET 0x80 + +class I2C_MPR121 : public I2c +{ +public: + // Hardware I2C + I2C_MPR121(); + + boolean begin(uint8_t bus = 1, uint8_t i2caddr = MPR121_I2CADDR_DEFAULT); + + uint16_t filteredData(uint8_t t); + uint16_t baselineData(uint8_t t); + + uint8_t readRegister8(uint8_t reg); + uint16_t readRegister16(uint8_t reg); + void writeRegister(uint8_t reg, uint8_t value); + uint16_t touched(void); + + void setThresholds(uint8_t touch, uint8_t release); + + int readI2C() { return 0; } // Unused + +private: + int _i2c_address; +}; + + +#endif /* I2CTK_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/06-Sensors/mpr121/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,171 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> +#include <rtdk.h> +#include "I2C_MPR121.h" + +// How many pins there are +#define NUM_TOUCH_PINS 12 + +// Define this to print data to terminal +#undef DEBUG_MPR121 + +// Change this to change how often the MPR121 is read (in Hz) +int readInterval = 50; + +// Change this threshold to set the minimum amount of touch +int threshold = 40; + +// This array holds the continuous sensor values +int sensorValue[NUM_TOUCH_PINS]; + +// ---- test code stuff -- can be deleted for your example ---- + +// 12 notes of a C major scale... +float gFrequencies[NUM_TOUCH_PINS] = {261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25, 587.33, 659.25, 698.25, 783.99}; + +// This is internal stuff for the demo +float gNormFrequencies[NUM_TOUCH_PINS]; +float gPhases[NUM_TOUCH_PINS] = {0}; + +// ---- internal stuff -- do not change ----- + +I2C_MPR121 mpr121; // Object to handle MPR121 sensing +AuxiliaryTask i2cTask; // Auxiliary task to read I2C + +int readCount = 0; // How long until we read again... +int readIntervalSamples = 0; // How many samples between reads + +void readMPR121(); + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + +bool setup(BelaContext *context, void *userData) +{ + if(!mpr121.begin(1, 0x5A)) { + rt_printf("Error initialising MPR121\n"); + return false; + } + + i2cTask = Bela_createAuxiliaryTask(readMPR121, 50, "bela-mpr121"); + readIntervalSamples = context->audioSampleRate / readInterval; + + for(int i = 0; i < NUM_TOUCH_PINS; i++) { + gNormFrequencies[i] = 2.0 * M_PI * gFrequencies[i] / context->audioSampleRate; + } + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numAnalogFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + for(int n = 0; n < context->audioFrames; n++) { + // Keep this code: it schedules the touch sensor readings + if(++readCount >= readIntervalSamples) { + readCount = 0; + Bela_scheduleAuxiliaryTask(i2cTask); + } + + float sample = 0.0; + + // This code can be replaced with your favourite audio code + for(int i = 0; i < NUM_TOUCH_PINS; i++) { + float amplitude = sensorValue[i] / 400.0; + + // Prevent clipping + if(amplitude > 0.5) + amplitude = 0.5; + + sample += amplitude * sinf(gPhases[i]); + gPhases[i] += gNormFrequencies[i]; + if(gPhases[i] > 2.0 * M_PI) + gPhases[i] -= 2.0 * M_PI; + } + + for(int ch = 0; ch < context->audioChannels; ch++) + context->audioOut[context->audioChannels * n + ch] = sample; + } +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + // Nothing to do here +} + + +// Auxiliary task to read the I2C board +void readMPR121() +{ + for(int i = 0; i < NUM_TOUCH_PINS; i++) { + sensorValue[i] = -(mpr121.filteredData(i) - mpr121.baselineData(i)); + sensorValue[i] -= threshold; + if(sensorValue[i] < 0) + sensorValue[i] = 0; +#ifdef DEBUG_MPR121 + rt_printf("%d ", sensorValue[i]); +#endif + } +#ifdef DEBUG_MPR121 + rt_printf("\n"); +#endif + + // You can use this to read binary on/off touch state more easily + //rt_printf("Touched: %x\n", mpr121.touched()); +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 06-capacitive-touch + +Capacitive touch sensing with MPR121 +--------------------------- + +This sketch allows you to hook up an MPR121 capactive touch sensing device +to Bela, for example the SparkFun Capacitive Touch Sensor Breakout - MPR121. +The breakout board gives you 12 electrode connections. + +To get this working with Bela you need to connect the breakout board to the I2C +terminal on the Bela board. See the Pin guide for details of which pin is which. + +The sensor data will then be available for you to use in the array +`sensorValue[NUM_TOUCH_PINS]`. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/07-DataLogging/basic-writeFile/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,115 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <unistd.h> +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + float frequency = 440.0; // Frequency of oscillator + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"frequency", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + frequency = atof(optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &frequency) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/07-DataLogging/basic-writeFile/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,100 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> +#include <WriteFile.h> + +float gPhase1, gPhase2; +float gFrequency1, gFrequency2; +float gInverseSampleRate; + +WriteFile file1; +WriteFile file2; + +bool setup(BelaContext *context, void *userData) +{ + gInverseSampleRate = 1.0/context->audioSampleRate; + file1.init("out1.m"); //set the file name to write to + file1.setHeader("myvar=[\n"); //set a line to be printed at the beginning of the file + file1.setFooter("];\n"); //set a line to be printed at the end of the file + file1.setEcho(true); // enable echo to the console (as well as to the file) + file1.setFormat("%.5f %.10f %f\n"); // set the format that you want to use for your output. Please use %f only (with modifiers) + file2.init("out2.m"); + file2.setHeader("input=[\n"); + file2.setFooter("];\n"); + file2.setEcho(false); + file2.setFormat("%f\n"); + gPhase1 = 0.0; + gPhase2 = 0.0; + + gFrequency1 = 200.0; + gFrequency2 = 201.0; + return true; +} + +void render(BelaContext *context, void *userData) +{ + static int count = 0; + if((count&16383) == 0){ + file2.log(context->audioIn, context->audioFrames); //write the input buffer every so often + } + for(unsigned int n = 0; n < context->audioFrames; n++) { + float chn1 = sinf(gPhase1); + float chn2 = sinf(gPhase2); + gPhase1 += 2.0 * M_PI * gFrequency1 * gInverseSampleRate; + gPhase2 += 2.0 * M_PI * gFrequency2 * gInverseSampleRate; + if(gPhase1 > 2.0 * M_PI) + gPhase1 -= 2.0 * M_PI; + if(gPhase2 > 2.0 * M_PI) + gPhase2 -= 2.0 * M_PI; + if( (count&511) == 0){ + file1.log(chn1); + file1.log(chn2); + file1.log(count); + } + count++; + } +} + +// cleanup_render() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in initialise_render(). + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 07-write-file + +Writing data to a file +--------------------------- + +This sketch demonstrates how to log values from within a project for later processing or analysis. + +*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/07-DataLogging/loggingSensors/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,115 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <unistd.h> +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + float frequency = 440.0; // Frequency of oscillator + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"frequency", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + frequency = atof(optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &frequency) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/07-DataLogging/loggingSensors/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,73 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> +#include <cmath> +#include <WriteFile.h> + +WriteFile file1; +WriteFile file2; + +bool setup(BelaContext *context, void *userData) +{ + file1.init("out.bin"); //set the file name to write to + file1.setEchoInterval(1000); + file1.setFileType(kBinary); + file1.setFormat("%.4f %.4f\n"); // set the format that you want to use for your output. Please use %f only (with modifiers). When in binary mode, this is used only for echoing to console + file2.init("out.m"); //set the file name to write to + file2.setHeader("myvar=[\n"); //set one or more lines to be printed at the beginning of the file + file2.setFooter("];\n"); //set one or more lines to be printed at the end of the file + file2.setFormat("%.4f\n"); // set the format that you want to use for your output. Please use %f only (with modifiers) + file2.setFileType(kText); + file2.setEchoInterval(10000); // only print to the console 1 line every other 10000 + return true; +} + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->analogFrames; n++) { + file1.log(&(context->analogIn[n*context->analogFrames]), 2); // log an array of values + file2.log(context->analogIn[n*context->analogFrames]); // log a single value + } +} + +// cleanup_render() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in initialise_render(). + +void cleanup(BelaContext *context, void *userData) +{ + +} + +/* ------------ Project Explantation ------------ */ + +/** +\example 07-logging-sensors + +Logging Sensor Data +--------------------------- + +This sketch demonstrates how to log sensor data for later processing or analysis. +*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/basicAnalogIn/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,30 @@ +#N canvas 203 356 637 339 10; +#X obj 63 170 osc~ 440; +#X obj 63 223 dac~; +#X obj 63 191 *~; +#X text 440 95 ADC 3: Analog In 0; +#X text 34 41 Basic analog in (or 'theremin'); +#X text 34 51 ===============================; +#X text 121 105 << Use first two analog in's; +#X text 440 49 ADC routing:; +#X text 440 57 ------------; +#X text 440 105 ADC 4: Analog In 1; +#X text 440 115 ADC 5: Analog In 2; +#X text 440 125 ADC 6: Analog In 3; +#X text 440 135 ADC 7: Analog In 4; +#X text 440 145 ADC 8: Analog In 5; +#X text 440 155 ADC 9: Analog In 6; +#X text 440 165 ADC 10: Analog In 7; +#X text 440 75 ADC 1: Audio In L; +#X text 440 85 ADC 2: Audio In R; +#X obj 63 149 *~ 880; +#X obj 63 106 adc~ 3 4; +#X text 355 277 ---------------------------------; +#X text 355 267 @krighxz / BELA / heavy / 12/2015; +#X text 379 286 beaglert.cc / enzienaudio.com; +#X connect 0 0 2 0; +#X connect 2 0 1 0; +#X connect 2 0 1 1; +#X connect 18 0 0 0; +#X connect 19 0 18 0; +#X connect 19 1 2 1;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/basicAnalogOut/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,30 @@ +#N canvas 275 504 679 362 10; +#X text 148 124 << Use first two analog in's; +#X text 431 57 ------------; +#X text 44 51 Basic analog out; +#X text 44 61 ================; +#X text 431 95 DAC 3: Analog Out 0; +#X text 431 105 DAC 4: Analog Out 1; +#X text 431 115 DAC 5: Analog Out 2; +#X text 431 125 DAC 6: Analog Out 3; +#X text 431 145 DAC 8: Analog Out 5; +#X text 431 135 DAC 7: Analog Out 4; +#X text 431 155 DAC 9: Analog Out 6; +#X text 431 165 DAC 10: Analog Out 7; +#X text 431 85 DAC 2: Audio Out R; +#X text 431 75 DAC 1: Audio Out L; +#X obj 92 201 *~; +#X obj 92 159 *~ 10; +#X obj 92 180 osc~ 1; +#X obj 35 242 dac~ 1 2 3; +#X text 143 241 << Output to first analog out; +#X text 431 49 DAC routing:; +#X text 432 289 ---------------------------------; +#X text 432 279 @krighxz / BELA / heavy / 12/2015; +#X text 456 298 beaglert.cc / enzienaudio.com; +#X obj 92 125 adc~ 3 4; +#X connect 14 0 17 2; +#X connect 15 0 16 0; +#X connect 16 0 14 0; +#X connect 23 0 15 0; +#X connect 23 1 14 1;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/basic_libpd/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,97 @@ +#N canvas 121 46 877 628 10; +#X obj 64 94 r bela_digitalIn11; +#X obj 219 94 r bela_digitalIn12; +#X obj 386 107 adc~ 13 14; +#X text 49 64 Digital in \, message rate; +#X text 214 69 Digital in \, message rate; +#X text 394 85 Digital ins \, signal rate; +#X obj 32 283 s bela_digitalOut15; +#X text 13 309 Digital out \, message rate; +#X obj 396 593 s bela_setDigital; +#X obj 396 533 loadbang; +#X msg 431 401 in 11; +#X text 524 390 First argument is the pin direction Second argument +is the pin number Third argument is the rate \, can be "~" or "sig" +for signal-rate or "message" for message-rate. Defaults to message-rate. +; +#X msg 431 458 in 13 ~; +#X msg 432 429 in 12 message; +#X msg 517 506 disable 17; +#X obj 386 139 snapshot~; +#X obj 500 134 snapshot~; +#X obj 529 56 loadbang; +#X obj 384 181 print digitalIn13; +#X obj 500 183 print digitalIn14; +#X obj 497 105 metro 200; +#X text 525 474 To stop using a pin (e.g.: to save CPU) \, send a disable +message containing the pin number; +#X obj 224 280 dac~ 16; +#X obj 22 232 metro 500; +#X obj 32 257 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 224 253 phasor~ 300; +#X text 160 234 Nice \, anti-aliased square wave; +#X obj 22 207 loadbang; +#X text 15 181 Blink that LED!; +#X obj 411 306 dac~ 17; +#X obj 405 248 osc~ 300; +#X obj 470 248 phasor~ 169; +#X obj 457 278 -~ 0.5; +#X text 403 210 Sum signals together for unpredictable effects; +#X obj 612 303 dac~ 18; +#X text 198 305 Digital out \, signal rate; +#X text 378 325 Digital out \, signal rate; +#X text 588 325 Digital out \, signal rate; +#X obj 608 222 adc~; +#X obj 612 249 *~ 0.5; +#X obj 612 276 +~ 0.5; +#X text 585 203 The ultimate bit-crusher; +#X msg 426 555 in 11 \, in 12 \, in 13 ~ \, in 14 ~ \, out 15 \, out +16 ~ \, out 17 ~ \, out 18 ~; +#X text 23 377 Each digital channel can be configured as either an +input or an output. Send messages to bela_setDigital to configure the +digitalPins (needed before using them). Pins settings can be modified +at will during execution. Message-rate input pins receive messages +only when the input changes. Message-rate output pins will write to +the output the most recent value you send them. Signal-rate inputs +and outputs are handled as regular audio channels. Outputs are thresholded +to 0.5 before being written to the actual output. Note that each pin +that is managed adds to the CPU usage \, so only activate the pins +you actually need.; +#X text 34 19 Digital channels are numbered 11 to 26 \, which corresponds +to Bela's 0 to 15 digital channels. They can be set to respond at message +rate or at signal rate; +#X obj 415 271 osc~ 1; +#X obj 385 157 change; +#X obj 500 158 change; +#X obj 64 116 print digitalIn11; +#X obj 219 117 print digitalIn12; +#X connect 0 0 48 0; +#X connect 1 0 49 0; +#X connect 2 0 15 0; +#X connect 2 1 16 0; +#X connect 9 0 42 0; +#X connect 10 0 8 0; +#X connect 12 0 8 0; +#X connect 13 0 8 0; +#X connect 14 0 8 0; +#X connect 15 0 46 0; +#X connect 16 0 47 0; +#X connect 17 0 20 0; +#X connect 20 0 16 0; +#X connect 20 0 15 0; +#X connect 23 0 24 0; +#X connect 24 0 6 0; +#X connect 25 0 22 0; +#X connect 27 0 23 0; +#X connect 30 0 29 0; +#X connect 31 0 32 0; +#X connect 32 0 29 0; +#X connect 38 0 39 0; +#X connect 38 1 39 0; +#X connect 39 0 40 0; +#X connect 40 0 34 0; +#X connect 42 0 8 0; +#X connect 45 0 29 0; +#X connect 46 0 18 0; +#X connect 47 0 19 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/basic_libpd/m_pd.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,770 @@ +/* Copyright (c) 1997-1999 Miller Puckette. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#ifndef __m_pd_h_ + +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +extern "C" { +#endif + +#define PD_MAJOR_VERSION 0 +#define PD_MINOR_VERSION 46 +#define PD_BUGFIX_VERSION 6 +#define PD_TEST_VERSION "" +extern int pd_compatibilitylevel; /* e.g., 43 for pd 0.43 compatibility */ + +/* old name for "MSW" flag -- we have to take it for the sake of many old +"nmakefiles" for externs, which will define NT and not MSW */ +#if defined(NT) && !defined(MSW) +#define MSW +#endif + +/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans@at.or.at> */ +#ifdef _MSC_VER +/* #pragma warning( disable : 4091 ) */ +#pragma warning( disable : 4305 ) /* uncast const double to float */ +#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */ +#pragma warning( disable : 4101 ) /* unused automatic variables */ +#endif /* _MSC_VER */ + + /* the external storage class is "extern" in UNIX; in MSW it's ugly. */ +#ifdef _WIN32 +#ifdef PD_INTERNAL +#define EXTERN __declspec(dllexport) extern +#else +#define EXTERN __declspec(dllimport) extern +#endif /* PD_INTERNAL */ +#else +#define EXTERN extern +#endif /* _WIN32 */ + + /* and depending on the compiler, hidden data structures are + declared differently: */ +#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ ) +#define EXTERN_STRUCT struct +#else +#define EXTERN_STRUCT extern struct +#endif + +/* Define some attributes, specific to the compiler */ +#if defined(__GNUC__) +#define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__ ((format (printf, a, b))) +#else +#define ATTRIBUTE_FORMAT_PRINTF(a, b) +#endif + +#if !defined(_SIZE_T) && !defined(_SIZE_T_) +#include <stddef.h> /* just for size_t -- how lame! */ +#endif + +/* Microsoft Visual Studio is not C99, it does not provide stdint.h */ +#ifdef _MSC_VER +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef signed __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +# include <stdint.h> +#endif + +/* for FILE, needed by sys_fopen() and sys_fclose() only */ +#include <stdio.h> + +#define MAXPDSTRING 1000 /* use this for anything you want */ +#define MAXPDARG 5 /* max number of args we can typecheck today */ + +/* signed and unsigned integer types the size of a pointer: */ +#if !defined(PD_LONGINTTYPE) +#define PD_LONGINTTYPE long +#endif + +#if !defined(PD_FLOATSIZE) + /* normally, our floats (t_float, t_sample,...) are 32bit */ +# define PD_FLOATSIZE 32 +#endif + +#if PD_FLOATSIZE == 32 +# define PD_FLOATTYPE float +/* an unsigned int of the same size as FLOATTYPE: */ +# define PD_FLOATUINTTYPE unsigned int + +#elif PD_FLOATSIZE == 64 +# define PD_FLOATTYPE double +# define PD_FLOATUINTTYPE unsigned long +#else +# error invalid FLOATSIZE: must be 32 or 64 +#endif + +typedef PD_LONGINTTYPE t_int; /* pointer-size integer */ +typedef PD_FLOATTYPE t_float; /* a float type at most the same size */ +typedef PD_FLOATTYPE t_floatarg; /* float type for function calls */ + +typedef struct _symbol +{ + char *s_name; + struct _class **s_thing; + struct _symbol *s_next; +} t_symbol; + +EXTERN_STRUCT _array; +#define t_array struct _array /* g_canvas.h */ + +/* pointers to glist and array elements go through a "stub" which sticks +around after the glist or array is freed. The stub itself is deleted when +both the glist/array is gone and the refcount is zero, ensuring that no +gpointers are pointing here. */ + +#define GP_NONE 0 /* the stub points nowhere (has been cut off) */ +#define GP_GLIST 1 /* the stub points to a glist element */ +#define GP_ARRAY 2 /* ... or array */ + +typedef struct _gstub +{ + union + { + struct _glist *gs_glist; /* glist we're in */ + struct _array *gs_array; /* array we're in */ + } gs_un; + int gs_which; /* GP_GLIST/GP_ARRAY */ + int gs_refcount; /* number of gpointers pointing here */ +} t_gstub; + +typedef struct _gpointer /* pointer to a gobj in a glist */ +{ + union + { + struct _scalar *gp_scalar; /* scalar we're in (if glist) */ + union word *gp_w; /* raw data (if array) */ + } gp_un; + int gp_valid; /* number which must match gpointee */ + t_gstub *gp_stub; /* stub which points to glist/array */ +} t_gpointer; + +typedef union word +{ + t_float w_float; + t_symbol *w_symbol; + t_gpointer *w_gpointer; + t_array *w_array; + struct _binbuf *w_binbuf; + int w_index; +} t_word; + +typedef enum +{ + A_NULL, + A_FLOAT, + A_SYMBOL, + A_POINTER, + A_SEMI, + A_COMMA, + A_DEFFLOAT, + A_DEFSYM, + A_DOLLAR, + A_DOLLSYM, + A_GIMME, + A_CANT +} t_atomtype; + +#define A_DEFSYMBOL A_DEFSYM /* better name for this */ + +typedef struct _atom +{ + t_atomtype a_type; + union word a_w; +} t_atom; + +EXTERN_STRUCT _class; +#define t_class struct _class + +EXTERN_STRUCT _outlet; +#define t_outlet struct _outlet + +EXTERN_STRUCT _inlet; +#define t_inlet struct _inlet + +EXTERN_STRUCT _binbuf; +#define t_binbuf struct _binbuf + +EXTERN_STRUCT _clock; +#define t_clock struct _clock + +EXTERN_STRUCT _outconnect; +#define t_outconnect struct _outconnect + +EXTERN_STRUCT _glist; +#define t_glist struct _glist +#define t_canvas struct _glist /* LATER lose this */ + +typedef t_class *t_pd; /* pure datum: nothing but a class pointer */ + +typedef struct _gobj /* a graphical object */ +{ + t_pd g_pd; /* pure datum header (class) */ + struct _gobj *g_next; /* next in list */ +} t_gobj; + +typedef struct _scalar /* a graphical object holding data */ +{ + t_gobj sc_gobj; /* header for graphical object */ + t_symbol *sc_template; /* template name (LATER replace with pointer) */ + t_word sc_vec[1]; /* indeterminate-length array of words */ +} t_scalar; + +typedef struct _text /* patchable object - graphical, with text */ +{ + t_gobj te_g; /* header for graphical object */ + t_binbuf *te_binbuf; /* holder for the text */ + t_outlet *te_outlet; /* linked list of outlets */ + t_inlet *te_inlet; /* linked list of inlets */ + short te_xpix; /* x&y location (within the toplevel) */ + short te_ypix; + short te_width; /* requested width in chars, 0 if auto */ + unsigned int te_type:2; /* from defs below */ +} t_text; + +#define T_TEXT 0 /* just a textual comment */ +#define T_OBJECT 1 /* a MAX style patchable object */ +#define T_MESSAGE 2 /* a MAX stype message */ +#define T_ATOM 3 /* a cell to display a number or symbol */ + +#define te_pd te_g.g_pd + + /* t_object is synonym for t_text (LATER unify them) */ + +typedef struct _text t_object; + +#define ob_outlet te_outlet +#define ob_inlet te_inlet +#define ob_binbuf te_binbuf +#define ob_pd te_g.g_pd +#define ob_g te_g + +typedef void (*t_method)(void); +typedef void *(*t_newmethod)( void); + +/* in ARM 64 a varargs prototype generates a different function call sequence +from a fixed one, so in that special case we make a more restrictive +definition for t_gotfn. This will break some code in the "chaos" package +in Pd extended. (that code will run incorrectly anyhow so why not catch it +at compile time anyhow.) */ +#if defined(__APPLE__) && defined(__aarch64__) +typedef void (*t_gotfn)(void *x); +#else +typedef void (*t_gotfn)(void *x, ...); +#endif + +/* ---------------- pre-defined objects and symbols --------------*/ +EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */ +EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */ +EXTERN t_symbol s_pointer; +EXTERN t_symbol s_float; +EXTERN t_symbol s_symbol; +EXTERN t_symbol s_bang; +EXTERN t_symbol s_list; +EXTERN t_symbol s_anything; +EXTERN t_symbol s_signal; +EXTERN t_symbol s__N; +EXTERN t_symbol s__X; +EXTERN t_symbol s_x; +EXTERN t_symbol s_y; +EXTERN t_symbol s_; + +/* --------- prototypes from the central message system ----------- */ +EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv); +EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv); +EXTERN t_symbol *gensym(const char *s); +EXTERN t_gotfn getfn(t_pd *x, t_symbol *s); +EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s); +EXTERN void nullfn(void); +EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...); + +/* the following macrose are for sending non-type-checkable mesages, i.e., +using function lookup but circumventing type checking on arguments. Only +use for internal messaging protected by A_CANT so that the message can't +be generated at patch level. */ +#define mess0(x, s) ((*getfn((x), (s)))((x))) +typedef void (*t_gotfn1)(void *x, void *arg1); +#define mess1(x, s, a) ((*(t_gotfn1)getfn((x), (s)))((x), (a))) +typedef void (*t_gotfn2)(void *x, void *arg1, void *arg2); +#define mess2(x, s, a,b) ((*(t_gotfn2)getfn((x), (s)))((x), (a),(b))) +typedef void (*t_gotfn3)(void *x, void *arg1, void *arg2, void *arg3); +#define mess3(x, s, a,b,c) ((*(t_gotfn3)getfn((x), (s)))((x), (a),(b),(c))) +typedef void (*t_gotfn4)(void *x, + void *arg1, void *arg2, void *arg3, void *arg4); +#define mess4(x, s, a,b,c,d) \ + ((*(t_gotfn4)getfn((x), (s)))((x), (a),(b),(c),(d))) +typedef void (*t_gotfn5)(void *x, + void *arg1, void *arg2, void *arg3, void *arg4, void *arg5); +#define mess5(x, s, a,b,c,d,e) \ + ((*(t_gotfn5)getfn((x), (s)))((x), (a),(b),(c),(d),(e))) + +EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv); +EXTERN t_pd *pd_newest(void); + +/* --------------- memory management -------------------- */ +EXTERN void *getbytes(size_t nbytes); +EXTERN void *getzbytes(size_t nbytes); +EXTERN void *copybytes(void *src, size_t nbytes); +EXTERN void freebytes(void *x, size_t nbytes); +EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize); + +/* -------------------- atoms ----------------------------- */ + +#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0) +#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0) +#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \ + (atom)->a_w.w_gpointer = (gp)) +#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f)) +#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \ + (atom)->a_w.w_symbol = (s)) +#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \ + (atom)->a_w.w_index = (n)) +#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \ + (atom)->a_w.w_symbol= (s)) + +EXTERN t_float atom_getfloat(t_atom *a); +EXTERN t_int atom_getint(t_atom *a); +EXTERN t_symbol *atom_getsymbol(t_atom *a); +EXTERN t_symbol *atom_gensym(t_atom *a); +EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv); +EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv); +EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv); + +EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize); + +/* ------------------ binbufs --------------- */ + +EXTERN t_binbuf *binbuf_new(void); +EXTERN void binbuf_free(t_binbuf *x); +EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y); + +EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size); +EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp); +EXTERN void binbuf_clear(t_binbuf *x); +EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv); +EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...); +EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y); +EXTERN void binbuf_addsemi(t_binbuf *x); +EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv); +EXTERN void binbuf_print(t_binbuf *x); +EXTERN int binbuf_getnatom(t_binbuf *x); +EXTERN t_atom *binbuf_getvec(t_binbuf *x); +EXTERN int binbuf_resize(t_binbuf *x, int newsize); +EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv); +EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname, + int crflag); +EXTERN int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas, + int crflag); +EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname, + int crflag); +EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir, + int crflag); +EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir); +EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, + int tonew); + +/* ------------------ clocks --------------- */ + +EXTERN t_clock *clock_new(void *owner, t_method fn); +EXTERN void clock_set(t_clock *x, double systime); +EXTERN void clock_delay(t_clock *x, double delaytime); +EXTERN void clock_unset(t_clock *x); +EXTERN void clock_setunit(t_clock *x, double timeunit, int sampflag); +EXTERN double clock_getlogicaltime(void); +EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */ +EXTERN double clock_gettimesince(double prevsystime); +EXTERN double clock_gettimesincewithunits(double prevsystime, + double units, int sampflag); +EXTERN double clock_getsystimeafter(double delaytime); +EXTERN void clock_free(t_clock *x); + +/* ----------------- pure data ---------------- */ +EXTERN t_pd *pd_new(t_class *cls); +EXTERN void pd_free(t_pd *x); +EXTERN void pd_bind(t_pd *x, t_symbol *s); +EXTERN void pd_unbind(t_pd *x, t_symbol *s); +EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c); +EXTERN void pd_pushsym(t_pd *x); +EXTERN void pd_popsym(t_pd *x); +EXTERN t_symbol *pd_getfilename(void); +EXTERN t_symbol *pd_getdirname(void); +EXTERN void pd_bang(t_pd *x); +EXTERN void pd_pointer(t_pd *x, t_gpointer *gp); +EXTERN void pd_float(t_pd *x, t_float f); +EXTERN void pd_symbol(t_pd *x, t_symbol *s); +EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv); +EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv); +#define pd_class(x) (*(x)) + +/* ----------------- pointers ---------------- */ +EXTERN void gpointer_init(t_gpointer *gp); +EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto); +EXTERN void gpointer_unset(t_gpointer *gp); +EXTERN int gpointer_check(const t_gpointer *gp, int headok); + +/* ----------------- patchable "objects" -------------- */ +EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, + t_symbol *s2); +EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp); +EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp); +EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp); +EXTERN t_inlet *signalinlet_new(t_object *owner, t_float f); +EXTERN void inlet_free(t_inlet *x); + +EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s); +EXTERN void outlet_bang(t_outlet *x); +EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp); +EXTERN void outlet_float(t_outlet *x, t_float f); +EXTERN void outlet_symbol(t_outlet *x, t_symbol *s); +EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv); +EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv); +EXTERN t_symbol *outlet_getsymbol(t_outlet *x); +EXTERN void outlet_free(t_outlet *x); +EXTERN t_object *pd_checkobject(t_pd *x); + + +/* -------------------- canvases -------------- */ + +EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir); + +EXTERN void canvas_setargs(int argc, t_atom *argv); +EXTERN void canvas_getargs(int *argcp, t_atom **argvp); +EXTERN t_symbol *canvas_getcurrentdir(void); +EXTERN t_glist *canvas_getcurrent(void); +EXTERN void canvas_makefilename(t_glist *c, char *file, + char *result,int resultsize); +EXTERN t_symbol *canvas_getdir(t_glist *x); +EXTERN char sys_font[]; /* default typeface set in s_main.c */ +EXTERN char sys_fontweight[]; /* default font weight set in s_main.c */ +EXTERN int sys_fontwidth(int fontsize); +EXTERN int sys_fontheight(int fontsize); +EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b); +EXTERN int canvas_open(t_canvas *x, const char *name, const char *ext, + char *dirresult, char **nameresult, unsigned int size, int bin); + +/* ---------------- widget behaviors ---------------------- */ + +EXTERN_STRUCT _widgetbehavior; +#define t_widgetbehavior struct _widgetbehavior + +EXTERN_STRUCT _parentwidgetbehavior; +#define t_parentwidgetbehavior struct _parentwidgetbehavior +EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x); + +/* -------------------- classes -------------- */ + +#define CLASS_DEFAULT 0 /* flags for new classes below */ +#define CLASS_PD 1 +#define CLASS_GOBJ 2 +#define CLASS_PATCHABLE 3 +#define CLASS_NOINLET 8 + +#define CLASS_TYPEMASK 3 + + +EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod, + t_method freemethod, size_t size, int flags, t_atomtype arg1, ...); +EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s, + t_atomtype type1, ...); +EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel, + t_atomtype arg1, ...); +EXTERN void class_addbang(t_class *c, t_method fn); +EXTERN void class_addpointer(t_class *c, t_method fn); +EXTERN void class_doaddfloat(t_class *c, t_method fn); +EXTERN void class_addsymbol(t_class *c, t_method fn); +EXTERN void class_addlist(t_class *c, t_method fn); +EXTERN void class_addanything(t_class *c, t_method fn); +EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s); +EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w); +EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w); +EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c); +EXTERN char *class_getname(t_class *c); +EXTERN char *class_gethelpname(t_class *c); +EXTERN char *class_gethelpdir(t_class *c); +EXTERN void class_setdrawcommand(t_class *c); +EXTERN int class_isdrawcommand(t_class *c); +EXTERN void class_domainsignalin(t_class *c, int onset); +EXTERN void class_set_extern_dir(t_symbol *s); +#define CLASS_MAINSIGNALIN(c, type, field) \ + class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0) + + /* prototype for functions to save Pd's to a binbuf */ +typedef void (*t_savefn)(t_gobj *x, t_binbuf *b); +EXTERN void class_setsavefn(t_class *c, t_savefn f); +EXTERN t_savefn class_getsavefn(t_class *c); +EXTERN void obj_saveformat(t_object *x, t_binbuf *bb); /* add format to bb */ + + /* prototype for functions to open properties dialogs */ +typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist); +EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f); +EXTERN t_propertiesfn class_getpropertiesfn(t_class *c); + +#ifndef PD_CLASS_DEF +#define class_addbang(x, y) class_addbang((x), (t_method)(y)) +#define class_addpointer(x, y) class_addpointer((x), (t_method)(y)) +#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y)) +#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y)) +#define class_addlist(x, y) class_addlist((x), (t_method)(y)) +#define class_addanything(x, y) class_addanything((x), (t_method)(y)) +#endif + +/* ------------ printing --------------------------------- */ +EXTERN void post(const char *fmt, ...); +EXTERN void startpost(const char *fmt, ...); +EXTERN void poststring(const char *s); +EXTERN void postfloat(t_floatarg f); +EXTERN void postatom(int argc, t_atom *argv); +EXTERN void endpost(void); +EXTERN void error(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); +EXTERN void verbose(int level, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); +EXTERN void bug(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); +EXTERN void pd_error(void *object, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); +EXTERN void logpost(const void *object, const int level, const char *fmt, ...) + ATTRIBUTE_FORMAT_PRINTF(3, 4); +EXTERN void sys_logerror(const char *object, const char *s); +EXTERN void sys_unixerror(const char *object); +EXTERN void sys_ouch(void); + + +/* ------------ system interface routines ------------------- */ +EXTERN int sys_isreadablefile(const char *name); +EXTERN int sys_isabsolutepath(const char *dir); +EXTERN void sys_bashfilename(const char *from, char *to); +EXTERN void sys_unbashfilename(const char *from, char *to); +EXTERN int open_via_path(const char *dir, const char *name, const char *ext, + char *dirresult, char **nameresult, unsigned int size, int bin); +EXTERN int sched_geteventno(void); +EXTERN double sys_getrealtime(void); +EXTERN int (*sys_idlehook)(void); /* hook to add idle time computation */ + +/* Win32's open()/fopen() do not handle UTF-8 filenames so we need + * these internal versions that handle UTF-8 filenames the same across + * all platforms. They are recommended for use in external + * objectclasses as well so they work with Unicode filenames on Windows */ +EXTERN int sys_open(const char *path, int oflag, ...); +EXTERN int sys_close(int fd); +EXTERN FILE *sys_fopen(const char *filename, const char *mode); +EXTERN int sys_fclose(FILE *stream); + +/* ------------ threading ------------------- */ +EXTERN void sys_lock(void); +EXTERN void sys_unlock(void); +EXTERN int sys_trylock(void); + + +/* --------------- signals ----------------------------------- */ + +typedef PD_FLOATTYPE t_sample; +typedef union _sampleint_union { + t_sample f; + PD_FLOATUINTTYPE i; +} t_sampleint_union; +#define MAXLOGSIG 32 +#define MAXSIGSIZE (1 << MAXLOGSIG) + +typedef struct _signal +{ + int s_n; /* number of points in the array */ + t_sample *s_vec; /* the array */ + t_float s_sr; /* sample rate */ + int s_refcount; /* number of times used */ + int s_isborrowed; /* whether we're going to borrow our array */ + struct _signal *s_borrowedfrom; /* signal to borrow it from */ + struct _signal *s_nextfree; /* next in freelist */ + struct _signal *s_nextused; /* next in used list */ + int s_vecsize; /* allocated size of array in points */ +} t_signal; + +typedef t_int *(*t_perfroutine)(t_int *args); + +EXTERN t_int *plus_perform(t_int *args); +EXTERN t_int *zero_perform(t_int *args); +EXTERN t_int *copy_perform(t_int *args); + +EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n); +EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n); +EXTERN void dsp_add_scalarcopy(t_float *in, t_sample *out, int n); +EXTERN void dsp_add_zero(t_sample *out, int n); + +EXTERN int sys_getblksize(void); +EXTERN t_float sys_getsr(void); +EXTERN int sys_get_inchannels(void); +EXTERN int sys_get_outchannels(void); + +EXTERN void dsp_add(t_perfroutine f, int n, ...); +EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec); +EXTERN void pd_fft(t_float *buf, int npoints, int inverse); +EXTERN int ilog2(int n); + +EXTERN void mayer_fht(t_sample *fz, int n); +EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag); +EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag); +EXTERN void mayer_realfft(int n, t_sample *real); +EXTERN void mayer_realifft(int n, t_sample *real); + +EXTERN float *cos_table; +#define LOGCOSTABSIZE 9 +#define COSTABSIZE (1<<LOGCOSTABSIZE) + +EXTERN int canvas_suspend_dsp(void); +EXTERN void canvas_resume_dsp(int oldstate); +EXTERN void canvas_update_dsp(void); +EXTERN int canvas_dspstate; + +/* up/downsampling */ +typedef struct _resample +{ + int method; /* up/downsampling method ID */ + + int downsample; /* downsampling factor */ + int upsample; /* upsampling factor */ + + t_sample *s_vec; /* here we hold the resampled data */ + int s_n; + + t_sample *coeffs; /* coefficients for filtering... */ + int coefsize; + + t_sample *buffer; /* buffer for filtering */ + int bufsize; +} t_resample; + +EXTERN void resample_init(t_resample *x); +EXTERN void resample_free(t_resample *x); + +EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method); +EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method); +EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method); + +/* ----------------------- utility functions for signals -------------- */ +EXTERN t_float mtof(t_float); +EXTERN t_float ftom(t_float); +EXTERN t_float rmstodb(t_float); +EXTERN t_float powtodb(t_float); +EXTERN t_float dbtorms(t_float); +EXTERN t_float dbtopow(t_float); + +EXTERN t_float q8_sqrt(t_float); +EXTERN t_float q8_rsqrt(t_float); +#ifndef N32 +EXTERN t_float qsqrt(t_float); /* old names kept for extern compatibility */ +EXTERN t_float qrsqrt(t_float); +#endif +/* --------------------- data --------------------------------- */ + + /* graphical arrays */ +EXTERN_STRUCT _garray; +#define t_garray struct _garray + +EXTERN t_class *garray_class; +EXTERN int garray_getfloatarray(t_garray *x, int *size, t_float **vec); +EXTERN int garray_getfloatwords(t_garray *x, int *size, t_word **vec); +EXTERN void garray_redraw(t_garray *x); +EXTERN int garray_npoints(t_garray *x); +EXTERN char *garray_vec(t_garray *x); +EXTERN void garray_resize(t_garray *x, t_floatarg f); /* avoid; use this: */ +EXTERN void garray_resize_long(t_garray *x, long n); /* better version */ +EXTERN void garray_usedindsp(t_garray *x); +EXTERN void garray_setsaveit(t_garray *x, int saveit); +EXTERN t_glist *garray_getglist(t_garray *x); +EXTERN t_array *garray_getarray(t_garray *x); +EXTERN t_class *scalar_class; + +EXTERN t_float *value_get(t_symbol *s); +EXTERN void value_release(t_symbol *s); +EXTERN int value_getfloat(t_symbol *s, t_float *f); +EXTERN int value_setfloat(t_symbol *s, t_float f); + +/* ------- GUI interface - functions to send strings to TK --------- */ +typedef void (*t_guicallbackfn)(t_gobj *client, t_glist *glist); + +EXTERN void sys_vgui(char *fmt, ...); +EXTERN void sys_gui(char *s); +EXTERN void sys_pretendguibytes(int n); +EXTERN void sys_queuegui(void *client, t_glist *glist, t_guicallbackfn f); +EXTERN void sys_unqueuegui(void *client); + /* dialog window creation and destruction */ +EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd); +EXTERN void gfxstub_deleteforkey(void *key); + +extern t_class *glob_pdobject; /* object to send "pd" messages */ + +/*------------- Max 0.26 compatibility --------------------*/ + +/* the following reflects the new way classes are laid out, with the class + pointing to the messlist and not vice versa. Externs shouldn't feel it. */ +typedef t_class *t_externclass; + +EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine, + t_method freeroutine, t_symbol *name, size_t size, int tiny, \ + t_atomtype arg1, ...); +EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...); + +#define t_getbytes getbytes +#define t_freebytes freebytes +#define t_resizebytes resizebytes +#define typedmess pd_typedmess +#define vmess pd_vmess + +/* A definition to help gui objects straddle 0.34-0.35 changes. If this is +defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */ + +#define PD_USE_TE_XPIX + +#ifndef _MSC_VER /* Microoft compiler can't handle "inline" function/macros */ +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) +/* a test for NANs and denormals. Should only be necessary on i386. */ +# if PD_FLOATSIZE == 32 +static inline int PD_BADFLOAT(t_sample f) { + t_sampleint_union u; + u.f=f; + return ((u.i & 0x7f800000)==0) || ((u.i&0x7f800000)==0x7f800000); +} +/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */ +static inline int PD_BIGORSMALL(t_sample f) { + t_sampleint_union u; + u.f=f; + return ((u.i & 0x60000000)==0) || ((u.i & 0x60000000)==0x60000000); +} +# else +# warning 64bit mode: BIGORSMALL not implemented yet +# define PD_BADFLOAT(f) 0 +# define PD_BIGORSMALL(f) 0 +# endif +#else +# define PD_BADFLOAT(f) 0 +# define PD_BIGORSMALL(f) 0 +#endif +#else /* _MSC_VER */ +#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \ + (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000)) +/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */ +#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \ + (((*(unsigned int*)&(f))&0x60000000)==0x60000000)) +#endif /* _MSC_VER */ + /* get version number at run time */ +EXTERN void sys_getversion(int *major, int *minor, int *bugfix); + +EXTERN_STRUCT _pdinstance; +#define t_pdinstance struct _pdinstance /* m_imp.h */ + +/* m_pd.c */ + +EXTERN t_pdinstance *pdinstance_new( void); +EXTERN void pd_setinstance(t_pdinstance *x); +EXTERN void pdinstance_free(t_pdinstance *x); +EXTERN t_canvas *pd_getcanvaslist(void); +EXTERN int pd_getdspstate(void); + +#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) +} +#endif + +#define __m_pd_h_ +#endif /* __m_pd_h_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/basic_libpd/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,91 @@ +/* + * default_main.cpp + * + * Created on: Oct 24, 2014 + * Author: parallels + */ +#include <unistd.h> +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include "../include/Bela.h" + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "h", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, 0) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/basic_libpd/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,403 @@ +/* + * render.cpp + * + * Created on: Oct 24, 2014 + * Author: parallels + */ + +#include <Bela.h> +#include <DigitalChannelManager.h> +#include <cmath> +#include <I2c_Codec.h> +#include <PRU.h> +#include <stdio.h> +#include "z_libpd.h" +#include "s_stuff.h" +#include <UdpServer.h> +#include <Midi.h> +//extern t_sample* sys_soundin; +//extern t_sample* sys_soundout; +// if you are 100% sure of what value was used to compile libpd/puredata, then +// you could #define this instead of getting it at runtime. It has proved to give some 0.3% +// performance boost when it is 8 (thanks to vectorize optimizations I guess). +int gBufLength; + +float* gInBuf; +float* gOutBuf; + +void pdnoteon(int ch, int pitch, int vel) { + printf("noteon: %d %d %d\n", ch, pitch, vel); +} + +void Bela_printHook(const char *recv){ + rt_printf("%s", recv); +} + +void libpdReadFilesLoop(){ + while(!gShouldStop){ + // check for modified sockets/file descriptors + // (libpd would normally do this every block WITHIN the audio thread) + // not sure if this is thread-safe at the moment + libpd_sys_microsleep(0); + usleep(1000); + } +} + +#define PARSE_MIDI +static AuxiliaryTask libpdReadFilesTask; +static Midi midi; +static DigitalChannelManager dcm; +//UdpServer udpServer; + +void sendDigitalMessage(bool state, unsigned int delay, void* receiverName){ + libpd_float((char*)receiverName, (float)state); +// rt_printf("%s: %d\n", (char*)receiverName, state); +} + +#define LIBPD_DIGITAL_OFFSET 11 // digitals are preceded by 2 audio and 8 analogs (even if using a different number of analogs) + +void Bela_messageHook(const char *source, const char *symbol, int argc, t_atom *argv){ + if(strcmp(source, "bela_setDigital") == 0){ + // symbol is the direction, argv[0] is the channel, argv[1] (optional) + // is signal("sig" or "~") or message("message", default) rate + bool isMessageRate = true; // defaults to message rate + bool direction = 0; // initialize it just to avoid the compiler's warning + bool disable = false; + if(strcmp(symbol, "in") == 0){ + direction = INPUT; + } else if(strcmp(symbol, "out") == 0){ + direction = OUTPUT; + } else if(strcmp(symbol, "disable") == 0){ + disable = true; + } else { + return; + } + if(argc == 0){ + return; + } else if (libpd_is_float(&argv[0]) == false){ + return; + } + int channel = libpd_get_float(&argv[0]) - LIBPD_DIGITAL_OFFSET; + if(disable == true){ + dcm.unmanage(channel); + return; + } + if(argc >= 2){ + t_atom* a = &argv[1]; + if(libpd_is_symbol(a)){ + char *s = libpd_get_symbol(a); + if(strcmp(s, "~") == 0 || strncmp(s, "sig", 3) == 0){ + isMessageRate = false; + } + } + } + dcm.manage(channel, direction, isMessageRate); + } +} + +void Bela_floatHook(const char *source, float value){ + // let's make this as optimized as possible for built-in digital Out parsing + // the built-in digital receivers are of the form "bela_digitalOutXX" where XX is between 11 and 26 + static int prefixLength = 15; // strlen("bela_digitalOut") + if(strncmp(source, "bela_digitalOut", prefixLength)==0){ + if(source[prefixLength] != 0){ //the two ifs are used instead of if(strlen(source) >= prefixLength+2) + if(source[prefixLength + 1] != 0){ + // quickly convert the suffix to integer, assuming they are numbers, avoiding to call atoi + int receiver = ((source[prefixLength] - 48) * 10); + receiver += (source[prefixLength+1] - 48); + unsigned int channel = receiver - 11; // go back to the actual Bela digital channel number + if(channel >= 0 && channel < 16){ //16 is the hardcoded value for the number of digital channels + dcm.setValue(channel, value); + } + } + } + } +} + +char receiverNames[16][21]={ + {"bela_digitalIn11"},{"bela_digitalIn12"},{"bela_digitalIn13"},{"bela_digitalIn14"},{"bela_digitalIn15"}, + {"bela_digitalIn16"},{"bela_digitalIn17"},{"bela_digitalIn18"},{"bela_digitalIn19"},{"bela_digitalIn20"}, + {"bela_digitalIn21"},{"bela_digitalIn22"},{"bela_digitalIn23"},{"bela_digitalIn24"},{"bela_digitalIn25"}, + {"bela_digitalIn26"} +}; + +static unsigned int analogChannelsInUse; +static unsigned int gLibpdBlockSize; +static unsigned int gChannelsInUse = 26; + +bool setup(BelaContext *context, void *userData) +{ + dcm.setCallback(sendDigitalMessage); + analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels - context->digitalChannels); + if(context->digitalChannels > 0){ + for(unsigned int ch = 0; ch < context->digitalChannels; ++ch){ + dcm.setCallbackArgument(ch, receiverNames[ch]); + } + } + midi.readFrom(0); + midi.writeTo(0); +#ifdef PARSE_MIDI + midi.enableParser(true); +#else + midi.enableParser(false); +#endif /* PARSE_MIDI */ +// gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse); +// udpServer.bindToPort(1234); + + gLibpdBlockSize = libpd_blocksize(); + // check that we are not running with a blocksize smaller than gLibPdBlockSize + // it would still work, but the load would be executed unevenly between calls to render + if(context->audioFrames < gLibpdBlockSize){ + fprintf(stderr, "Error: minimum block size must be %d\n", gLibpdBlockSize); + return false; + } + // set hooks before calling libpd_init + libpd_set_printhook(Bela_printHook); + libpd_set_floathook(Bela_floatHook); + libpd_set_messagehook(Bela_messageHook); + libpd_set_noteonhook(pdnoteon); + //TODO: add hooks for other midi events and generate MIDI output appropriately + libpd_init(); + //TODO: ideally, we would analyse the ASCII of the patch file and find out which in/outs to use + libpd_init_audio(gChannelsInUse, gChannelsInUse, context->audioSampleRate); + gInBuf = libpd_get_sys_soundin(); + gOutBuf = libpd_get_sys_soundout(); + + libpd_start_message(1); // one entry in list + libpd_add_float(1.0f); + libpd_finish_message("pd", "dsp"); + + gBufLength = max(gLibpdBlockSize, context->audioFrames); + + + // bind your receivers here + libpd_bind("bela_digitalOut11"); + libpd_bind("bela_digitalOut12"); + libpd_bind("bela_digitalOut13"); + libpd_bind("bela_digitalOut14"); + libpd_bind("bela_digitalOut15"); + libpd_bind("bela_digitalOut16"); + libpd_bind("bela_digitalOut17"); + libpd_bind("bela_digitalOut18"); + libpd_bind("bela_digitalOut19"); + libpd_bind("bela_digitalOut20"); + libpd_bind("bela_digitalOut21"); + libpd_bind("bela_digitalOut22"); + libpd_bind("bela_digitalOut23"); + libpd_bind("bela_digitalOut24"); + libpd_bind("bela_digitalOut25"); + libpd_bind("bela_digitalOut26"); + libpd_bind("bela_setDigital"); + + char file[] = "_main.pd"; + char folder[] = "./"; + // open patch [; pd open file folder( + libpd_openfile(file, folder); + libpdReadFilesTask = Bela_createAuxiliaryTask(libpdReadFilesLoop, 60, "libpdReadFiles"); + Bela_scheduleAuxiliaryTask(libpdReadFilesTask); + + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + int num; + // the safest thread-safe option to handle MIDI input is to process the MIDI buffer + // from the audio thread. +#ifdef PARSE_MIDI + while((num = midi.getParser()->numAvailableMessages()) > 0){ + static MidiChannelMessage message; + message = midi.getParser()->getNextChannelMessage(); + //message.prettyPrint(); // use this to print beautified message (channel, data bytes) + switch(message.getType()){ + case kmmNoteOn: + { + int noteNumber = message.getDataByte(0); + int velocity = message.getDataByte(1); + int channel = message.getChannel(); + libpd_noteon(channel, noteNumber, velocity); + break; + } + case kmmNoteOff: + { + /* PureData does not seem to handle noteoff messages as per the MIDI specs, + * so that the noteoff velocity is ignored. Here we convert them to noteon + * with a velocity of 0. + */ + int noteNumber = message.getDataByte(0); +// int velocity = message.getDataByte(1); // would be ignored by Pd + int channel = message.getChannel(); + libpd_noteon(channel, noteNumber, 0); + break; + } + case kmmControlChange: + { + int channel = message.getChannel(); + int controller = message.getDataByte(0); + int value = message.getDataByte(1); + libpd_controlchange(channel, controller, value); + break; + } + case kmmProgramChange: + { + int channel = message.getChannel(); + int program = message.getDataByte(0); + libpd_programchange(channel, program); + break; + } + case kmmPolyphonicKeyPressure: + { + int channel = message.getChannel(); + int pitch = message.getDataByte(0); + int value = message.getDataByte(1); + libpd_polyaftertouch(channel, pitch, value); + break; + } + case kmmChannelPressure: + { + int channel = message.getChannel(); + int value = message.getDataByte(0); + libpd_aftertouch(channel, value); + break; + } + case kmmPitchBend: + { + int channel = message.getChannel(); + int value = (message.getDataByte(1) << 7)| message.getDataByte(0); + libpd_pitchbend(channel, value); + break; + } + case kmmNone: + case kmmAny: + break; + } + } +#else + int input; + while((input = midi.getInput()) >= 0){ + libpd_midibyte(0, input); + } +#endif /* PARSE_MIDI */ + + static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize; + + // these are reset at every audio callback. Persistence across audio callbacks + // is handled by the core code. +// setDataOut = 0; +// clearDataOut = 0; + + for(unsigned int tick = 0; tick < numberOfPdBlocksToProcess; ++tick){ + unsigned int audioFrameBase = gLibpdBlockSize * tick; + unsigned int j; + unsigned int k; + float* p0; + float* p1; + for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { + for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { + *p1 = audioRead(context, audioFrameBase + j, k); + } + } + // then analogs + // this loop resamples by ZOH, as needed, using m + if(context->analogChannels == 8 ){ //hold the value for two frames + for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { + for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { + unsigned int analogFrame = (audioFrameBase + j) / 2; + *p1 = analogRead(context, analogFrame, k); + } + } + } else if(context->analogChannels == 4){ //write every frame + for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { + for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { + unsigned int analogFrame = audioFrameBase + j; + *p1 = analogRead(context, analogFrame, k); + } + } + } else if(context->analogChannels == 2){ //drop every other frame + for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { + for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { + unsigned int analogFrame = (audioFrameBase + j) * 2; + *p1 = analogRead(context, analogFrame, k); + } + } + } + + //then digital + // note: in multiple places below we assume that the number of digitals is same as number of audio + // digital in at message-rate + dcm.processInput(&context->digital[audioFrameBase], gLibpdBlockSize); + + // digital in at signal-rate + for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { + unsigned int digitalFrame = audioFrameBase + j; + for (k = 0, p1 = p0 + gLibpdBlockSize * (context->audioChannels + 8); + k < 16; ++k, p1 += gLibpdBlockSize) { + if(dcm.isSignalRate(k) && dcm.isInput(k)){ // only process input channels that are handled at signal rate + *p1 = digitalRead(context, digitalFrame, k); + } + } + } + + libpd_process_sys(); // process the block + + //digital out + // digital out at signal-rate + for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) { + unsigned int digitalFrame = (audioFrameBase + j); + for (k = 0, p1 = p0 + gLibpdBlockSize * (context->audioChannels + 8); + k < context->digitalChannels; k++, p1 += gLibpdBlockSize) { + if(dcm.isSignalRate(k) && dcm.isOutput(k)){ // only process output channels that are handled at signal rate + digitalWriteOnce(context, digitalFrame, k, *p1 > 0.5); + } + } + } + + // digital out at message-rate + dcm.processOutput(&context->digital[audioFrameBase], gLibpdBlockSize); + + //audio + for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { + for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { + audioWrite(context, audioFrameBase + j, k, *p1); + } + } + + //analog + if(context->analogChannels == 8){ + for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j += 2, p0 += 2) { //write every two frames + unsigned int analogFrame = (audioFrameBase + j) / 2; + for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { + analogWriteOnce(context, analogFrame, k, *p1); + } + } + } else if(context->analogChannels == 4){ //write every frame + for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) { + unsigned int analogFrame = (audioFrameBase + j); + for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { + analogWriteOnce(context, analogFrame, k, *p1); + } + } + } else if(context->analogChannels == 2){ //write every frame twice + for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { + for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { + int analogFrame = audioFrameBase * 2 + j * 2; + analogWriteOnce(context, analogFrame, k, *p1); + analogWriteOnce(context, analogFrame + 1, k, *p1); + } + } + } + } +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/basic_libpd/s_stuff.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,411 @@ +/* Copyright (c) 1997-1999 Miller Puckette. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* Audio and MIDI I/O, and other scheduling and system stuff. */ + +/* NOTE: this file describes Pd implementation details which may change +in future releases. The public (stable) API is in m_pd.h. */ + +/* in s_path.c */ + +typedef struct _namelist /* element in a linked list of stored strings */ +{ + struct _namelist *nl_next; /* next in list */ + char *nl_string; /* the string */ +} t_namelist; + +t_namelist *namelist_append(t_namelist *listwas, const char *s, int allowdup); +t_namelist *namelist_append_files(t_namelist *listwas, const char *s); +void namelist_free(t_namelist *listwas); +char *namelist_get(t_namelist *namelist, int n); +void sys_setextrapath(const char *p); +extern int sys_usestdpath; +extern t_namelist *sys_externlist; +extern t_namelist *sys_searchpath; +extern t_namelist *sys_helppath; +int sys_open_absolute(const char *name, const char* ext, + char *dirresult, char **nameresult, unsigned int size, int bin, int *fdp); +int sys_trytoopenone(const char *dir, const char *name, const char* ext, + char *dirresult, char **nameresult, unsigned int size, int bin); +t_symbol *sys_decodedialog(t_symbol *s); + +/* s_file.c */ + +void sys_loadpreferences( void); +void sys_savepreferences( void); +extern int sys_defeatrt; +extern t_symbol *sys_flags; + +/* s_main.c */ +extern int sys_debuglevel; +extern int sys_verbose; +extern int sys_noloadbang; +extern int sys_nogui; +extern char *sys_guicmd; + +EXTERN int sys_nearestfontsize(int fontsize); +EXTERN int sys_hostfontsize(int fontsize); + +extern int sys_defaultfont; +EXTERN t_symbol *sys_libdir; /* library directory for auxilliary files */ +extern t_symbol *sys_guidir; /* directory holding pd_gui, u_pdsend, etc */ + +/* s_loader.c */ + +typedef int (*loader_t)(t_canvas *canvas, char *classname); /* callback type */ +EXTERN int sys_load_lib(t_canvas *canvas, char *filename); +EXTERN void sys_register_loader(loader_t loader); + +/* s_audio.c */ + +#define SENDDACS_NO 0 /* return values for sys_send_dacs() */ +#define SENDDACS_YES 1 +#define SENDDACS_SLEPT 2 + +#define DEFDACBLKSIZE 8 +extern int sys_schedblocksize; /* audio block size for scheduler */ +extern int sys_hipriority; /* real-time flag, true if priority boosted */ +EXTERN t_sample *sys_soundout; +EXTERN t_sample *sys_soundin; +extern int sys_inchannels; +extern int sys_outchannels; +extern int sys_advance_samples; /* scheduler advance in samples */ +extern int sys_blocksize; /* audio I/O block size in sample frames */ +extern t_float sys_dacsr; +extern int sys_schedadvance; +extern int sys_sleepgrain; +EXTERN void sys_set_audio_settings(int naudioindev, int *audioindev, + int nchindev, int *chindev, + int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, + int srate, int advance, int callback, int blocksize); +/* the same as above, but reopens the audio subsystem if needed */ +EXTERN void sys_set_audio_settings_reopen(int naudioindev, int *audioindev, + int nchindev, int *chindev, + int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, + int srate, int advance, int callback, int blocksize); +EXTERN void sys_reopen_audio( void); +EXTERN void sys_close_audio(void); + /* return true if the interface prefers always being open (ala jack) : */ +EXTERN int audio_shouldkeepopen( void); +EXTERN int audio_isopen( void); /* true if audio interface is open */ +EXTERN int sys_audiodevnametonumber(int output, const char *name); +EXTERN void sys_audiodevnumbertoname(int output, int devno, char *name, + int namesize); + +int sys_send_dacs(void); +void sys_reportidle(void); +void sys_set_priority(int higher); +void sys_audiobuf(int nbufs); +void sys_getmeters(t_sample *inmax, t_sample *outmax); +void sys_listdevs(void); +void sys_setblocksize(int n); + +EXTERN void sys_get_audio_devs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, int *cancallback, + int maxndev, int devdescsize); +EXTERN void sys_get_audio_apis(char *buf); + +/* s_midi.c */ +#define MAXMIDIINDEV 16 /* max. number of input ports */ +#define MAXMIDIOUTDEV 16 /* max. number of output ports */ +extern int sys_midiapi; +extern int sys_nmidiin; +extern int sys_nmidiout; +extern int sys_midiindevlist[]; +extern int sys_midioutdevlist[]; + +EXTERN void sys_open_midi(int nmidiin, int *midiinvec, + int nmidiout, int *midioutvec, int enable); + +EXTERN void sys_get_midi_apis(char *buf); +EXTERN void sys_get_midi_devs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, + int maxndev, int devdescsize); +EXTERN void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, + int *pnmidioutdev, int *pmidioutdev); +EXTERN int sys_mididevnametonumber(int output, const char *name); +EXTERN void sys_mididevnumbertoname(int output, int devno, char *name, + int namesize); + +EXTERN void sys_reopen_midi( void); +EXTERN void sys_close_midi( void); +EXTERN void sys_putmidimess(int portno, int a, int b, int c); +EXTERN void sys_putmidibyte(int portno, int a); +EXTERN void sys_poll_midi(void); +EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime); +EXTERN void sys_midibytein(int portno, int byte); + + /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */ +void midi_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int maxndev, int devdescsize); +void sys_do_open_midi(int nmidiindev, int *midiindev, + int nmidioutdev, int *midioutdev); + +#ifdef USEAPI_ALSA +EXTERN void sys_alsa_putmidimess(int portno, int a, int b, int c); +EXTERN void sys_alsa_putmidibyte(int portno, int a); +EXTERN void sys_alsa_poll_midi(void); +EXTERN void sys_alsa_setmiditimediff(double inbuftime, double outbuftime); +EXTERN void sys_alsa_midibytein(int portno, int byte); +EXTERN void sys_alsa_close_midi( void); + + + /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */ +void midi_alsa_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int maxndev, int devdescsize); +void sys_alsa_do_open_midi(int nmidiindev, int *midiindev, + int nmidioutdev, int *midioutdev); +#endif + +/* m_sched.c */ +EXTERN void sys_log_error(int type); +#define ERR_NOTHING 0 +#define ERR_ADCSLEPT 1 +#define ERR_DACSLEPT 2 +#define ERR_RESYNC 3 +#define ERR_DATALATE 4 + +#define SCHED_AUDIO_NONE 0 +#define SCHED_AUDIO_POLL 1 +#define SCHED_AUDIO_CALLBACK 2 +void sched_set_using_audio(int flag); + +/* s_inter.c */ + +EXTERN void sys_microsleep(int microsec); +EXTERN void sys_init_fdpoll(void); + +EXTERN void sys_bail(int exitcode); +EXTERN int sys_pollgui(void); + +EXTERN_STRUCT _socketreceiver; +#define t_socketreceiver struct _socketreceiver + +typedef void (*t_socketnotifier)(void *x, int n); +typedef void (*t_socketreceivefn)(void *x, t_binbuf *b); + +EXTERN t_socketreceiver *socketreceiver_new(void *owner, + t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp); +EXTERN void socketreceiver_read(t_socketreceiver *x, int fd); +EXTERN void sys_sockerror(char *s); +EXTERN void sys_closesocket(int fd); + +typedef void (*t_fdpollfn)(void *ptr, int fd); +EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr); +EXTERN void sys_rmpollfn(int fd); +#if defined(USEAPI_OSS) || defined(USEAPI_ALSA) +void sys_setalarm(int microsec); +#endif + +#define API_NONE 0 +#define API_ALSA 1 +#define API_OSS 2 +#define API_MMIO 3 +#define API_PORTAUDIO 4 +#define API_JACK 5 +#define API_SGI 6 /* gone */ +#define API_AUDIOUNIT 7 +#define API_ESD 8 /* no idea what this was, probably gone now */ +#define API_DUMMY 9 + + /* figure out which API should be the default. The one we judge most + likely to offer a working device takes precedence so that if you + start up Pd for the first time there's a reasonable chance you'll have + sound. (You'd think portaudio would be best but it seems to default + to jack on linux, and and on Windows we only use it for ASIO). + If nobody shows up, define DUMMY and make it the default.*/ +#if defined(USEAPI_MMIO) +# define API_DEFAULT API_MMIO +# define API_DEFSTRING "MMIO" +#elif defined(USEAPI_ALSA) +# define API_DEFAULT API_ALSA +# define API_DEFSTRING "ALSA" +#elif defined(USEAPI_OSS) +# define API_DEFAULT API_OSS +# define API_DEFSTRING "OSS" +#elif defined(USEAPI_AUDIOUNIT) +# define API_DEFAULT API_AUDIOUNIT +# define API_DEFSTRING "AudioUnit" +#elif defined(USEAPI_ESD) +# define API_DEFAULT API_ESD +# define API_DEFSTRING "ESD (?)" +#elif defined(USEAPI_PORTAUDIO) +# define API_DEFAULT API_PORTAUDIO +# define API_DEFSTRING "portaudio" +#elif defined(USEAPI_JACK) +# define API_DEFAULT API_JACK +# define API_DEFSTRING "Jack audio connection kit" +#else +# ifndef USEAPI_DUMMY /* we need at least one so bring in the dummy */ +# define USEAPI_DUMMY +# endif /* USEAPI_DUMMY */ +# define API_DEFAULT API_DUMMY +# define API_DEFSTRING "dummy audio" +#endif + +#define DEFAULTAUDIODEV 0 + +#define MAXAUDIOINDEV 4 +#define MAXAUDIOOUTDEV 4 + +#define DEFMIDIDEV 0 + +#define DEFAULTSRATE 44100 +#ifdef _WIN32 +#define DEFAULTADVANCE 80 +#else +#ifdef __APPLE__ +#define DEFAULTADVANCE 5 /* this is in addition to their own delay */ +#else +#define DEFAULTADVANCE 25 +#endif +#endif + +typedef void (*t_audiocallback)(void); + +int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, + t_sample *soundout, int framesperbuf, int nbuffers, + int indeviceno, int outdeviceno, t_audiocallback callback); +void pa_close_audio(void); +int pa_send_dacs(void); +void sys_reportidle(void); +void pa_listdevs(void); +void pa_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); + +int oss_open_audio(int naudioindev, int *audioindev, int nchindev, + int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, + int *choutdev, int rate, int blocksize); +void oss_close_audio(void); +int oss_send_dacs(void); +void oss_reportidle(void); +void oss_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); + +int alsa_open_audio(int naudioindev, int *audioindev, int nchindev, + int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, + int *choutdev, int rate, int blocksize); +void alsa_close_audio(void); +int alsa_send_dacs(void); +void alsa_reportidle(void); +void alsa_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); + +int jack_open_audio(int wantinchans, int wantoutchans, int srate, + t_audiocallback callback); +void jack_close_audio(void); +int jack_send_dacs(void); +void jack_reportidle(void); +void jack_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); +void jack_listdevs(void); + +int mmio_open_audio(int naudioindev, int *audioindev, + int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, + int nchoutdev, int *choutdev, int rate, int blocksize); +void mmio_close_audio( void); +void mmio_reportidle(void); +int mmio_send_dacs(void); +void mmio_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); + +int audiounit_open_audio(int naudioindev, int *audioindev, int nchindev, + int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, + int *choutdev, int rate); +void audiounit_close_audio(void); +int audiounit_send_dacs(void); +void audiounit_listdevs(void); +void audiounit_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); + +int esd_open_audio(int naudioindev, int *audioindev, int nchindev, + int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, + int *choutdev, int rate); +void esd_close_audio(void); +int esd_send_dacs(void); +void esd_listdevs(void); +void esd_getdevs(char *indevlist, int *nindevs, + char *outdevlist, int *noutdevs, int *canmulti, + int maxndev, int devdescsize); + +int dummy_open_audio(int nin, int nout, int sr); +int dummy_close_audio( void); +int dummy_send_dacs( void); +void dummy_getdevs(char *indevlist, int *nindevs, char *outdevlist, + int *noutdevs, int *canmulti, int maxndev, int devdescsize); +void dummy_listdevs( void); + +void sys_listmididevs(void); +EXTERN void sys_set_midi_api(int whichapi); +EXTERN void sys_set_audio_api(int whichapi); +EXTERN int sys_audioapi; +EXTERN void sys_set_audio_state(int onoff); + +/* API dependent audio flags and settings */ +void oss_set32bit( void); +void linux_alsa_devname(char *devname); + +EXTERN void sys_get_audio_params( + int *pnaudioindev, int *paudioindev, int *chindev, + int *pnaudiooutdev, int *paudiooutdev, int *choutdev, + int *prate, int *padvance, int *callback, int *blocksize); +void sys_save_audio_params( + int naudioindev, int *audioindev, int *chindev, + int naudiooutdev, int *audiooutdev, int *choutdev, + int rate, int advance, int callback, int blocksize); + +/* s_file.c */ + +typedef void (*t_printhook)(const char *s); +extern t_printhook sys_printhook; /* set this to override printing */ +extern int sys_printtostderr; + +/* jsarlo { */ + +EXTERN double sys_time; +EXTERN double sys_time_per_dsp_tick; +EXTERN int sys_externalschedlib; + +EXTERN t_sample* get_sys_soundout(void ) ; +EXTERN t_sample* get_sys_soundin(void ) ; +EXTERN int* get_sys_main_advance(void ) ; +EXTERN double* get_sys_time_per_dsp_tick(void ) ; +EXTERN int* get_sys_schedblocksize(void ) ; +EXTERN double* get_sys_time(void ) ; +EXTERN t_float* get_sys_dacsr(void ) ; +EXTERN int* get_sys_sleepgrain(void ) ; +EXTERN int* get_sys_schedadvance(void ) ; + +EXTERN void sys_clearhist(void ); +EXTERN void sys_initmidiqueue(void ); +EXTERN int sys_addhist(int phase); +EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime); +EXTERN void sched_tick( void); +EXTERN void sys_pollmidiqueue(void ); +EXTERN int sys_pollgui(void ); +EXTERN void sys_setchsr(int chin, int chout, int sr); + +EXTERN void inmidi_realtimein(int portno, int cmd); +EXTERN void inmidi_byte(int portno, int byte); +EXTERN void inmidi_sysex(int portno, int byte); +EXTERN void inmidi_noteon(int portno, int channel, int pitch, int velo); +EXTERN void inmidi_controlchange(int portno, + int channel, + int ctlnumber, + int value); +EXTERN void inmidi_programchange(int portno, int channel, int value); +EXTERN void inmidi_pitchbend(int portno, int channel, int value); +EXTERN void inmidi_aftertouch(int portno, int channel, int value); +EXTERN void inmidi_polyaftertouch(int portno, + int channel, + int pitch, + int value); +/* } jsarlo */ +extern t_widgetbehavior text_widgetbehavior;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/basic_libpd/z_libpd.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2010 Peter Brinkmann (peter.brinkmann@gmail.com) + * + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. + * + * See https://github.com/libpd/libpd/wiki for documentation + * + */ + +#ifndef __Z_LIBPD_H__ +#define __Z_LIBPD_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "m_pd.h" + +EXTERN int libpd_init(void); +EXTERN void libpd_clear_search_path(void); +EXTERN void libpd_add_to_search_path(const char *sym); + +EXTERN void *libpd_openfile(const char *basename, const char *dirname); +EXTERN void libpd_closefile(void *p); +EXTERN int libpd_getdollarzero(void *p); + +EXTERN int libpd_blocksize(void); +EXTERN int libpd_init_audio(int inChans, int outChans, int sampleRate); +EXTERN int libpd_process_raw(const float *inBuffer, float *outBuffer); +EXTERN t_sample* libpd_get_sys_soundin(); +EXTERN t_sample* libpd_get_sys_soundout(); +EXTERN int libpd_process_sys(); +EXTERN int libpd_process_short(const int ticks, + const short *inBuffer, short *outBuffer); +EXTERN int libpd_process_float(int ticks, + const float *inBuffer, float *outBuffer); +EXTERN int libpd_process_double(int ticks, + const double *inBuffer, double *outBuffer); + +EXTERN int libpd_arraysize(const char *name); +// The parameters of the next two functions are inspired by memcpy. +EXTERN int libpd_read_array(float *dest, const char *src, int offset, int n); +EXTERN int libpd_write_array(const char *dest, int offset, float *src, int n); + +EXTERN int libpd_bang(const char *recv); +EXTERN int libpd_float(const char *recv, float x); +EXTERN int libpd_symbol(const char *recv, const char *sym); + +EXTERN void libpd_set_float(t_atom *v, float x); +EXTERN void libpd_set_symbol(t_atom *v, const char *sym); +EXTERN int libpd_list(const char *recv, int argc, t_atom *argv); +EXTERN int libpd_message(const char *recv, const char *msg, int argc, t_atom *argv); + +EXTERN int libpd_start_message(int max_length); +EXTERN void libpd_add_float(float x); +EXTERN void libpd_add_symbol(const char *sym); +EXTERN int libpd_finish_list(const char *recv); +EXTERN int libpd_finish_message(const char *recv, const char *msg); + +EXTERN int libpd_exists(const char *sym); +EXTERN void *libpd_bind(const char *sym); +EXTERN void libpd_unbind(void *p); + +EXTERN int libpd_is_float(t_atom *a); +EXTERN int libpd_is_symbol(t_atom *a); +EXTERN float libpd_get_float(t_atom *a); +EXTERN char *libpd_get_symbol(t_atom *a); +EXTERN t_atom *libpd_next_atom(t_atom *a); + +typedef void (*t_libpd_printhook)(const char *recv); +typedef void (*t_libpd_banghook)(const char *recv); +typedef void (*t_libpd_floathook)(const char *recv, float x); +typedef void (*t_libpd_symbolhook)(const char *recv, const char *sym); +typedef void (*t_libpd_listhook)(const char *recv, int argc, t_atom *argv); +typedef void (*t_libpd_messagehook)(const char *recv, const char *msg, + int argc, t_atom *argv); + +EXTERN void libpd_set_printhook(const t_libpd_printhook hook); +EXTERN void libpd_set_banghook(const t_libpd_banghook hook); +EXTERN void libpd_set_floathook(const t_libpd_floathook hook); +EXTERN void libpd_set_symbolhook(const t_libpd_symbolhook hook); +EXTERN void libpd_set_listhook(const t_libpd_listhook hook); +EXTERN void libpd_set_messagehook(const t_libpd_messagehook hook); + +EXTERN int libpd_noteon(int channel, int pitch, int velocity); +EXTERN int libpd_controlchange(int channel, int controller, int value); +EXTERN int libpd_programchange(int channel, int value); +EXTERN int libpd_pitchbend(int channel, int value); +EXTERN int libpd_aftertouch(int channel, int value); +EXTERN int libpd_polyaftertouch(int channel, int pitch, int value); +EXTERN int libpd_midibyte(int port, int byte); +EXTERN int libpd_sysex(int port, int byte); +EXTERN int libpd_sysrealtime(int port, int byte); + +typedef void (*t_libpd_noteonhook)(int channel, int pitch, int velocity); +typedef void (*t_libpd_controlchangehook)(int channel, + int controller, int value); +typedef void (*t_libpd_programchangehook)(int channel, int value); +typedef void (*t_libpd_pitchbendhook)(int channel, int value); +typedef void (*t_libpd_aftertouchhook)(int channel, int value); +typedef void (*t_libpd_polyaftertouchhook)(int channel, int pitch, int value); +typedef void (*t_libpd_midibytehook)(int port, int byte); + +EXTERN void libpd_set_noteonhook(const t_libpd_noteonhook hook); +EXTERN void libpd_set_controlchangehook(const t_libpd_controlchangehook hook); +EXTERN void libpd_set_programchangehook(const t_libpd_programchangehook hook); +EXTERN void libpd_set_pitchbendhook(const t_libpd_pitchbendhook hook); +EXTERN void libpd_set_aftertouchhook(const t_libpd_aftertouchhook hook); +EXTERN void libpd_set_polyaftertouchhook(const t_libpd_polyaftertouchhook hook); +EXTERN void libpd_set_midibytehook(const t_libpd_midibytehook hook); +EXTERN void libpd_sys_microsleep(int sleep); + +#ifdef __cplusplus +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/circularBuffer/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,79 @@ +#N canvas 436 490 738 494 10; +#X obj 135 167 loadbang; +#X msg 135 212 1; +#X obj 183 234 / 44.1; +#X obj 135 253 metro; +#X obj 135 286 f; +#X obj 160 286 + 64; +#X obj 160 308 % 65536, f 8; +#X msg 160 329 start \$1; +#X obj 160 351 tabwrite~ circbuf; +#X obj 363 303 - 32768; +#X obj 363 325 + 65536; +#X obj 363 347 % 65536; +#X obj 342 371 +~ 0; +#X msg 381 236 0; +#X obj 342 258 phasor~; +#X obj 342 392 tabread4~ circbuf; +#X obj 341 415 dac~; +#N canvas 422 781 312 126 buf 0; +#N canvas 0 22 450 278 (subpatch) 0; +#X array circbuf 65536 float 2; +#X coords 0 1 65535 -1 256 64 1 0 0; +#X restore 23 28 graph; +#X restore 129 441 pd buf; +#X obj 32 101 osc~ 440; +#X obj 342 213 samplerate~; +#X obj 134 189 t b b b b; +#X text 30 82 audio input; +#X text 219 310 write pointer; +#X text 412 349 read pointer; +#X obj 342 282 *~ 16; +#X obj 342 236 / 16; +#X obj 183 214 f 16; +#X obj 363 189 r \$0-blocksize; +#X obj 204 186 r \$0-blocksize; +#X obj 394 259 r \$0-blocksize; +#X obj 390 123 s \$0-blocksize; +#X text 34 13 VIRTUAL CIRCULAR BUFFER; +#X text 34 23 =======================; +#X obj 390 55 loadbang; +#X msg 390 77 16; +#X text 517 454 ---------------------------------; +#X text 517 444 @krighxz / BELA / heavy / 12/2015; +#X text 541 463 beaglert.cc / enzienaudio.com; +#X text 426 78 << replace with target blocksize; +#X text 446 90 BELA default: 16; +#X text 446 102 PD default: 64; +#X connect 0 0 20 0; +#X connect 1 0 3 0; +#X connect 2 0 3 1; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 5 0 6 0; +#X connect 5 0 9 0; +#X connect 6 0 7 0; +#X connect 6 0 4 1; +#X connect 7 0 8 0; +#X connect 9 0 10 0; +#X connect 10 0 11 0; +#X connect 11 0 12 1; +#X connect 12 0 15 0; +#X connect 13 0 14 1; +#X connect 14 0 24 0; +#X connect 15 0 16 0; +#X connect 15 0 16 1; +#X connect 18 0 8 0; +#X connect 19 0 25 0; +#X connect 20 0 1 0; +#X connect 20 1 26 0; +#X connect 20 2 13 0; +#X connect 20 3 19 0; +#X connect 24 0 12 0; +#X connect 25 0 14 0; +#X connect 26 0 2 0; +#X connect 27 0 25 1; +#X connect 28 0 26 1; +#X connect 29 0 24 1; +#X connect 33 0 34 0; +#X connect 34 0 30 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/digital/bela_digital-help.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,97 @@ +#N canvas 121 46 877 628 10; +#X obj 64 94 r bela_digitalIn11; +#X obj 219 94 r bela_digitalIn12; +#X obj 386 107 adc~ 13 14; +#X text 49 64 Digital in \, message rate; +#X text 214 69 Digital in \, message rate; +#X text 394 85 Digital ins \, signal rate; +#X obj 32 283 s bela_digitalOut15; +#X text 13 309 Digital out \, message rate; +#X obj 396 593 s bela_setDigital; +#X obj 396 533 loadbang; +#X msg 431 401 in 11; +#X text 524 390 First argument is the pin direction Second argument +is the pin number Third argument is the rate \, can be "~" or "sig" +for signal-rate or "message" for message-rate. Defaults to message-rate. +; +#X msg 431 458 in 13 ~; +#X msg 432 429 in 12 message; +#X msg 517 506 disable 17; +#X obj 386 139 snapshot~; +#X obj 500 134 snapshot~; +#X obj 529 56 loadbang; +#X obj 384 181 print digitalIn13; +#X obj 500 183 print digitalIn14; +#X obj 497 105 metro 200; +#X text 525 474 To stop using a pin (e.g.: to save CPU) \, send a disable +message containing the pin number; +#X obj 224 280 dac~ 16; +#X obj 22 232 metro 500; +#X obj 32 257 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 224 253 phasor~ 300; +#X text 160 234 Nice \, anti-aliased square wave; +#X obj 22 207 loadbang; +#X text 15 181 Blink that LED!; +#X obj 411 306 dac~ 17; +#X obj 405 248 osc~ 300; +#X obj 470 248 phasor~ 169; +#X obj 457 278 -~ 0.5; +#X text 403 210 Sum signals together for unpredictable effects; +#X obj 612 303 dac~ 18; +#X text 198 305 Digital out \, signal rate; +#X text 378 325 Digital out \, signal rate; +#X text 588 325 Digital out \, signal rate; +#X obj 608 222 adc~; +#X obj 612 249 *~ 0.5; +#X obj 612 276 +~ 0.5; +#X text 585 203 The ultimate bit-crusher; +#X msg 426 555 in 11 \, in 12 \, in 13 ~ \, in 14 ~ \, out 15 \, out +16 ~ \, out 17 ~ \, out 18 ~; +#X text 23 377 Each digital channel can be configured as either an +input or an output. Send messages to bela_setDigital to configure the +digitalPins (needed before using them). Pins settings can be modified +at will during execution. Message-rate input pins receive messages +only when the input changes. Message-rate output pins will write to +the output the most recent value you send them. Signal-rate inputs +and outputs are handled as regular audio channels. Outputs are thresholded +to 0.5 before being written to the actual output. Note that each pin +that is managed adds to the CPU usage \, so only activate the pins +you actually need.; +#X text 34 19 Digital channels are numbered 11 to 26 \, which corresponds +to Bela's 0 to 15 digital channels. They can be set to respond at message +rate or at signal rate; +#X obj 415 271 osc~ 1; +#X obj 385 157 change; +#X obj 500 158 change; +#X obj 64 116 print digitalIn11; +#X obj 219 117 print digitalIn12; +#X connect 0 0 48 0; +#X connect 1 0 49 0; +#X connect 2 0 15 0; +#X connect 2 1 16 0; +#X connect 9 0 42 0; +#X connect 10 0 8 0; +#X connect 12 0 8 0; +#X connect 13 0 8 0; +#X connect 14 0 8 0; +#X connect 15 0 46 0; +#X connect 16 0 47 0; +#X connect 17 0 20 0; +#X connect 20 0 16 0; +#X connect 20 0 15 0; +#X connect 23 0 24 0; +#X connect 24 0 6 0; +#X connect 25 0 22 0; +#X connect 27 0 23 0; +#X connect 30 0 29 0; +#X connect 31 0 32 0; +#X connect 32 0 29 0; +#X connect 38 0 39 0; +#X connect 38 1 39 0; +#X connect 39 0 40 0; +#X connect 40 0 34 0; +#X connect 42 0 8 0; +#X connect 45 0 29 0; +#X connect 46 0 18 0; +#X connect 47 0 19 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/digital/digital_example.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,89 @@ +#N canvas 279 78 857 690 10; +#X obj 18 477 osc~ 200; +#X obj 57 522 *~; +#X obj 112 405 line~ 1; +#X msg 116 372 1 \, 0 200; +#X obj 205 472 line~ 1; +#X msg 209 439 1 \, 0 200; +#X obj 210 405 select 1; +#X obj 140 531 *~; +#X obj 484 601 s bela_setDigital; +#X obj 484 532 loadbang; +#X msg 65 445 0; +#X obj 116 332 r bela_digitalIn12; +#X obj 422 217 r bela_digitalIn14; +#X obj 422 243 s bela_digitalOut13; +#X obj 285 218 r bela_digitalIn12; +#X obj 285 243 s bela_digitalOut11; +#X obj 374 339 timer; +#X msg 404 304 bang; +#X msg 368 304 bang; +#X obj 555 184 metro 1000; +#X obj 575 304 s bela_digitalOut15; +#X obj 374 366 print sourceto12; +#X obj 488 351 timer; +#X msg 518 316 bang; +#X msg 482 316 bang; +#X obj 487 380 print sourceto14; +#X obj 663 15 r bela_digitalIn16; +#X msg 553 265 1; +#X obj 577 214 delay 500; +#X obj 480 275 select 1; +#X obj 346 268 select 1; +#X msg 584 281 0; +#X obj 634 251 select 1 0; +#X obj 80 622 dac~ 3 4; +#X obj 65 566 expr~ $v1*0.5 + 0.5; +#X obj 138 588 expr~ $v1*0.5 + 0.5; +#X obj 65 202 dac~ 11; +#X obj 114 83 osc~ 300; +#X obj 176 179 dac~ 1 3; +#X obj 34 136 adc~ 17; +#X obj 423 504 delay 3000; +#X msg 388 552 disable 12; +#X msg 484 552 out 11 ~ \, out 13 \, in 14 \, out 15 \, in 16 \, in +17 ~; +#X connect 0 0 1 0; +#X connect 0 0 7 0; +#X connect 1 0 34 0; +#X connect 2 0 1 1; +#X connect 3 0 2 0; +#X connect 4 0 7 1; +#X connect 5 0 4 0; +#X connect 6 0 5 0; +#X connect 6 0 10 0; +#X connect 7 0 35 0; +#X connect 9 0 42 0; +#X connect 9 0 40 0; +#X connect 10 0 0 1; +#X connect 11 0 3 0; +#X connect 12 0 13 0; +#X connect 12 0 29 0; +#X connect 14 0 15 0; +#X connect 14 0 30 0; +#X connect 16 0 21 0; +#X connect 17 0 16 1; +#X connect 18 0 16 0; +#X connect 19 0 27 0; +#X connect 19 0 28 0; +#X connect 22 0 25 0; +#X connect 23 0 22 1; +#X connect 24 0 22 0; +#X connect 26 0 32 0; +#X connect 27 0 20 0; +#X connect 27 0 24 0; +#X connect 27 0 18 0; +#X connect 28 0 31 0; +#X connect 29 0 23 0; +#X connect 30 0 17 0; +#X connect 31 0 20 0; +#X connect 32 0 27 0; +#X connect 32 1 31 0; +#X connect 34 0 33 0; +#X connect 35 0 33 1; +#X connect 37 0 38 0; +#X connect 37 0 38 1; +#X connect 39 0 36 0; +#X connect 40 0 41 0; +#X connect 41 0 8 0; +#X connect 42 0 8 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/envelopeTrigger/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,196 @@ +#N canvas 646 209 359 287 10; +#X obj 28 207 dac~; +#N canvas 324 380 556 621 env 0; +#N canvas 886 1001 131 207 >~ 0; +#X obj 19 -37 -~; +#X obj 19 -58 min~; +#X obj 19 26 *~ 1e+37; +#X obj 19 5 +~ 1e-37; +#X obj 19 -16 clip~ -1e-37 0; +#X obj 19 -83 inlet~; +#X obj 62 -83 inlet~; +#X obj 19 48 outlet~; +#X connect 0 0 4 0; +#X connect 1 0 0 0; +#X connect 2 0 7 0; +#X connect 3 0 2 0; +#X connect 4 0 3 0; +#X connect 5 0 1 0; +#X connect 6 0 0 1; +#X connect 6 0 1 1; +#X restore 199 106 pd >~; +#X obj 23 173 /~ 44100; +#X obj 68 153 samplerate~; +#X obj 68 133 loadbang; +#X obj 199 128 biquad~ 0 0 -1 1 0; +#X obj 23 209 rpole~; +#X obj 23 153 sig~ 1; +#X obj 226 171 sig~ 0.5; +#N canvas 0 22 110 231 <~ 0; +#X obj 11 -41 -~; +#X obj 11 29 +~ 1e-37; +#X obj 11 8 clip~ -1e-37 0; +#X obj 11 -86 inlet~; +#X obj 55 -85 inlet~; +#X obj 11 -62 max~; +#X obj 11 -17 *~ -1; +#X obj 11 81 outlet~; +#X obj 11 50 *~ 1e+37; +#X connect 0 0 6 0; +#X connect 1 0 8 0; +#X connect 2 0 1 0; +#X connect 3 0 5 0; +#X connect 4 0 0 1; +#X connect 4 0 5 1; +#X connect 5 0 0 0; +#X connect 6 0 2 0; +#X connect 8 0 7 0; +#X restore 199 192 pd <~; +#X text 237 193 (x != x); +#X obj 23 467 *~; +#X obj 199 150 *~ -1; +#X obj 23 331 *~ 512; +#X obj 23 229 clip~ 0 1; +#X obj 23 352 tabread4~ env1; +#X obj 23 310 *~; +#X obj 199 64 abs~; +#X obj 199 43 hip~ 1; +#X obj 199 22 inlet~ excitationSignal; +#X obj 218 269 sig~ 1; +#X obj 218 292 /~; +#X obj 226 86 inlet~ threshold; +#X obj 262 229 inlet~ envDuration; +#X obj 38 445 osc~ 220; +#X obj 38 425 +~ 50; +#X obj 38 385 *~; +#X obj 38 405 *~ 1000; +#X obj 262 269 clip~ 1e-05 100000; +#X obj 23 487 outlet~; +#N canvas 0 22 450 278 (subpatch) 0; +#X array env1 512 float 3; +#A 0 0 0.0625 0.0883883 0.108253 0.125 0.139754 0.153093 0.165359 0.176777 +0.1875 0.197642 0.207289 0.216506 0.225347 0.233854 0.242061 0.25 0.257694 +0.265165 0.272431 0.279509 0.286411 0.293151 0.299739 0.306186 0.3125 +0.318689 0.32476 0.330719 0.336573 0.342327 0.347985 0.353553 0.359035 +0.364434 0.369755 0.375 0.380173 0.385276 0.390312 0.395285 0.400195 +0.405046 0.40984 0.414578 0.419263 0.423896 0.428478 0.433013 0.4375 +0.441942 0.446339 0.450694 0.455007 0.459279 0.463512 0.467707 0.471865 +0.475986 0.480072 0.484123 0.488141 0.492125 0.496078 0.5 0.503891 +0.507752 0.511585 0.515388 0.519164 0.522913 0.526634 0.53033 0.534 +0.537645 0.541266 0.544862 0.548435 0.551985 0.555512 0.559017 0.5625 +0.565962 0.569402 0.572822 0.576222 0.579601 0.582961 0.586302 0.589624 +0.592927 0.596212 0.599479 0.602728 0.60596 0.609175 0.612372 0.615554 +0.618718 0.621867 0.625 0.628117 0.631219 0.634306 0.637377 0.640434 +0.643477 0.646505 0.649519 0.652519 0.655506 0.658478 0.661438 0.664384 +0.667317 0.670238 0.673146 0.676041 0.678924 0.681795 0.684653 0.6875 +0.690335 0.693159 0.695971 0.698771 0.701561 0.704339 0.707107 0.709864 +0.71261 0.715345 0.71807 0.720785 0.72349 0.726184 0.728869 0.731544 +0.734209 0.736864 0.73951 0.742146 0.744773 0.747391 0.75 0.7526 0.75519 +0.757772 0.760345 0.76291 0.765466 0.768013 0.770552 0.773082 0.775605 +0.778119 0.780625 0.783123 0.785613 0.788095 0.790569 0.793036 0.795495 +0.797947 0.800391 0.802827 0.805256 0.807678 0.810093 0.8125 0.8149 +0.817294 0.81968 0.822059 0.824432 0.826797 0.829156 0.831508 0.833854 +0.836193 0.838525 0.840851 0.843171 0.845484 0.847791 0.850092 0.852386 +0.854675 0.856957 0.859233 0.861503 0.863767 0.866025 0.868278 0.870524 +0.872765 0.875 0.877229 0.879453 0.881671 0.883883 0.88609 0.888292 +0.890488 0.892679 0.894864 0.897044 0.899218 0.901388 0.903552 0.905711 +0.907865 0.910014 0.912157 0.914296 0.91643 0.918559 0.920682 0.922801 +0.924916 0.927025 0.929129 0.931229 0.933324 0.935414 0.9375 0.939581 +0.941657 0.943729 0.945797 0.947859 0.949918 0.951972 0.954021 0.956066 +0.958107 0.960143 0.962175 0.964203 0.966227 0.968246 0.970261 0.972272 +0.974279 0.976281 0.97828 0.980274 0.982265 0.984251 0.986233 0.988212 +0.990186 0.992157 0.994123 0.996086 0.998045 1 0.992172 0.984375 0.976609 +0.968874 0.961169 0.953495 0.945852 0.938239 0.930657 0.923106 0.915586 +0.908097 0.900638 0.89321 0.885813 0.878447 0.871111 0.863806 0.856532 +0.849289 0.842076 0.834894 0.827743 0.820623 0.813533 0.806474 0.799446 +0.792449 0.785483 0.778547 0.771642 0.764767 0.757924 0.751111 0.744329 +0.737578 0.730857 0.724168 0.717509 0.71088 0.704283 0.697716 0.69118 +0.684675 0.678201 0.671757 0.665344 0.658962 0.652611 0.64629 0.64 +0.633741 0.627513 0.621315 0.615148 0.609012 0.602907 0.596832 0.590788 +0.584775 0.578793 0.572841 0.56692 0.56103 0.555171 0.549343 0.543545 +0.537778 0.532041 0.526336 0.520661 0.515017 0.509404 0.503822 0.49827 +0.492749 0.487259 0.481799 0.476371 0.470973 0.465605 0.460269 0.454963 +0.449689 0.444444 0.439231 0.434048 0.428897 0.423775 0.418685 0.413625 +0.408597 0.403599 0.398631 0.393695 0.388789 0.383914 0.37907 0.374256 +0.369473 0.364721 0.36 0.355309 0.35065 0.346021 0.341423 0.336855 +0.332318 0.327812 0.323337 0.318893 0.314479 0.310096 0.305744 0.301423 +0.297132 0.292872 0.288643 0.284444 0.280277 0.27614 0.272034 0.267958 +0.263914 0.2599 0.255917 0.251965 0.248043 0.244152 0.240292 0.236463 +0.232664 0.228897 0.22516 0.221453 0.217778 0.214133 0.210519 0.206936 +0.203383 0.199862 0.196371 0.19291 0.189481 0.186082 0.182714 0.179377 +0.176071 0.172795 0.16955 0.166336 0.163153 0.16 0.156878 0.153787 +0.150727 0.147697 0.144698 0.14173 0.138793 0.135886 0.13301 0.130165 +0.127351 0.124567 0.121815 0.119093 0.116401 0.113741 0.111111 0.108512 +0.105944 0.103406 0.1009 0.0984237 0.0959785 0.093564 0.0911803 0.0888274 +0.0865052 0.0842138 0.0819531 0.0797232 0.077524 0.0753556 0.073218 +0.0711111 0.069035 0.0669896 0.064975 0.0629911 0.0610381 0.0591157 +0.0572241 0.0553633 0.0535332 0.0517339 0.0499654 0.0482276 0.0465206 +0.0448443 0.0431988 0.041584 0.04 0.0384467 0.0369243 0.0354325 0.0339715 +0.0325413 0.0311419 0.0297732 0.0284352 0.027128 0.0258516 0.0246059 +0.023391 0.0222068 0.0210534 0.0199308 0.0188389 0.0177778 0.0167474 +0.0157478 0.0147789 0.0138408 0.0129335 0.0120569 0.0112111 0.010396 +0.00961169 0.00885813 0.00813533 0.00744329 0.00678201 0.00615148 0.00555171 +0.0049827 0.00444444 0.00393695 0.00346021 0.00301423 0.002599 0.00221453 +0.00186082 0.00153787 0.00124567 0.000984237 0.000753556 0.000553633 +0.000384467 0.000246059 0.000138408 6.15148e-05 1.53787e-05 0; +#X coords 0 1 512 0 512 64 1 0 0; +#X restore 24 536 graph; +#X text 244 55 centre signal around zero and take abs value; +#X text 243 107 if greater than threshold output 1; +#X text 313 129 differentiator; +#X text 238 150 (generates impulse on positive trigger (0->1); +#X text 67 210 signal-rate counter; +#X text 296 193 -> resets counter by briefly setting; +#X text 314 204 rpole~ coeff to 0; +#X text 96 416 kickdrum 101 :P; +#X text 400 514 pre-generated envelope; +#X obj 262 249 *~; +#X text 127 352 << use envelope value for volume and frequency; +#X connect 0 0 4 0; +#X connect 1 0 5 0; +#X connect 2 0 1 1; +#X connect 3 0 2 0; +#X connect 4 0 11 0; +#X connect 5 0 13 0; +#X connect 6 0 1 0; +#X connect 7 0 8 1; +#X connect 8 0 5 1; +#X connect 10 0 28 0; +#X connect 11 0 8 0; +#X connect 12 0 14 0; +#X connect 13 0 15 0; +#X connect 14 0 10 0; +#X connect 14 0 25 0; +#X connect 14 0 25 1; +#X connect 15 0 12 0; +#X connect 16 0 0 0; +#X connect 17 0 16 0; +#X connect 18 0 17 0; +#X connect 19 0 20 0; +#X connect 20 0 15 1; +#X connect 21 0 0 1; +#X connect 22 0 39 0; +#X connect 22 0 39 1; +#X connect 23 0 10 1; +#X connect 24 0 23 0; +#X connect 25 0 26 0; +#X connect 26 0 24 0; +#X connect 27 0 20 1; +#X connect 39 0 27 0; +#X restore 28 174 pd env; +#X obj 79 110 adc~ 9; +#X obj 129 130 adc~ 10; +#X text 72 90 piezo input for excitation; +#X text 123 110 fader 1 sets threshold; +#X text 183 130 fader 2 sets duration; +#X text 29 17 SAMPLE-ACCURATE ENVELOPE TRIGGER; +#X text 29 27 ================================; +#X obj 28 90 adc~ 8; +#X text 141 236 ---------------------------------; +#X text 141 226 @krighxz / BELA / heavy / 12/2015; +#X text 165 245 beaglert.cc / enzienaudio.com; +#X connect 1 0 0 0; +#X connect 1 0 0 1; +#X connect 2 0 1 1; +#X connect 3 0 1 2; +#X connect 9 0 1 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/hello-midi/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,81 @@ +#N canvas 85 58 1280 685 10; +#X obj 19 396 dac~ 1 2; +#X text 39 1 Hello world!; +#X text 37 11 ============; +#X obj 31 353 *~ 0.1; +#X text 202 448 ---------------------------------; +#X text 202 438 @krighxz / BELA / heavy / 12/2015; +#X text 226 457 beaglert.cc / enzienaudio.com; +#X obj 39 132 mtof; +#X floatatom 79 59 5 0 0 0 - - -, f 5; +#X floatatom 122 59 5 0 0 0 - - -, f 5; +#X floatatom 41 63 5 0 0 0 - - -, f 5; +#X obj 26 170 phasor~ 440; +#X text 100 363 (the harsh sound of success); +#X obj 260 83 * 20; +#X obj 261 112 + 200; +#X obj 132 85 loadbang; +#X msg 131 111 1000; +#X obj 125 166 sig~; +#X text 673 121 [pgmin]; +#X obj 218 178 * 10; +#X obj 30 250 hip~; +#X obj 26 275 hip~; +#X obj 20 302 hip~; +#X obj 19 323 hip~; +#X obj 87 192 lop~ 4; +#X obj 152 256 line; +#X obj 200 200 + 50; +#X msg 170 227 \$1 200; +#X msg 93 114 0; +#X msg 185 112 0; +#X obj 29 224 vcf~ 4; +#X obj 70 333 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 42 92 mono; +#X obj 40 28 bela_notein 0; +#X obj 260 60 bela_ctlin 5 0; +#X obj 220 151 bela_ctlin 6 0; +#X text 537 58 [ctlin]; +#X text 332 27 [notein]; +#X text 140 29 <== the bela equivalent of ==>; +#X text 349 59 <== the bela equivalent of ==>; +#X text 483 121 <== the bela equivalent of ==>; +#X obj 405 175 print pgmin; +#X obj 408 121 bela_pgmin 0; +#X connect 3 0 0 1; +#X connect 3 0 0 0; +#X connect 7 0 11 0; +#X connect 8 0 32 1; +#X connect 10 0 32 0; +#X connect 11 0 30 0; +#X connect 13 0 14 0; +#X connect 14 0 17 0; +#X connect 15 0 16 0; +#X connect 15 0 29 0; +#X connect 15 0 28 0; +#X connect 16 0 17 0; +#X connect 17 0 24 0; +#X connect 19 0 26 0; +#X connect 20 0 21 0; +#X connect 21 0 22 0; +#X connect 22 0 23 0; +#X connect 23 0 3 0; +#X connect 24 0 30 1; +#X connect 25 0 20 1; +#X connect 25 0 21 1; +#X connect 25 0 22 1; +#X connect 25 0 23 1; +#X connect 26 0 27 0; +#X connect 27 0 25 0; +#X connect 29 0 19 0; +#X connect 30 0 20 0; +#X connect 31 0 3 1; +#X connect 32 0 7 0; +#X connect 32 1 31 0; +#X connect 33 0 10 0; +#X connect 33 1 8 0; +#X connect 33 2 9 0; +#X connect 34 0 13 0; +#X connect 35 0 19 0; +#X connect 42 0 41 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/hello-midi/countTo.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,33 @@ +#N canvas 584 255 450 300 10; +#X obj 65 196 outlet; +#X obj 98 8 inlet; +#X text 189 49 counts from 0 to the given number -1; +#X text 214 95 inlet:N; +#X text 212 112 outlet: 0 \, 1 \, 2 \, ... \, N-1; +#X obj 143 61 f; +#X obj 100 138 spigot; +#X obj 129 89 <; +#X obj 129 113 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 95 28 t b f b; +#X obj 92 74 + 1; +#X obj 43 73 f; +#X obj 63 104 t b f f f; +#X msg 92 53 0; +#X obj 16 144 delay 0; +#X connect 1 0 9 0; +#X connect 5 0 7 1; +#X connect 6 0 11 0; +#X connect 7 0 8 0; +#X connect 8 0 6 1; +#X connect 9 0 11 0; +#X connect 9 1 5 0; +#X connect 9 1 13 0; +#X connect 10 0 11 1; +#X connect 11 0 12 0; +#X connect 12 0 14 0; +#X connect 12 1 0 0; +#X connect 12 2 7 0; +#X connect 12 3 10 0; +#X connect 13 0 11 1; +#X connect 14 0 6 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/hello-midi/maxArray.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,67 @@ +#N canvas 464 23 1002 583 10; +#X obj 224 202 max; +#X obj 265 200 f; +#X obj 223 229 change; +#X obj 223 251 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 223 271 f; +#X obj 259 323 f; +#X obj 187 315 f; +#X obj 268 282 t b b; +#X obj 183 364 outlet; +#X obj 269 379 outlet; +#X obj 179 17 inlet; +#X obj 225 177 tabread \$1; +#X obj 230 88 t f f b; +#X text 376 37 Finds a maximum value in an array; +#X text 531 112 \$2 arrayLength; +#X obj 292 10 inlet; +#X text 425 146 inlets:; +#X text 473 144 1 bang to find the maximum; +#X text 475 157 2 arrayLength; +#X text 407 90 creation arguments: \$1 arrayName; +#X obj 246 38 \$2; +#X obj 202 40 bang; +#X obj 230 65 f; +#X obj 224 6 loadbang; +#X text 444 216 outlets: 1 maximum value; +#X text 498 231 2 index of the maximum value; +#X msg 276 141 -1e+15; +#X obj 222 142 t f f f; +#X floatatom 158 266 5 0 0 0 - - -, f 5; +#X obj 332 302 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 288 253 select 127; +#X floatatom 301 324 5 0 0 0 - - -, f 5; +#X text 362 256 heavy does not support the second inlet of select so +I have to hard code 127 in here; +#X obj 223 110 countTo; +#X connect 0 0 1 0; +#X connect 0 0 2 0; +#X connect 0 0 6 1; +#X connect 0 0 28 0; +#X connect 1 0 0 1; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 4 0 5 1; +#X connect 4 0 31 0; +#X connect 5 0 9 0; +#X connect 6 0 8 0; +#X connect 7 0 6 0; +#X connect 7 1 5 0; +#X connect 10 0 21 0; +#X connect 11 0 0 0; +#X connect 12 0 33 0; +#X connect 12 2 26 0; +#X connect 15 0 22 1; +#X connect 20 0 22 1; +#X connect 21 0 22 0; +#X connect 22 0 12 0; +#X connect 23 0 20 0; +#X connect 26 0 0 1; +#X connect 27 0 30 0; +#X connect 27 1 11 0; +#X connect 27 2 4 1; +#X connect 30 0 7 0; +#X connect 30 0 29 0; +#X connect 33 0 27 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/hello-midi/mono.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,106 @@ +#N canvas 69 182 1020 452 10; +#N canvas 0 23 450 278 (subpatch) 0; +#X array \$0-activeNotes 127 float 2; +#X coords 0 100 127 -1 200 140 1 0 0; +#X restore 537 25 graph; +#N canvas 89 91 450 300 resetArray 1; +#X obj 121 145 tabwrite \$0-activeNotes; +#X msg 123 115 -0.5; +#X obj 154 90 t b f; +#X msg 129 45 128; +#X obj 103 14 inlet; +#X text 212 71 countto; +#X obj 153 69 countTo; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 2 1 0 1; +#X connect 3 0 6 0; +#X connect 4 0 3 0; +#X connect 6 0 2 0; +#X restore 83 49 pd resetArray; +#X obj 83 3 loadbang; +#X obj 88 25 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 39 188 maxArray \$0-activeNotes 128; +#X obj 183 219 f; +#X obj 39 237 >= 0; +#X floatatom 148 313 5 0 0 0 - - -, f 5; +#X obj 70 262 select 1; +#X obj 366 87 f; +#X obj 426 60 f; +#X text 334 39 note; +#X text 424 16 velocity; +#X obj 423 87 > 0; +#X obj 344 281 tabwrite \$0-activeNotes; +#X obj 330 207 f; +#X floatatom 303 178 5 0 0 0 - - -, f 5; +#X obj 265 163 f; +#X obj 304 150 + 1; +#X msg 277 130 -1; +#X msg 371 207 -0.5; +#X obj 400 116 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 367 137 spigot; +#X obj 447 134 spigot; +#X obj 460 86 == 0; +#X obj 470 109 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 434 163 t b f; +#X obj 337 60 inlet; +#X obj 426 32 inlet; +#X obj 148 350 outlet; +#X obj 275 89 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 41 163 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 363 172 t b f; +#X obj 334 240 t b f; +#X text 578 211 pass in velocity/note pairs (velocity first) and obtain +as an output the most recent note still active; +#X text 581 268 outlet 2 gate; +#X obj 330 366 outlet; +#X text 583 251 outlet 1 most recent note active (-1 otherwise); +#X text 155 329 most recent note active; +#X msg 338 338 0; +#X msg 378 339 1; +#X connect 2 0 3 0; +#X connect 3 0 1 0; +#X connect 3 0 19 0; +#X connect 4 0 6 0; +#X connect 4 1 5 1; +#X connect 5 0 7 0; +#X connect 5 0 40 0; +#X connect 6 0 8 0; +#X connect 7 0 29 0; +#X connect 8 0 5 0; +#X connect 8 1 39 0; +#X connect 9 0 22 0; +#X connect 9 0 23 0; +#X connect 10 0 13 0; +#X connect 10 0 24 0; +#X connect 13 0 21 0; +#X connect 15 0 33 0; +#X connect 16 0 15 1; +#X connect 17 0 18 0; +#X connect 18 0 16 0; +#X connect 18 0 17 1; +#X connect 19 0 17 1; +#X connect 20 0 33 0; +#X connect 21 0 22 1; +#X connect 22 0 32 0; +#X connect 23 0 26 0; +#X connect 24 0 25 0; +#X connect 25 0 23 1; +#X connect 26 0 20 0; +#X connect 26 1 14 1; +#X connect 27 0 9 0; +#X connect 28 0 10 0; +#X connect 28 0 30 0; +#X connect 30 0 17 0; +#X connect 31 0 4 0; +#X connect 32 0 15 0; +#X connect 32 1 14 1; +#X connect 33 0 31 0; +#X connect 33 1 14 0; +#X connect 39 0 36 0; +#X connect 40 0 36 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/hello-world/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,13 @@ +#N canvas 275 573 461 212 10; +#X obj 39 143 dac~ 1 2; +#X text 35 32 Hello world!; +#X text 35 42 ============; +#X text 95 79 (the sweet sound of success); +#X obj 39 102 *~ 0.1; +#X obj 39 81 osc~ 440; +#X text 238 160 ---------------------------------; +#X text 238 150 @krighxz / BELA / heavy / 12/2015; +#X text 262 169 beaglert.cc / enzienaudio.com; +#X connect 4 0 0 1; +#X connect 4 0 0 0; +#X connect 5 0 4 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/karplusStrong/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,240 @@ +#N canvas 440 516 715 490 10; +#X obj 38 370 dac~ 1 2; +#X text 470 442 ---------------------------------; +#X text 470 432 @krighxz / BELA / heavy / 12/2015; +#X text 494 451 beaglert.cc / enzienaudio.com; +#X text 33 22 Karplus Strong; +#X text 33 32 ==============; +#X obj 38 323 vd~ \$0-wg1; +#X obj 118 345 lop~ 1000; +#X obj 118 367 *~ 0.99; +#X obj 118 389 s~ \$0-fb1; +#X obj 38 94 adc~ 3; +#X obj 38 116 hip~ 100; +#X obj 98 176 r~ \$0-fb1; +#X obj 38 198 delwrite~ \$0-wg1 100; +#X obj 38 268 *~; +#X obj 38 290 *~ 10; +#X text 99 116 <<< centre (i.e. DC block) signal with high-pass filter +; +#X text 100 94 <<< use accelerometer \, piezo or FSR on first analog +in; +#X text 105 245 <<< use potentiometer or fader on second analog in +; +#X text 100 75 EXCITATION INPUT:; +#X text 100 225 DELAY PERIOD:; +#X text 182 365 <<< and decay here [0-0.9999]; +#X text 182 345 <<< set damping here [~100-20000]; +#N canvas 335 566 461 274 gate 0; +#N canvas 0 22 450 278 (subpatch) 0; +#X array \$0-xfer 1024 float 3; +#A 0 0 -0.808242 -0.804734 -0.801234 -0.797741 -0.794256 -0.790778 +-0.787309 -0.783846 -0.780392 -0.776945 -0.773506 -0.770074 -0.76665 +-0.763233 -0.759824 -0.756423 -0.75303 -0.749644 -0.746266 -0.742895 +-0.739532 -0.736176 -0.732829 -0.729488 -0.726156 -0.722831 -0.719514 +-0.716204 -0.712902 -0.709608 -0.706321 -0.703042 -0.69977 -0.696507 +-0.69325 -0.690002 -0.686761 -0.683527 -0.680302 -0.677084 -0.673873 +-0.67067 -0.667475 -0.664288 -0.661108 -0.657935 -0.654771 -0.651614 +-0.648464 -0.645323 -0.642188 -0.639062 -0.635943 -0.632832 -0.629728 +-0.626632 -0.623544 -0.620463 -0.61739 -0.614324 -0.611266 -0.608216 +-0.605174 -0.602139 -0.599111 -0.596092 -0.59308 -0.590075 -0.587078 +-0.584089 -0.581107 -0.578134 -0.575167 -0.572209 -0.569257 -0.566314 +-0.563378 -0.56045 -0.55753 -0.554617 -0.551711 -0.548814 -0.545924 +-0.543041 -0.540167 -0.537299 -0.53444 -0.531588 -0.528744 -0.525907 +-0.523078 -0.520257 -0.517443 -0.514637 -0.511839 -0.509048 -0.506265 +-0.503489 -0.500721 -0.497961 -0.495208 -0.492463 -0.489726 -0.486996 +-0.484274 -0.481559 -0.478852 -0.476153 -0.473461 -0.470777 -0.468101 +-0.465432 -0.462771 -0.460117 -0.457472 -0.454833 -0.452203 -0.44958 +-0.446964 -0.444357 -0.441757 -0.439164 -0.436579 -0.434002 -0.431432 +-0.42887 -0.426316 -0.42377 -0.42123 -0.418699 -0.416175 -0.413659 +-0.41115 -0.40865 -0.406156 -0.403671 -0.401193 -0.398722 -0.396259 +-0.393804 -0.391357 -0.388917 -0.386485 -0.38406 -0.381643 -0.379234 +-0.376832 -0.374438 -0.372051 -0.369673 -0.367301 -0.364938 -0.362582 +-0.360233 -0.357893 -0.35556 -0.353234 -0.350916 -0.348606 -0.346304 +-0.344009 -0.341721 -0.339442 -0.33717 -0.334905 -0.332649 -0.330399 +-0.328158 -0.325924 -0.323698 -0.321479 -0.319268 -0.317065 -0.314869 +-0.312681 -0.3105 -0.308328 -0.306162 -0.304005 -0.301855 -0.299713 +-0.297578 -0.295451 -0.293331 -0.291219 -0.289115 -0.287019 -0.28493 +-0.282848 -0.280775 -0.278709 -0.27665 -0.2746 -0.272556 -0.270521 +-0.268493 -0.266473 -0.26446 -0.262455 -0.260458 -0.258468 -0.256486 +-0.254511 -0.252545 -0.250585 -0.248634 -0.24669 -0.244753 -0.242825 +-0.240904 -0.23899 -0.237084 -0.235186 -0.233296 -0.231413 -0.229537 +-0.22767 -0.22581 -0.223957 -0.222112 -0.220275 -0.218446 -0.216624 +-0.21481 -0.213003 -0.211204 -0.209413 -0.207629 -0.205853 -0.204084 +-0.202323 -0.20057 -0.198824 -0.197086 -0.195356 -0.193633 -0.191918 +-0.190211 -0.188511 -0.186819 -0.185134 -0.183457 -0.181788 -0.180126 +-0.178472 -0.176826 -0.175187 -0.173556 -0.171932 -0.170316 -0.168708 +-0.167108 -0.165515 -0.163929 -0.162351 -0.160781 -0.159219 -0.157664 +-0.156117 -0.154577 -0.153045 -0.151521 -0.150004 -0.148495 -0.146993 +-0.1455 -0.144013 -0.142535 -0.141064 -0.139601 -0.138145 -0.136697 +-0.135256 -0.133824 -0.132398 -0.130981 -0.129571 -0.128169 -0.126774 +-0.125387 -0.124008 -0.122636 -0.121272 -0.119915 -0.118566 -0.117225 +-0.115891 -0.114565 -0.113247 -0.111936 -0.110633 -0.109338 -0.10805 +-0.10677 -0.105497 -0.104232 -0.102975 -0.101725 -0.100483 -0.0992487 +-0.0980219 -0.0968027 -0.0955911 -0.0943872 -0.0931909 -0.0920023 -0.0908212 +-0.0896478 -0.0884821 -0.0873239 -0.0861734 -0.0850305 -0.0838953 -0.0827676 +-0.0816476 -0.0805353 -0.0794305 -0.0783334 -0.077244 -0.0761621 -0.0750879 +-0.0740213 -0.0729623 -0.071911 -0.0708673 -0.0698312 -0.0688028 -0.067782 +-0.0667688 -0.0657632 -0.0647653 -0.063775 -0.0627924 -0.0618173 -0.0608499 +-0.0598901 -0.058938 -0.0579935 -0.0570566 -0.0561273 -0.0552057 -0.0542917 +-0.0533853 -0.0524866 -0.0515955 -0.050712 -0.0498361 -0.0489679 -0.0481073 +-0.0472543 -0.046409 -0.0455713 -0.0447412 -0.0439188 -0.0431039 -0.0422968 +-0.0414972 -0.0407053 -0.039921 -0.0391443 -0.0383752 -0.0376138 -0.03686 +-0.0361139 -0.0353754 -0.0346445 -0.0339212 -0.0332056 -0.0324976 -0.0317972 +-0.0311044 -0.0304193 -0.0297418 -0.029072 -0.0284097 -0.0277551 -0.0271082 +-0.0264688 -0.0258371 -0.025213 -0.0245966 -0.0239877 -0.0233865 -0.022793 +-0.022207 -0.0216287 -0.021058 -0.020495 -0.0199396 -0.0193918 -0.0188516 +-0.0183191 -0.0177942 -0.0172769 -0.0167673 -0.0162653 -0.0157709 -0.0152841 +-0.014805 -0.0143335 -0.0138696 -0.0134134 -0.0129648 -0.0125238 -0.0120905 +-0.0116647 -0.0112466 -0.0108362 -0.0104333 -0.0100381 -0.00965057 +-0.00927063 -0.00889832 -0.00853363 -0.00817657 -0.00782715 -0.00748535 +-0.00715118 -0.00682465 -0.00650574 -0.00619446 -0.00589081 -0.00559479 +-0.0053064 -0.00502563 -0.0047525 -0.004487 -0.00422913 -0.00397888 +-0.00373627 -0.00350128 -0.00327393 -0.0030542 -0.0028421 -0.00263763 +-0.0024408 -0.00225159 -0.00207001 -0.00189606 -0.00172974 -0.00157104 +-0.00141998 -0.00127655 -0.00114075 -0.00101257 -0.000892029 -0.000779114 +-0.000673828 -0.000576172 -0.000486145 -0.000403747 -0.000328979 -0.000261841 +-0.000202332 -0.000150452 -0.000106201 -6.95801e-05 -4.05884e-05 -1.92261e-05 +-5.49316e-06 0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 +-0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 +-0 -0 -0 -0 -0 -0 -0 -0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5.49316e-06 +1.92261e-05 4.05884e-05 6.95801e-05 0.000106201 0.000150452 0.000202332 +0.000261841 0.000328979 0.000403747 0.000486145 0.000576172 0.000673828 +0.000779114 0.000892029 0.00101257 0.00114075 0.00127655 0.00141998 +0.00157104 0.00172974 0.00189606 0.00207001 0.00225159 0.0024408 0.00263763 +0.0028421 0.0030542 0.00327393 0.00350128 0.00373627 0.00397888 0.00422913 +0.004487 0.0047525 0.00502563 0.0053064 0.00559479 0.00589081 0.00619446 +0.00650574 0.00682465 0.00715118 0.00748535 0.00782715 0.00817657 0.00853363 +0.00889832 0.00927063 0.00965057 0.0100381 0.0104333 0.0108362 0.0112466 +0.0116647 0.0120905 0.0125238 0.0129648 0.0134134 0.0138696 0.0143335 +0.014805 0.0152841 0.0157709 0.0162653 0.0167673 0.0172769 0.0177942 +0.0183191 0.0188516 0.0193918 0.0199396 0.020495 0.021058 0.0216287 +0.022207 0.022793 0.0233865 0.0239877 0.0245966 0.025213 0.0258371 +0.0264688 0.0271082 0.0277551 0.0284097 0.029072 0.0297418 0.0304193 +0.0311044 0.0317972 0.0324976 0.0332056 0.0339212 0.0346445 0.0353754 +0.0361139 0.03686 0.0376138 0.0383752 0.0391443 0.039921 0.0407053 +0.0414972 0.0422968 0.0431039 0.0439188 0.0447412 0.0455713 0.046409 +0.0472543 0.0481073 0.0489679 0.0498361 0.050712 0.0515955 0.0524866 +0.0533853 0.0542917 0.0552057 0.0561273 0.0570566 0.0579935 0.058938 +0.0598901 0.0608499 0.0618173 0.0627924 0.063775 0.0647653 0.0657632 +0.0667688 0.067782 0.0688028 0.0698312 0.0708673 0.071911 0.0729623 +0.0740213 0.0750879 0.0761621 0.077244 0.0783334 0.0794305 0.0805353 +0.0816476 0.0827676 0.0838953 0.0850305 0.0861734 0.0873239 0.0884821 +0.0896478 0.0908212 0.0920023 0.0931909 0.0943872 0.0955911 0.0968027 +0.0980219 0.0992487 0.100483 0.101725 0.102975 0.104232 0.105497 0.10677 +0.10805 0.109338 0.110633 0.111936 0.113247 0.114565 0.115891 0.117225 +0.118566 0.119915 0.121272 0.122636 0.124008 0.125387 0.126774 0.128169 +0.129571 0.130981 0.132398 0.133824 0.135256 0.136697 0.138145 0.139601 +0.141064 0.142535 0.144013 0.1455 0.146993 0.148495 0.150004 0.151521 +0.153045 0.154577 0.156117 0.157664 0.159219 0.160781 0.162351 0.163929 +0.165515 0.167108 0.168708 0.170316 0.171932 0.173556 0.175187 0.176826 +0.178472 0.180126 0.181788 0.183457 0.185134 0.186819 0.188511 0.190211 +0.191918 0.193633 0.195356 0.197086 0.198824 0.20057 0.202323 0.204084 +0.205853 0.207629 0.209413 0.211204 0.213003 0.21481 0.216624 0.218446 +0.220275 0.222112 0.223957 0.22581 0.22767 0.229537 0.231413 0.233296 +0.235186 0.237084 0.23899 0.240904 0.242825 0.244753 0.24669 0.248634 +0.250585 0.252545 0.254511 0.256486 0.258468 0.260458 0.262455 0.26446 +0.266473 0.268493 0.270521 0.272556 0.2746 0.27665 0.278709 0.280775 +0.282848 0.28493 0.287019 0.289115 0.291219 0.293331 0.295451 0.297578 +0.299713 0.301855 0.304005 0.306162 0.308328 0.3105 0.312681 0.314869 +0.317065 0.319268 0.321479 0.323698 0.325924 0.328158 0.330399 0.332649 +0.334905 0.33717 0.339442 0.341721 0.344009 0.346304 0.348606 0.350916 +0.353234 0.35556 0.357893 0.360233 0.362582 0.364938 0.367301 0.369673 +0.372051 0.374438 0.376832 0.379234 0.381643 0.38406 0.386485 0.388917 +0.391357 0.393804 0.396259 0.398722 0.401193 0.403671 0.406156 0.40865 +0.41115 0.413659 0.416175 0.418699 0.42123 0.42377 0.426316 0.42887 +0.431432 0.434002 0.436579 0.439164 0.441757 0.444357 0.446964 0.44958 +0.452203 0.454833 0.457472 0.460117 0.462771 0.465432 0.468101 0.470777 +0.473461 0.476153 0.478852 0.481559 0.484274 0.486996 0.489726 0.492463 +0.495208 0.497961 0.500721 0.503489 0.506265 0.509048 0.511839 0.514637 +0.517443 0.520257 0.523078 0.525907 0.528744 0.531588 0.53444 0.537299 +0.540167 0.543041 0.545924 0.548814 0.551711 0.554617 0.55753 0.56045 +0.563378 0.566314 0.569257 0.572209 0.575167 0.578134 0.581107 0.584089 +0.587078 0.590075 0.59308 0.596092 0.599111 0.602139 0.605174 0.608216 +0.611266 0.614324 0.61739 0.620463 0.623544 0.626632 0.629728 0.632832 +0.635943 0.639062 0.642188 0.645323 0.648464 0.651614 0.654771 0.657935 +0.661108 0.664288 0.667475 0.67067 0.673873 0.677084 0.680302 0.683527 +0.686761 0.690002 0.69325 0.696507 0.69977 0.703042 0.706321 0.709608 +0.712902 0.716204 0.719514 0.722831; +#A 1000 0.726156 0.729488 0.732829 0.736176 0.739532 0.742895 0.746266 +0.749644 0.75303 0.756423 0.759824 0.763233 0.76665 0.770074 0.773506 +0.776945 0.780392 0.783846 0.787309 0.790778 0.794256 0.797741 0.801234 +0.804734; +#X coords 0 1 1023 -1 200 200 1 0 0; +#X restore 230 34 graph; +#X obj 25 27 inlet~; +#X obj 25 49 clip~ -1 1; +#X obj 25 71 *~ 512; +#X obj 25 93 +~ 512; +#X obj 25 115 tabread4~ \$0-xfer; +#X obj 25 137 outlet~; +#N canvas 0 22 334 332 generate-xfer 0; +#X obj 8 290 tabwrite \$0-xfer; +#X obj 8 109 / 1024; +#X obj 8 129 * 2; +#X obj 8 149 - 1; +#X obj 8 169 moses 0; +#X obj 8 191 + 0.1; +#X obj 8 213 clip -1 0; +#X obj 68 191 - 0.1; +#X obj 68 213 clip 0 1; +#X obj 101 16 inlet threshold; +#X obj 101 78 count 1024; +#X obj 128 58 s \$0-thresh; +#X obj 95 169 r \$0-thresh; +#X obj 101 38 t b f; +#X obj 68 236 *; +#X obj 8 236 *; +#X obj 8 258 * -1; +#X text 140 203 <<< deadzone; +#X text 140 253 <<< smooth by taking exponent; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 4 1 7 0; +#X connect 5 0 6 0; +#X connect 6 0 15 0; +#X connect 6 0 15 1; +#X connect 7 0 8 0; +#X connect 8 0 14 0; +#X connect 8 0 14 1; +#X connect 9 0 13 0; +#X connect 10 0 0 1; +#X connect 10 0 1 0; +#X connect 12 0 5 1; +#X connect 12 0 7 1; +#X connect 13 0 10 0; +#X connect 13 1 11 0; +#X connect 14 0 0 0; +#X connect 15 0 16 0; +#X connect 16 0 0 0; +#X restore 26 217 pd generate-xfer; +#X text 58 196 <<< threshold; +#X obj 26 173 loadbang; +#X msg 26 195 0.1; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 5 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 7 0; +#X restore 38 137 pd gate; +#X obj 38 246 adc~ 10; +#X text 98 137 <<< thresholding to remove any consistent noise in the +excitation signal; +#X connect 6 0 7 0; +#X connect 6 0 0 0; +#X connect 6 0 0 1; +#X connect 7 0 8 0; +#X connect 8 0 9 0; +#X connect 10 0 11 0; +#X connect 11 0 23 0; +#X connect 12 0 13 0; +#X connect 14 0 15 0; +#X connect 15 0 6 0; +#X connect 23 0 13 0; +#X connect 24 0 14 0; +#X connect 24 0 14 1;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/karplusStrong/count.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,30 @@ +#N canvas 592 177 306 227 10; +#X obj 32 111 f; +#X obj 57 111 + 1; +#X obj 57 151 sel 0; +#X obj 57 171 del 1e-36; +#X obj 57 131 > 1023; +#X msg 32 90 0; +#X obj 19 171 - 1; +#X obj 19 193 outlet; +#X obj 90 87 \$1; +#X obj 90 109 - 1; +#X obj 90 66 loadbang; +#X obj 32 48 inlet; +#X obj 32 69 t b; +#X text 33 14 temporary replacement for [until] object; +#X text 67 195 outputs index (0->[N-1]); +#X connect 0 0 1 0; +#X connect 1 0 0 1; +#X connect 1 0 4 0; +#X connect 1 0 6 0; +#X connect 2 0 3 0; +#X connect 3 0 0 0; +#X connect 4 0 2 0; +#X connect 5 0 0 0; +#X connect 6 0 7 0; +#X connect 8 0 9 0; +#X connect 9 0 4 1; +#X connect 10 0 8 0; +#X connect 11 0 12 0; +#X connect 12 0 5 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,186 @@ +#N canvas 8 23 1272 752 10; +#X text 39 1 Hello world!; +#X text 1003 636 ---------------------------------; +#X text 1003 626 @krighxz / BELA / heavy / 12/2015; +#X text 1027 645 beaglert.cc / enzienaudio.com; +#X text 306 61 [pgmin]; +#X text 416 31 [ctlin]; +#X text 825 28 [notein]; +#X text 228 32 <== the bela equivalent of ==>; +#X text 116 61 <== the bela equivalent of ==>; +#X obj 740 28 bela_notein 0; +#X obj 740 57 pack 0 0; +#X obj 740 106 pack 0 0 0; +#X obj 596 976 dac~ 1 2; +#X obj 646 178 s voice-note-1; +#X obj 736 178 s voice-note-2; +#X obj 826 178 s voice-note-3; +#X obj 916 178 s voice-note-4; +#X obj 594 252 catch~ output; +#X obj 541 57 voice 1; +#X obj 1150 21 loadbang; +#X obj 1150 43 metro 10; +#X obj 1150 65 s metro; +#X obj 944 336 * 1000; +#X obj 1036 392 s Q; +#X obj 944 381 s attack; +#X obj 1036 336 * 8000; +#X obj 1036 365 + 200; +#X obj 1116 379 s~ wobble; +#X obj 944 358 + 5; +#X obj 1116 336 *~ 25; +#X obj 629 334 r Q; +#X obj 594 309 *~ 1; +#X obj 981 565 clip~ 0 0.999; +#X obj 836 610 *~; +#X obj 740 128 route 1 2 3 4, f 36; +#X obj 836 509 +~ 100; +#X obj 836 485 *~ 1900; +#X obj 624 651 delwrite~ ddd 2000; +#X obj 740 84 poly 4 1; +#X obj 664 729 *~ 0.5; +#X obj 598 730 *~ 0.5; +#X obj 597 757 hip~ 5; +#X obj 624 558 hip~ 5; +#X obj 624 580 hv_tanh; +#X obj 836 667 hip~ 5; +#X obj 836 689 hv_tanh; +#X obj 836 566 delread~ ddd 500; +#N canvas 0 22 178 130 snapshot 0; +#X obj 24 20 inlet~; +#X obj 24 62 snapshot~; +#X obj 24 84 outlet; +#X obj 86 29 r metro; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 3 0 1 0; +#X restore 846 538 pd snapshot; +#X obj 78 173 bela_ctlin 1 0; +#X obj 159 203 s c1; +#X obj 41 61 bela_pgmin 0; +#X obj 78 233 bela_ctlin 2 0; +#X obj 159 263 s c2; +#X obj 78 293 bela_ctlin 3 0; +#X obj 159 323 s c3; +#X obj 78 353 bela_ctlin 4 0; +#X obj 159 383 s c4; +#X obj 498 731 r c1; +#X obj 498 753 / 127; +#X obj 943 311 / 127; +#X obj 943 289 r c2; +#X obj 1033 311 / 127; +#X obj 1033 289 r c3; +#X obj 1115 291 / 127; +#X obj 1115 269 r c4; +#X obj 1115 313 sig~; +#X obj 78 413 bela_ctlin 5 0; +#X obj 159 443 s c5; +#X obj 78 473 bela_ctlin 6 0; +#X obj 159 503 s c6; +#X obj 828 407 / 127; +#X obj 828 429 sig~; +#X obj 828 385 r c5; +#X obj 981 519 / 127; +#X obj 981 541 sig~; +#X obj 981 497 r c6; +#X obj 593 389 *~ 0.5; +#X obj 777 562 vd~ ddd; +#X obj 597 784 hv_tanh; +#X obj 597 818 *~; +#X obj 593 360 lop~ 1000; +#X obj 828 458 lop~ 10; +#X obj 78 533 bela_ctlin 7 0; +#X obj 159 563 s c7; +#X obj 78 593 bela_ctlin 8 0; +#X obj 159 623 s c8; +#X obj 664 769 loadbang; +#X msg 665 792 0.75; +#X obj 1116 456 * 8000; +#X obj 1116 485 + 200; +#X obj 1113 431 / 127; +#X obj 1113 409 r c7; +#X obj 1116 512 s QP; +#X obj 653 850 lop~ 8000; +#X obj 1065 725 r c8; +#X obj 689 824 r QP; +#X obj 1065 750 / 127; +#X obj 1065 772 s octVol; +#X obj 541 77 voice 2; +#X obj 541 97 voice 3; +#X obj 541 117 voice 4; +#X connect 9 0 10 0; +#X connect 9 1 10 1; +#X connect 10 0 38 0; +#X connect 11 0 34 0; +#X connect 17 0 31 0; +#X connect 19 0 20 0; +#X connect 20 0 21 0; +#X connect 22 0 28 0; +#X connect 25 0 26 0; +#X connect 26 0 23 0; +#X connect 28 0 24 0; +#X connect 29 0 27 0; +#X connect 30 0 80 1; +#X connect 31 0 80 0; +#X connect 32 0 33 1; +#X connect 33 0 39 0; +#X connect 33 0 44 0; +#X connect 34 0 13 0; +#X connect 34 1 14 0; +#X connect 34 2 15 0; +#X connect 34 3 16 0; +#X connect 35 0 47 0; +#X connect 35 0 77 0; +#X connect 36 0 35 0; +#X connect 38 0 11 0; +#X connect 38 1 11 1; +#X connect 38 2 11 2; +#X connect 39 0 41 0; +#X connect 40 0 41 0; +#X connect 41 0 78 0; +#X connect 42 0 43 0; +#X connect 43 0 37 0; +#X connect 44 0 45 0; +#X connect 45 0 37 0; +#X connect 47 0 46 0; +#X connect 48 0 49 0; +#X connect 51 0 52 0; +#X connect 53 0 54 0; +#X connect 55 0 56 0; +#X connect 57 0 58 0; +#X connect 58 0 79 1; +#X connect 59 0 22 0; +#X connect 60 0 59 0; +#X connect 61 0 25 0; +#X connect 62 0 61 0; +#X connect 63 0 65 0; +#X connect 64 0 63 0; +#X connect 65 0 29 0; +#X connect 66 0 67 0; +#X connect 68 0 69 0; +#X connect 70 0 71 0; +#X connect 71 0 81 0; +#X connect 72 0 70 0; +#X connect 73 0 74 0; +#X connect 74 0 32 0; +#X connect 75 0 73 0; +#X connect 76 0 40 0; +#X connect 76 0 42 0; +#X connect 77 0 33 0; +#X connect 78 0 79 0; +#X connect 79 0 93 0; +#X connect 80 0 76 0; +#X connect 81 0 36 0; +#X connect 82 0 83 0; +#X connect 84 0 85 0; +#X connect 86 0 87 0; +#X connect 87 0 79 1; +#X connect 88 0 89 0; +#X connect 89 0 92 0; +#X connect 90 0 88 0; +#X connect 91 0 90 0; +#X connect 93 0 12 0; +#X connect 93 0 12 1; +#X connect 94 0 96 0; +#X connect 95 0 93 1; +#X connect 96 0 97 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/backmain.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,79 @@ +#N canvas 85 58 1280 685 10; +#X obj 19 396 dac~ 1 2; +#X text 39 1 Hello world!; +#X text 37 11 ============; +#X obj 31 353 *~ 0.1; +#X text 202 448 ---------------------------------; +#X text 202 438 @krighxz / BELA / heavy / 12/2015; +#X text 226 457 beaglert.cc / enzienaudio.com; +#X obj 39 132 mtof; +#X floatatom 79 59 5 0 0 0 - - -, f 5; +#X floatatom 122 59 5 0 0 0 - - -, f 5; +#X floatatom 41 63 5 0 0 0 - - -, f 5; +#X obj 26 170 phasor~ 440; +#X text 100 363 (the harsh sound of success); +#X obj 260 83 * 20; +#X obj 261 112 + 200; +#X obj 132 85 loadbang; +#X msg 131 111 1000; +#X obj 125 166 sig~; +#X text 673 121 [pgmin]; +#X obj 218 178 * 10; +#X obj 30 250 hip~; +#X obj 26 275 hip~; +#X obj 20 302 hip~; +#X obj 19 323 hip~; +#X obj 87 192 lop~ 4; +#X obj 152 256 line; +#X obj 200 200 + 50; +#X msg 170 227 \$1 200; +#X msg 93 114 0; +#X msg 185 112 0; +#X obj 29 224 vcf~ 4; +#X obj 70 333 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 42 92 mono; +#X obj 40 28 bela_notein 0; +#X obj 260 60 bela_ctlin 5 0; +#X obj 220 151 bela_ctlin 6 0; +#X obj 408 121 bela_pgmin 3; +#X text 537 58 [ctlin]; +#X text 332 27 [notein]; +#X text 140 29 <== the bela equivalent of ==>; +#X text 349 59 <== the bela equivalent of ==>; +#X text 483 121 <== the bela equivalent of ==>; +#X connect 3 0 0 1; +#X connect 3 0 0 0; +#X connect 7 0 11 0; +#X connect 8 0 32 1; +#X connect 10 0 32 0; +#X connect 11 0 30 0; +#X connect 13 0 14 0; +#X connect 14 0 17 0; +#X connect 15 0 16 0; +#X connect 15 0 29 0; +#X connect 15 0 28 0; +#X connect 16 0 17 0; +#X connect 17 0 24 0; +#X connect 19 0 26 0; +#X connect 20 0 21 0; +#X connect 21 0 22 0; +#X connect 22 0 23 0; +#X connect 23 0 3 0; +#X connect 24 0 30 1; +#X connect 25 0 20 1; +#X connect 25 0 21 1; +#X connect 25 0 22 1; +#X connect 25 0 23 1; +#X connect 26 0 27 0; +#X connect 27 0 25 0; +#X connect 29 0 19 0; +#X connect 30 0 20 0; +#X connect 31 0 3 1; +#X connect 32 0 7 0; +#X connect 32 1 31 0; +#X connect 33 0 10 0; +#X connect 33 1 8 0; +#X connect 33 2 9 0; +#X connect 34 0 13 0; +#X connect 35 0 19 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/bela_ctlin.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,76 @@ +#N canvas 554 204 703 475 10; +#X obj 53 431 outlet; +#X obj 108 429 outlet; +#X obj 99 127 r ctlin; +#X obj 92 151 unpack f f f; +#X obj 154 429 outlet; +#X obj 86 322 spigot; +#X text 51 450 value; +#X text 105 450 number; +#X obj 211 138 loadbang; +#X obj 177 193 \$1; +#X obj 126 214 == \$1; +#X obj 119 299 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 84 349 unpack f f f; +#X obj 143 247 ||; +#X obj 177 217 == 0; +#X text 70 11 Emulates ctlin \, except number of outlets is fixed. +; +#X obj 228 247 ||; +#X obj 262 217 == 0; +#X obj 212 214 == \$2; +#X obj 262 193 \$2; +#X obj 177 277 &&; +#X obj 211 163 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X text 173 299 If (inputController==\$1 || \$1==0) && (inputChannel==\$2 +|| \$2==0); +#X text 197 52 Known issue: trying to select inputController 0 will +result i accepting all controllers (because a pd external cannot tell +the difference between \$1 been explicitely set to 0 and the patch +not having any argument); +#X text 162 450 channel; +#X obj 56 192 pack f f f; +#X obj 80 408 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X floatatom 81 382 5 0 0 0 - - -, f 5; +#X obj 121 412 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X floatatom 122 386 5 0 0 0 - - -, f 5; +#X obj 172 406 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X floatatom 173 380 5 0 0 0 - - -, f 5; +#X obj 122 92 s ctlin; +#X obj 64 29 r bela_ctlin; +#X connect 2 0 3 0; +#X connect 3 0 25 0; +#X connect 3 1 10 0; +#X connect 3 1 25 1; +#X connect 3 2 18 0; +#X connect 3 2 25 2; +#X connect 5 0 12 0; +#X connect 8 0 21 0; +#X connect 9 0 14 0; +#X connect 10 0 13 0; +#X connect 11 0 5 1; +#X connect 12 0 0 0; +#X connect 12 0 27 0; +#X connect 12 1 1 0; +#X connect 12 1 29 0; +#X connect 12 2 4 0; +#X connect 12 2 31 0; +#X connect 13 0 20 0; +#X connect 14 0 13 1; +#X connect 16 0 20 1; +#X connect 17 0 16 1; +#X connect 18 0 16 0; +#X connect 19 0 17 0; +#X connect 20 0 11 0; +#X connect 21 0 9 0; +#X connect 21 0 19 0; +#X connect 25 0 5 0; +#X connect 27 0 26 0; +#X connect 29 0 28 0; +#X connect 31 0 30 0; +#X connect 33 0 32 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/bela_notein.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,59 @@ +#N canvas 399 23 629 685 10; +#X obj 94 481 outlet; +#X obj 165 475 outlet; +#X obj 141 184 unpack f f f; +#X obj 221 472 outlet; +#X obj 143 365 spigot; +#X obj 268 181 loadbang; +#X obj 234 236 \$1; +#X obj 183 257 == \$1; +#X obj 176 342 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 143 392 unpack f f f; +#X obj 200 290 ||; +#X obj 234 260 == 0; +#X obj 268 206 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X text 160 65 Emulates notein \, except number of outlets is fixed. +; +#X text 92 499 notenumber; +#X text 161 489 velocity; +#X text 220 486 channel; +#X text 229 311 If (inputChannel==\$1 || \$1==0); +#X obj 115 232 pack f f f; +#X obj 82 428 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X floatatom 84 410 5 0 0 0 - - -, f 5; +#X obj 145 448 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X floatatom 147 430 5 0 0 0 - - -, f 5; +#X obj 198 451 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X floatatom 200 433 5 0 0 0 - - -, f 5; +#X obj 131 112 s notein; +#X obj 140 149 r notein; +#X obj 135 84 r bela_notein; +#X connect 2 0 18 0; +#X connect 2 1 18 1; +#X connect 2 2 7 0; +#X connect 2 2 18 2; +#X connect 4 0 9 0; +#X connect 5 0 12 0; +#X connect 6 0 11 0; +#X connect 7 0 10 0; +#X connect 8 0 4 1; +#X connect 9 0 0 0; +#X connect 9 0 20 0; +#X connect 9 1 1 0; +#X connect 9 1 22 0; +#X connect 9 2 3 0; +#X connect 9 2 24 0; +#X connect 10 0 8 0; +#X connect 11 0 10 1; +#X connect 12 0 6 0; +#X connect 18 0 4 0; +#X connect 20 0 19 0; +#X connect 22 0 21 0; +#X connect 24 0 23 0; +#X connect 26 0 2 0; +#X connect 27 0 25 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/bela_pgmin.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,53 @@ +#N canvas 623 197 587 546 10; +#X obj 73 413 outlet; +#X obj 174 411 outlet; +#X obj 106 304 spigot; +#X obj 197 126 loadbang; +#X obj 197 175 \$1; +#X obj 146 196 == \$1; +#X obj 139 281 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 163 229 ||; +#X obj 197 199 == 0; +#X obj 197 151 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 89 111 unpack f f; +#X obj 106 332 unpack f f; +#X text 52 436 program number; +#X text 182 432 channel; +#X text 193 281 If (channel==\$1 || \$1==0); +#X text 167 45 emulates pgmin except it always has 2 outlets and requires +the input parameters to be explicitely set. Set them to 0 to avoid +filtering; +#X text 262 132 It'd be nicer with [t l l] but have to compensate for +the fact that it is not supported by heavy; +#X obj 77 183 pack f f; +#X floatatom 72 355 5 0 0 0 - - -, f 5; +#X obj 63 379 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X floatatom 150 361 5 0 0 0 - - -, f 5; +#X obj 141 385 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 91 63 s pgmin; +#X obj 93 87 r pgmin; +#X obj 89 42 r bela_pgmin; +#X connect 2 0 11 0; +#X connect 3 0 9 0; +#X connect 4 0 8 0; +#X connect 5 0 7 0; +#X connect 6 0 2 1; +#X connect 7 0 6 0; +#X connect 8 0 7 1; +#X connect 9 0 4 0; +#X connect 10 0 17 0; +#X connect 10 1 5 0; +#X connect 10 1 17 1; +#X connect 11 0 0 0; +#X connect 11 0 18 0; +#X connect 11 1 1 0; +#X connect 11 1 20 0; +#X connect 17 0 2 0; +#X connect 18 0 19 0; +#X connect 20 0 21 0; +#X connect 23 0 10 0; +#X connect 24 0 22 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/countTo.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,33 @@ +#N canvas 584 255 450 300 10; +#X obj 65 196 outlet; +#X obj 98 8 inlet; +#X text 189 49 counts from 0 to the given number -1; +#X text 214 95 inlet:N; +#X text 212 112 outlet: 0 \, 1 \, 2 \, ... \, N-1; +#X obj 143 61 f; +#X obj 100 138 spigot; +#X obj 129 89 <; +#X obj 129 113 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 95 28 t b f b; +#X obj 92 74 + 1; +#X obj 43 73 f; +#X obj 63 104 t b f f f; +#X msg 92 53 0; +#X obj 16 144 delay 0; +#X connect 1 0 9 0; +#X connect 5 0 7 1; +#X connect 6 0 11 0; +#X connect 7 0 8 0; +#X connect 8 0 6 1; +#X connect 9 0 11 0; +#X connect 9 1 5 0; +#X connect 9 1 13 0; +#X connect 10 0 11 1; +#X connect 11 0 12 0; +#X connect 12 0 14 0; +#X connect 12 1 0 0; +#X connect 12 2 7 0; +#X connect 12 3 10 0; +#X connect 13 0 11 1; +#X connect 14 0 6 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/hv_tanh.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,27 @@ +#N canvas 254 82 445 331 10; +#X obj 39 37 inlet~; +#X obj 39 67 clip~ -3 3; +#X obj 54 107 *~; +#X obj 39 277 outlet~; +#X obj 109 107 sig~ 27; +#X obj 54 147 +~; +#X obj 54 217 /~; +#X obj 39 247 *~; +#X obj 94 147 *~ 9; +#X obj 94 187 +~; +#X text 142 177 // http://www.musicdsp.org/showone.php?id=238; +#X text 140 198 // y = x * (27 + x^2) / (27 + 9*x^2); +#X text 144 152 // pade-approximation of tanh function; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 1 0 2 1; +#X connect 1 0 7 0; +#X connect 2 0 5 0; +#X connect 2 0 8 0; +#X connect 4 0 5 1; +#X connect 4 0 9 1; +#X connect 5 0 6 0; +#X connect 6 0 7 1; +#X connect 7 0 3 0; +#X connect 8 0 9 0; +#X connect 9 0 6 1;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/maxArray.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,67 @@ +#N canvas 464 23 1002 583 10; +#X obj 224 202 max; +#X obj 265 200 f; +#X obj 223 229 change; +#X obj 223 251 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 223 271 f; +#X obj 259 323 f; +#X obj 187 315 f; +#X obj 268 282 t b b; +#X obj 183 364 outlet; +#X obj 269 379 outlet; +#X obj 179 17 inlet; +#X obj 225 177 tabread \$1; +#X obj 230 88 t f f b; +#X text 376 37 Finds a maximum value in an array; +#X text 531 112 \$2 arrayLength; +#X obj 292 10 inlet; +#X text 425 146 inlets:; +#X text 473 144 1 bang to find the maximum; +#X text 475 157 2 arrayLength; +#X text 407 90 creation arguments: \$1 arrayName; +#X obj 246 38 \$2; +#X obj 202 40 bang; +#X obj 230 65 f; +#X obj 224 6 loadbang; +#X text 444 216 outlets: 1 maximum value; +#X text 498 231 2 index of the maximum value; +#X msg 276 141 -1e+15; +#X obj 222 142 t f f f; +#X floatatom 158 266 5 0 0 0 - - -, f 5; +#X obj 332 302 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 288 253 select 127; +#X floatatom 301 324 5 0 0 0 - - -, f 5; +#X text 362 256 heavy does not support the second inlet of select so +I have to hard code 127 in here; +#X obj 223 110 countTo; +#X connect 0 0 1 0; +#X connect 0 0 2 0; +#X connect 0 0 6 1; +#X connect 0 0 28 0; +#X connect 1 0 0 1; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 4 0 5 1; +#X connect 4 0 31 0; +#X connect 5 0 9 0; +#X connect 6 0 8 0; +#X connect 7 0 6 0; +#X connect 7 1 5 0; +#X connect 10 0 21 0; +#X connect 11 0 0 0; +#X connect 12 0 33 0; +#X connect 12 2 26 0; +#X connect 15 0 22 1; +#X connect 20 0 22 1; +#X connect 21 0 22 0; +#X connect 22 0 12 0; +#X connect 23 0 20 0; +#X connect 26 0 0 1; +#X connect 27 0 30 0; +#X connect 27 1 11 0; +#X connect 27 2 4 1; +#X connect 30 0 7 0; +#X connect 30 0 29 0; +#X connect 33 0 27 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/mono.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,106 @@ +#N canvas 69 182 1020 452 10; +#N canvas 0 23 450 278 (subpatch) 0; +#X array \$0-activeNotes 127 float 2; +#X coords 0 100 127 -1 200 140 1 0 0; +#X restore 537 25 graph; +#N canvas 89 91 450 300 resetArray 1; +#X obj 121 145 tabwrite \$0-activeNotes; +#X msg 123 115 -0.5; +#X obj 154 90 t b f; +#X msg 129 45 128; +#X obj 103 14 inlet; +#X text 212 71 countto; +#X obj 153 69 countTo; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 2 1 0 1; +#X connect 3 0 6 0; +#X connect 4 0 3 0; +#X connect 6 0 2 0; +#X restore 83 49 pd resetArray; +#X obj 83 3 loadbang; +#X obj 88 25 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 39 188 maxArray \$0-activeNotes 128; +#X obj 183 219 f; +#X obj 39 237 >= 0; +#X floatatom 148 313 5 0 0 0 - - -, f 5; +#X obj 70 262 select 1; +#X obj 366 87 f; +#X obj 426 60 f; +#X text 334 39 note; +#X text 424 16 velocity; +#X obj 423 87 > 0; +#X obj 344 281 tabwrite \$0-activeNotes; +#X obj 330 207 f; +#X floatatom 303 178 5 0 0 0 - - -, f 5; +#X obj 265 163 f; +#X obj 304 150 + 1; +#X msg 277 130 -1; +#X msg 371 207 -0.5; +#X obj 400 116 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 367 137 spigot; +#X obj 447 134 spigot; +#X obj 460 86 == 0; +#X obj 470 109 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 434 163 t b f; +#X obj 337 60 inlet; +#X obj 426 32 inlet; +#X obj 148 350 outlet; +#X obj 275 89 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 41 163 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 363 172 t b f; +#X obj 334 240 t b f; +#X text 578 211 pass in velocity/note pairs (velocity first) and obtain +as an output the most recent note still active; +#X text 581 268 outlet 2 gate; +#X obj 330 366 outlet; +#X text 583 251 outlet 1 most recent note active (-1 otherwise); +#X text 155 329 most recent note active; +#X msg 338 338 0; +#X msg 378 339 1; +#X connect 2 0 3 0; +#X connect 3 0 1 0; +#X connect 3 0 19 0; +#X connect 4 0 6 0; +#X connect 4 1 5 1; +#X connect 5 0 7 0; +#X connect 5 0 40 0; +#X connect 6 0 8 0; +#X connect 7 0 29 0; +#X connect 8 0 5 0; +#X connect 8 1 39 0; +#X connect 9 0 22 0; +#X connect 9 0 23 0; +#X connect 10 0 13 0; +#X connect 10 0 24 0; +#X connect 13 0 21 0; +#X connect 15 0 33 0; +#X connect 16 0 15 1; +#X connect 17 0 18 0; +#X connect 18 0 16 0; +#X connect 18 0 17 1; +#X connect 19 0 17 1; +#X connect 20 0 33 0; +#X connect 21 0 22 1; +#X connect 22 0 32 0; +#X connect 23 0 26 0; +#X connect 24 0 25 0; +#X connect 25 0 23 1; +#X connect 26 0 20 0; +#X connect 26 1 14 1; +#X connect 27 0 9 0; +#X connect 28 0 10 0; +#X connect 28 0 30 0; +#X connect 30 0 17 0; +#X connect 31 0 4 0; +#X connect 32 0 15 0; +#X connect 32 1 14 1; +#X connect 33 0 31 0; +#X connect 33 1 14 0; +#X connect 39 0 36 0; +#X connect 40 0 36 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/midi-poly-synth/voice.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,55 @@ +#N canvas 145 23 388 553 10; +#X obj 45 25 r voice-note-\$1; +#X obj 45 47 unpack 0 0; +#X obj 45 103 mtof; +#X obj 111 446 *~; +#X obj 152 367 / 127; +#X obj 111 500 throw~ output; +#X obj 152 419 line~; +#X obj 152 393 pack 0 0; +#X obj 59 176 phasor~; +#X obj 129 176 phasor~; +#X obj 86 304 +~; +#X obj 197 367 r attack; +#X obj 137 115 sig~; +#X obj 137 137 +~; +#X obj 171 113 r~ wobble; +#X obj 59 198 *~ 2; +#X obj 59 220 -~ 1; +#X obj 129 198 *~ 2; +#X obj 129 220 -~ 1; +#X obj 310 280 r octVol; +#X obj 268 397 osc~; +#X obj 268 419 *~; +#X obj 111 371 +~; +#X obj 123 475 *~ 0.5; +#X obj 268 364 mtof; +#X obj 267 323 - 12; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 1 0 25 0; +#X connect 1 1 4 0; +#X connect 2 0 8 0; +#X connect 2 0 12 0; +#X connect 3 0 23 0; +#X connect 4 0 7 0; +#X connect 6 0 3 1; +#X connect 7 0 6 0; +#X connect 8 0 15 0; +#X connect 9 0 17 0; +#X connect 10 0 22 0; +#X connect 11 0 7 1; +#X connect 12 0 13 0; +#X connect 13 0 9 0; +#X connect 14 0 13 1; +#X connect 15 0 16 0; +#X connect 16 0 10 1; +#X connect 17 0 18 0; +#X connect 18 0 10 0; +#X connect 19 0 21 1; +#X connect 20 0 21 0; +#X connect 21 0 22 1; +#X connect 22 0 3 0; +#X connect 23 0 5 0; +#X connect 24 0 20 0; +#X connect 25 0 24 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/rubberDuckie/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,247 @@ +#N canvas 275 573 442 207 10; +#X obj 39 149 dac~ 1 2; +#X text 218 143 ---------------------------------; +#X text 218 133 @krighxz / BELA / heavy / 12/2015; +#X text 242 152 beaglert.cc / enzienaudio.com; +#X text 35 32 Rubber Duckie; +#X text 35 42 =============; +#N canvas 325 86 823 605 duckie 0; +#X obj 186 510 *~; +#X obj 306 517 *~; +#X obj 372 468 noise~; +#X obj 372 492 bp~ 3000 10; +#X obj 366 162 abs~; +#X obj 509 158 sig~ 0; +#X obj 467 371 +~; +#X obj 411 210 -~ 0.55; +#X obj 411 231 /~ 0.2; +#X obj 411 252 clip~ 0 1; +#X obj 411 282 *~; +#X obj 411 308 *~ 1000; +#X obj 366 334 +~; +#X obj 366 308 +~ 800; +#X obj 186 536 *~ 0.2; +#X obj 366 282 *~ 800; +#N canvas 568 775 135 226 <~ 0; +#X obj 20 -43 -~; +#X obj 20 27 +~ 1e-37; +#X obj 20 6 clip~ -1e-37 0; +#X obj 20 -88 inlet~; +#X obj 64 -87 inlet~; +#X obj 20 -64 max~; +#X obj 20 -19 *~ -1; +#X obj 20 79 outlet~; +#X obj 20 48 *~ 1e+37; +#X connect 0 0 6 0; +#X connect 1 0 8 0; +#X connect 2 0 1 0; +#X connect 3 0 5 0; +#X connect 4 0 0 1; +#X connect 4 0 5 1; +#X connect 5 0 0 0; +#X connect 6 0 2 0; +#X connect 8 0 7 0; +#X restore 186 367 pd <~ 0; +#N canvas 568 775 135 226 <~ 0; +#X obj 20 -43 -~; +#X obj 20 27 +~ 1e-37; +#X obj 20 6 clip~ -1e-37 0; +#X obj 20 -88 inlet~; +#X obj 64 -87 inlet~; +#X obj 20 -64 max~; +#X obj 20 -19 *~ -1; +#X obj 20 79 outlet~; +#X obj 20 48 *~ 1e+37; +#X connect 0 0 6 0; +#X connect 1 0 8 0; +#X connect 2 0 1 0; +#X connect 3 0 5 0; +#X connect 4 0 0 1; +#X connect 4 0 5 1; +#X connect 5 0 0 0; +#X connect 6 0 2 0; +#X connect 8 0 7 0; +#X restore 482 181 pd <~; +#X obj 186 428 *~; +#X obj 225 345 sig~ 1; +#X obj 186 394 lop~ 10; +#X text 524 393 << band-limited pulse; +#X text 10 367 reed stops when overblown >>; +#X obj 186 460 *~; +#X obj 186 480 *~; +#X text 25 470 exp amplitude response >>; +#X text 537 238 << detune frequency on change of direction; +#X obj 482 236 *~ -300; +#X obj 306 485 *~; +#X obj 306 449 *~ 0.1; +#X text 448 493 << noise simulates non-oscillating airflow when overblown +; +#X obj 186 561 outlet~; +#N canvas 58 1286 407 525 pulse 0; +#X obj 83 340 *~; +#X obj 83 366 *~; +#X obj 31 366 sig~ 1; +#X obj 52 419 /~; +#X obj 67 393 +~; +#X text 116 366 X^2; +#X text 97 396 1+X^2; +#X text 84 421 1/(1+X^2); +#X obj 83 317 osc~; +#X obj 167 320 clip~ 0 999999; +#X obj 52 483 outlet~; +#X text 271 218 << tweak all this; +#X text 25 14 based on F04.waveshaping.pulse.pd; +#X obj 83 84 /~ 2; +#X obj 167 148 -~; +#X obj 167 170 /~ 127; +#X obj 52 452 hip~ 5; +#X obj 167 202 *~; +#X obj 167 232 *~; +#X obj 167 262 *~; +#X obj 167 294 *~ 1000; +#X obj 118 125 sig~ 139; +#X obj 83 58 inlet~; +#N canvas 331 1377 215 174 _ftom 0; +#X obj -482 -776 tabread4~ _ftom; +#X obj -482 -818 /~ 10000; +#X obj -482 -797 *~ 256; +#N canvas 0 23 450 278 (subpatch) 0; +#X array _ftom 256 float 3; +#A 0 0 27.0762 39.0762 46.0958 51.0762 54.9394 58.0958 60.7645 63.0762 +65.1153 66.9394 68.5894 70.0958 71.4815 72.7645 73.9589 75.0762 76.1258 +77.1153 78.0514 78.9394 79.784 80.5894 81.359 82.0958 82.8025 83.4815 +84.1349 84.7645 85.372 85.9589 86.5266 87.0762 87.609 88.1258 88.6276 +89.1153 89.5897 90.0514 90.5011 90.9394 91.3669 91.784 92.1914 92.5894 +92.9785 93.359 93.7313 94.0958 94.4528 94.8025 95.1453 95.4815 95.8113 +96.1349 96.4525 96.7645 97.0709 97.372 97.6679 97.9589 98.2451 98.5266 +98.8036 99.0762 99.3446 99.609 99.8693 100.126 100.379 100.628 100.873 +101.115 101.354 101.59 101.822 102.051 102.278 102.501 102.722 102.939 +103.154 103.367 103.577 103.784 103.989 104.191 104.392 104.589 104.785 +104.978 105.17 105.359 105.546 105.731 105.914 106.096 106.275 106.453 +106.629 106.803 106.975 107.145 107.314 107.482 107.647 107.811 107.974 +108.135 108.294 108.453 108.609 108.764 108.918 109.071 109.222 109.372 +109.521 109.668 109.814 109.959 110.103 110.245 110.386 110.527 110.666 +110.804 110.94 111.076 111.211 111.345 111.477 111.609 111.74 111.869 +111.998 112.126 112.253 112.379 112.504 112.628 112.751 112.873 112.995 +113.115 113.235 113.354 113.472 113.59 113.706 113.822 113.937 114.051 +114.165 114.278 114.39 114.501 114.612 114.722 114.831 114.939 115.047 +115.154 115.261 115.367 115.472 115.577 115.681 115.784 115.887 115.989 +116.09 116.191 116.292 116.392 116.491 116.589 116.688 116.785 116.882 +116.978 117.074 117.17 117.265 117.359 117.453 117.546 117.639 117.731 +117.823 117.915 118.005 118.096 118.186 118.275 118.364 118.453 118.541 +118.629 118.716 118.803 118.889 118.975 119.06 119.145 119.23 119.314 +119.398 119.482 119.565 119.647 119.729 119.811 119.893 119.974 120.055 +120.135 120.215 120.294 120.374 120.453 120.531 120.609 120.687 120.764 +120.842 120.918 120.995 121.071 121.147 121.222 121.297 121.372 121.446 +121.521 121.594 121.668 121.741 121.814 121.887 121.959 122.031 122.103 +122.174 122.245 122.316 122.386 122.457 122.527 122.596 122.666 122.735 +122.804 122.872 122.94 123.008; +#X coords 0 127 256 -12 50 50 1 0 0; +#X restore -546 -793 graph; +#X obj -482 -838 clip~ 0 10000; +#X obj -482 -858 inlet~; +#X obj -482 -755 outlet~; +#X text -567 -722 shoddy temp replacement for ftom~; +#X connect 0 0 6 0; +#X connect 1 0 2 0; +#X connect 2 0 0 0; +#X connect 4 0 1 0; +#X connect 5 0 4 0; +#X restore 182 125 pd _ftom; +#X connect 0 0 1 0; +#X connect 0 0 1 1; +#X connect 1 0 4 1; +#X connect 2 0 3 0; +#X connect 2 0 4 0; +#X connect 3 0 16 0; +#X connect 4 0 3 1; +#X connect 8 0 0 0; +#X connect 9 0 0 1; +#X connect 13 0 8 0; +#X connect 13 0 23 0; +#X connect 14 0 15 0; +#X connect 15 0 17 0; +#X connect 15 0 17 1; +#X connect 16 0 10 0; +#X connect 17 0 18 0; +#X connect 17 0 18 1; +#X connect 18 0 19 0; +#X connect 18 0 19 1; +#X connect 19 0 20 0; +#X connect 20 0 9 0; +#X connect 21 0 14 0; +#X connect 22 0 13 0; +#X connect 23 0 14 1; +#X restore 467 394 pd pulse; +#X obj 366 105 inlet~; +#X text 295 104 airflow >>; +#X text 218 118 ('squeeze pressure'); +#X text 13 20 Sound model of a rubber duckie toy; +#X text 14 51 Hint: use the differential of a continuous signal as +input for a realistic response; +#X text 13 29 ==================================; +#X obj 366 133 lop~ 0.5; +#X text 423 132 << airflow resistance; +#X connect 0 0 14 0; +#X connect 1 0 14 0; +#X connect 2 0 3 0; +#X connect 3 0 1 1; +#X connect 4 0 7 0; +#X connect 4 0 15 0; +#X connect 4 0 29 0; +#X connect 4 0 18 1; +#X connect 4 0 16 0; +#X connect 5 0 17 1; +#X connect 6 0 32 0; +#X connect 7 0 8 0; +#X connect 8 0 9 0; +#X connect 9 0 10 0; +#X connect 9 0 10 1; +#X connect 10 0 11 0; +#X connect 11 0 12 1; +#X connect 12 0 6 0; +#X connect 13 0 12 0; +#X connect 14 0 31 0; +#X connect 15 0 13 0; +#X connect 16 0 20 0; +#X connect 17 0 27 0; +#X connect 18 0 23 0; +#X connect 18 0 23 1; +#X connect 19 0 16 1; +#X connect 20 0 18 0; +#X connect 23 0 24 1; +#X connect 23 0 24 0; +#X connect 24 0 0 0; +#X connect 27 0 6 1; +#X connect 28 0 1 0; +#X connect 29 0 28 1; +#X connect 29 0 28 0; +#X connect 32 0 0 1; +#X connect 33 0 39 0; +#X connect 39 0 4 0; +#X connect 39 0 17 0; +#X restore 39 127 pd duckie; +#X obj 39 77 adc~ 10; +#N canvas 0 22 504 229 differential 0; +#X obj 27 80 rzero~ 1; +#X obj 72 57 sig~ 1; +#X obj 27 152 *~ 44100; +#X obj 72 131 samplerate~; +#X obj 72 110 loadbang; +#X obj 27 25 inlet~; +#X obj 27 190 outlet~; +#X text 84 83 y[n] = x[n] - x[n-1]; +#X text 121 57 <<< heavy currently requires signal input to set coefficient +; +#X text 91 151 <<< multiply by samplerate to get velocity; +#X connect 0 0 2 0; +#X connect 1 0 0 1; +#X connect 2 0 6 0; +#X connect 3 0 2 1; +#X connect 4 0 3 0; +#X connect 5 0 0 0; +#X restore 39 101 pd differential; +#X connect 6 0 0 0; +#X connect 6 0 0 1; +#X connect 7 0 8 0; +#X connect 8 0 6 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/samphold/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,22 @@ +#N canvas 275 504 414 247 10; +#X obj 55 212 dac~ 1 2; +#X obj 55 171 *~ 0.1; +#X obj 55 150 osc~ 440; +#X obj 55 61 noise~; +#X obj 55 128 samphold~; +#X text 51 21 ==================; +#X text 51 11 Sample and hold FM; +#X obj 55 85 lop~ 1; +#X obj 122 107 phasor~ 880; +#X obj 55 107 *~ 1e+06; +#X text 193 199 ---------------------------------; +#X text 193 189 @krighxz / BELA / heavy / 12/2015; +#X text 217 208 beaglert.cc / enzienaudio.com; +#X connect 1 0 0 1; +#X connect 1 0 0 0; +#X connect 2 0 1 0; +#X connect 3 0 7 0; +#X connect 4 0 2 0; +#X connect 7 0 9 0; +#X connect 8 0 4 1; +#X connect 9 0 4 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/simple-fm/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,42 @@ +#N canvas 275 573 409 282 10; +#X obj 37 230 dac~ 1 2; +#X text 175 222 ---------------------------------; +#X obj 37 102 *~ 1000; +#X obj 37 199 *~ 0.1; +#X obj 37 79 adc~ 3; +#X obj 65 125 adc~ 4; +#X obj 94 147 adc~ 5; +#N canvas 81 574 322 252 FMvoice 1; +#X obj 20 174 +~; +#X obj 93 116 osc~; +#X obj 93 157 *~; +#X obj 93 76 *~; +#X obj 158 98 *~; +#X obj 20 225 outlet~; +#X obj 20 200 osc~; +#X obj 20 39 inlet~ freq; +#X obj 108 39 inlet~ harmRatio~; +#X obj 173 69 inlet~ modIndex~; +#X connect 0 0 6 0; +#X connect 1 0 2 0; +#X connect 2 0 0 1; +#X connect 3 0 4 0; +#X connect 3 0 1 0; +#X connect 4 0 2 1; +#X connect 6 0 5 0; +#X connect 7 0 3 0; +#X connect 7 0 0 0; +#X connect 8 0 3 1; +#X connect 9 0 4 1; +#X restore 37 169 pd FMvoice; +#X text 33 22 Simple FM; +#X text 33 32 =========; +#X text 175 212 @krighxz / BELA / heavy / 12/2015; +#X text 199 231 beaglert.cc / enzienaudio.com; +#X connect 2 0 7 0; +#X connect 3 0 0 1; +#X connect 3 0 0 0; +#X connect 4 0 2 0; +#X connect 5 0 7 1; +#X connect 6 0 7 2; +#X connect 7 0 3 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/08-PureData/tableScrubbing/_main.pd Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,35 @@ +#N canvas 503 319 861 473 10; +#N canvas 0 22 450 278 (subpatch) 0; +#X array exampleTable 65238 float 2; +#X coords 0 1 65238 -1 200 140 1 0 0; +#X restore 21 213 graph; +#X obj 243 329 adc~ 1 2 3; +#X obj 300 426 dac~; +#X text 317 264 <<< delete this object before compiling!; +#X obj 300 392 tabread4~ exampleTable; +#X msg 243 218 read -resize rt.wav exampleTable; +#X obj 300 350 lop~ 1; +#X obj 300 371 *~ 65238; +#X obj 243 266 soundfiler; +#X text 489 229 right-click array -> properties -> toggle "save contents" +; +#X text 463 216 <<< after loading a file:; +#X text 17 23 Load sample into table and scrub using analog input; +#X text 17 33 ===================================================; +#X text 362 351 <<< avoid zipper noise; +#X text 362 371 <<< length of sample; +#X text 317 328 <<< analog input 0 (range 0-1); +#X text 631 419 ---------------------------------; +#X text 631 409 @krighxz / BELA / heavy / 12/2015; +#X text 655 428 beaglert.cc / enzienaudio.com; +#X text 30 61 N.B. the patch cannot be bigger than 512kb in size \; +only use this for *very small soundfiles*; +#X text 29 99 You can modify the render.cpp file to load samples into +tables using the Heavy API: https://enzienaudio.com/docs/c.html#api-hv-table +; +#X connect 1 2 6 0; +#X connect 4 0 2 0; +#X connect 4 0 2 1; +#X connect 5 0 8 0; +#X connect 6 0 7 0; +#X connect 7 0 4 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/Junction.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,95 @@ +/* + * + * Excitation Junction for two waveguides + * + * Christian Heinrichs 04/2015 + * + */ + +#include "Junction.h" +#include "../include/Utilities.h" + +Junction::Junction() { + + setFrequency(440); + _dt = 1.0/44100.0; + + // initialize variables + for(int i=0;i<WG_BUFFER_SIZE;i++) { + _buffer_l[i] = 0; + _buffer_r[i] = 0; + } + _excitation = 0; + _lastPlectrumDisplacement = 0; + _readPtr = 0; + +} + +void Junction::update(float excitation, float left, float right) { + + // 1. advance delay buffer read pointer + + if(++_readPtr>=WG_BUFFER_SIZE) + _readPtr=0; + + // 2. add excitation sample into buffer + + _buffer_l[(_readPtr+_delay_l+WG_BUFFER_SIZE)%WG_BUFFER_SIZE] = excitation; + _buffer_r[(_readPtr+_delay_r+WG_BUFFER_SIZE)%WG_BUFFER_SIZE] = excitation; + + // 3. feed right input to left output and vice versa + + _buffer_l[_readPtr] += right; + _buffer_r[_readPtr] += left; + + // 4. store excitation value for later use + _excitation = excitation; + +} + +float Junction::getOutput(int direction) { + + if(direction = 0) + return _buffer_l[_readPtr]; + else + return _buffer_r[_readPtr]; + +} + +float Junction::getExcitationDisplacement() { + + // string displacement and excitation force + // use delayed value to account for excitation position + float in = _buffer_l[(_readPtr+_delay_l+WG_BUFFER_SIZE)%WG_BUFFER_SIZE] + _excitation; + + // integrate total force + float out = 0.00001 * in + 0.99999 * _lastPlectrumDisplacement; + + // store variable for next iteration + _lastPlectrumDisplacement = out; + + // multiply by delta time + return out * _dt; + +} + +void Junction::setPluckPosition(float pluckPos){ + + pluckPos = constrain(pluckPos,0,1); + _delay_l = pluckPos * _periodInSamples; + _delay_r = (1-pluckPos) * _periodInSamples; + +} + +void Junction::setPeriod(float period) { + + _periodInMilliseconds = period; + +} + +void Junction::setFrequency(float frequency) { + + _periodInMilliseconds = 1000.0/frequency; + _periodInSamples = (int)(_periodInMilliseconds * 44.1); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/Junction.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,54 @@ +/* + * + * Excitation Junction for two waveguides + * + * Christian Heinrichs 04/2015 + * + */ + +#ifndef JUNCTION_H_ +#define JUNCTION_H_ + +#include <cmath> + +#ifndef WG_BUFFER_SIZE +#define WG_BUFFER_SIZE 4096 +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +class Junction +{ + +public: + + Junction(); + void setup(); + void update(float excitation, float left, float right); + float getOutput(int direction); + float getExcitationDisplacement(); + void setFrequency(float frequency); + void setPeriod(float periodInMs); + void setPluckPosition(float pluckPos); + +private: + + double _dt; + float _periodInMilliseconds; + int _periodInSamples; + + int _delay_l; + int _delay_r; + + float _buffer_l[WG_BUFFER_SIZE]; + float _buffer_r[WG_BUFFER_SIZE]; + int _readPtr; + + float _excitation; + float _lastPlectrumDisplacement; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/MassSpringDamper.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,59 @@ +/* + * + * Simple 1-Dimensional Mass Spring Damper + * + * Christian Heinrichs 04/2015 + * + */ + +#include "MassSpringDamper.h" + +MassSpringDamper::MassSpringDamper(float mass, float spring, float damp) { + + _dt = 1.0/44100.0; + _mass = mass; + _spring = spring; + _damp = damp; + _position = 0; + _velocity = 0; + +} + +void MassSpringDamper::setup() { + +} + +double MassSpringDamper::update(float inForce) { + + // 1. calculate spring/damper forces using current position and velocity + + double out = (_position * (double)_spring * -1) + (_velocity * (double)_damp * -1); + + // 2. apply external force + + out += inForce; + + // 3. derive acceleration (a = f/m) + + out /= (double)_mass; + + // 4. derive velocity (v = a*dt) + + out *= _dt; + + // 5. apply previous velocity + + out += _velocity; + + // 6. save current velocity state for next iteration + + _velocity = out; + + // 7. derive new position (x[n] = x[n-1] + v[n]) and save for next iteration + + out += _position; + _position = out; + + return out; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/MassSpringDamper.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,32 @@ +/* + * + * Simple 1-Dimensional Mass Spring Damper + * + * Christian Heinrichs 04/2015 + * + */ + +#ifndef MASSSPRINGDAMPER_H_ +#define MASSSPRINGDAMPER_H_ + +class MassSpringDamper +{ + +public: + + MassSpringDamper(float mass, float spring, float damp); + void setup(); + double update(float inForce); + +private: + + double _dt; + float _mass; + float _spring; + float _damp; + double _position; + double _velocity; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/Plectrum.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,61 @@ +/* + * + * Plectrum model for touching and plucking strings + * + * Christian Heinrichs 04/2015 + * + * [inspired by E. Berdahl's pluck~ abstraction for the FireFader] + * + */ + +#include "Plectrum.h" + +#include "../include/Utilities.h" +#include <cmath> +#include <stdio.h> +#include <cstdlib> + +Plectrum::Plectrum() { + + _contact = 0; + _lastDistance = 0; + +} + +void Plectrum::setup(float spring, float damp, float hyst) { + + _spring = spring; + _damp = damp; + _hyst = hyst; + +} + +float Plectrum::update(float position, float stringPosition) { + + float distance = position - stringPosition; + + // Calculate spring/damp forces based on distance to string + + float springOut = distance * _spring; + + float dampOut = (distance - _lastDistance) * 44100; + + float out = springOut+dampOut; + + // If distance crosses zero, enable contact + + if((distance>0 && _lastDistance<=0)||(distance<0 && _lastDistance>=0)) + _contact = 1; + + // If distance exceeds hysteresis threshold, jump to zero (i.e. 'pluck') + + if(fabs(distance)>_hyst) + _contact = 0; + + // FIXME: contact doesn't switch back to zero if distance goes back in original direction + + _lastDistance = distance; + + return out * _contact; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/Plectrum.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,35 @@ +/* + * + * Plectrum model for touching and plucking strings + * + * [inspired by E. Berdahl's pluck~ abstraction for the FireFader] + * + */ + +#ifndef PLECTRUM_H_ +#define PLECTRUM_H_ + +class Plectrum +{ + +public: + + Plectrum(); + void setup(float spring, float damp, float hyst); + float update(float position, float stringPosition); + +private: + + double _dt; + float _spring; + float _damp; + double _position; + double _velocity; + float _hyst; + float _lastDistance; + int _contact; + +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/String.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,91 @@ +/* + * + * 1-D string consisting of two waveguides and junction + * + * Christian Heinrichs 04/2015 + * + */ + +#include "String.h" +#include "Junction.h" +#include "Waveguide.h" + +#include "../include/Utilities.h" +#include <rtdk.h> +#include <cmath> +#include <stdio.h> +#include <cstdlib> + +String::String(){ + + wg_l = Waveguide(); + wg_r = Waveguide(); + junction = Junction(); + + junction.setPluckPosition(0.5); + + _previous_l = 0; + _previous_r = 0; + +} + +float String::update(float in) { + + // 1. send excitation signal and previous waveguide outputs into junction + + junction.update(in,_previous_l,_previous_r); + + // 2. save new waveguide outputs for next iteration + + _previous_l = wg_l.update(junction.getOutput(0)); + _previous_r = wg_r.update(junction.getOutput(1)); + + // 3. use right waveguide as output + + //rt_printf("BANANA %f ",_readPtr); + //rt_printf("%f\n",_previous_r); + + return _previous_r; +} + +float String::getPlectrumDisplacement() { + + return junction.getExcitationDisplacement(); + +} + +void String::setPluckPosition(float pluckPos){ + + junction.setPluckPosition(pluckPos); + +} + +void String::setGlobalPosition(float pos) { + + _globalPosition = pos; + +} + +float String::getGlobalPosition() { + + return _globalPosition; + +} + +void String::setMidinote(float midinote) { + + float frequency = 440.0f*(float)powf(2,(midinote-57)/12.0f); + + junction.setFrequency(frequency); + wg_l.setFrequency(frequency); + wg_r.setFrequency(frequency); + +} + +void String::setFrequency(float frequency) { + + junction.setFrequency(frequency); + wg_l.setFrequency(frequency); + wg_r.setFrequency(frequency); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/String.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,45 @@ +/* + * + * 1-D string consisting of two waveguides and junction + * + * Christian Heinrichs 04/2015 + * + */ + +#ifndef STRING_H_ +#define STRING_H_ + +#include <cmath> +#include "Junction.h" +#include "Waveguide.h" + +class String +{ + +public: + + String(); + float update(float in); + + float getPlectrumDisplacement(); + void setMidinote(float midinote); + void setFrequency(float frequency); + void setPeriod(float periodInMs); + void setPluckPosition(float pluckPos); + void setGlobalPosition(float pos); + float getGlobalPosition(); + +private: + + float _previous_l; + float _previous_r; + + float _globalPosition; + + Waveguide wg_l; + Waveguide wg_r; + Junction junction; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/Waveguide.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,128 @@ +/* + * + * Simple 1-Dimensional Waveguide + * + */ + +#include "Waveguide.h" +#include "../include/Utilities.h" +#include <rtdk.h> +#include <cmath> +#include <stdio.h> +#include <cstdlib> + +#define DECAY 0.995//0.999 +#define DAMPING 0.01//0.05 + +// TODO: make damping and decay parametrisable + +Waveguide::Waveguide() { + + // initialize variables + a1_lp = 0; + a2_lp = 0; + b0_lp = 0; + b1_lp = 0; + b2_lp = 0; + _dt = 1.0/44100.0; + setFrequency(440); + updateFilterCoeffs(8000); + _filterReadPtr=0; + for(int i=0;i<FILTER_BUFFER_SIZE;i++) { + _filterBuffer_x[i] = 0; + _filterBuffer_y[i] = 0; + } + for(int i=0;i<WG_BUFFER_SIZE;i++) { + _buffer[i] = 0; + } + _lastX = 0; + _lastY = 0; + _readPtr = 0; + +} + +void Waveguide::setup() { + +} + +float Waveguide::update(float in) { + + // 1. advance delay buffer read pointer + + if(++_readPtr>=WG_BUFFER_SIZE) + _readPtr=0; + + // 2. write input into buffer + + _buffer[_readPtr] = in; + + // 3. read delayed sample from buffer + + float out = _buffer[(_readPtr-_periodInSamples+WG_BUFFER_SIZE)%WG_BUFFER_SIZE]; + + // 4. apply damping (low-pass) filter to output + + if(++_filterReadPtr>=FILTER_BUFFER_SIZE) + _filterReadPtr=0; + + out = b0_lp*out + + b1_lp*_filterBuffer_x[(_filterReadPtr-1+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] + + b2_lp*_filterBuffer_x[(_filterReadPtr-2+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] - + a1_lp*_filterBuffer_y[(_filterReadPtr-1+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] - + a2_lp*_filterBuffer_y[(_filterReadPtr-2+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE]; + + // 5. Simple high-pass filter to block DC-offset + // y[n] = x[n] - x[n-1] + a * y[n-1] + float gain = 0.9999; + float temp = out; + out = out - _lastX + gain * _lastY; + _lastY = out; + _lastX = temp; + + // 6. Apply intensity damping + out *= DECAY; + + _filterBuffer_x[_filterReadPtr] = in; + _filterBuffer_y[_filterReadPtr] = out; + + return out; + +} + +void Waveguide::setFrequency(float frequency) { + + // NB: currently no interpolation, so may not be ideal for dynamically changing waveguide frequency + _periodInMilliseconds = 1000.0/frequency; + _periodInSamples = (int)(_periodInMilliseconds * 44.1); + +} + +void Waveguide::updateFilterCoeffs(float frequency) { + + // FIXME: Butterworth filter doesn't work very well, + // using simple FIR in the meantime + + a1_lp = 0; + a2_lp = 0; + b0_lp = 1.0 - DAMPING; + b1_lp = DAMPING; + b2_lp = 0; + + /* + // 'w' for sake of resembling lower-case 'omega' + float w = 2.0 * M_PI * frequency; + float t = _dt; + // The Q for a 2nd-order Butterworth is sqrt(2)/2 + float q = 0.707;//sqrt(2.0)/2.0; + + // low-pass filter coefficients + float a0_lp = w*w*t*t + 2*(w/q)*t + 4.0; + float k = 1.0/a0_lp; + a1_lp = (2.0*w*w*t*t - 8.0) * k; + a2_lp = (4.0 - (w/q)*2.0*t + w*w*t*t) * k; + b0_lp = (w*w*t*t) * k; + b1_lp = (2.0*w*w*t*t) * k; + b2_lp = (w*w*t*t) * k; + */ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/Waveguide.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,57 @@ +/* + * + * Simple 1-Dimensional Waveguide + * + * Christian Heinrichs 04/2015 + * + */ + +#ifndef WAVEGUIDE_H_ +#define WAVEGUIDE_H_ + +#include <cmath> + +#ifndef WG_BUFFER_SIZE +#define WG_BUFFER_SIZE 4096 +#endif + +#ifndef FILTER_BUFFER_SIZE +#define FILTER_BUFFER_SIZE 4 +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +class Waveguide +{ + +public: + + Waveguide(); + void setup(); + float update(float in); + void updateFilterCoeffs(float frequency); + void setFrequency(float frequency); + +private: + + double _dt; + float _periodInMilliseconds; + int _periodInSamples; + + float _buffer[WG_BUFFER_SIZE]; + int _readPtr; + + float _filterBuffer_x[FILTER_BUFFER_SIZE]; + float _filterBuffer_y[FILTER_BUFFER_SIZE]; + float _hipBuffer_x[FILTER_BUFFER_SIZE]; + float _hipBuffer_y[FILTER_BUFFER_SIZE]; + int _filterReadPtr; + + float b0_lp,b1_lp,b2_lp,a1_lp, a2_lp; + float _lastY,_lastX; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/airharp/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,211 @@ +/* + * AIR-HARP + * Physically modelled strings using waveguide junctions and mass-spring-dampers + * + * render.cpp + * + * Christian Heinrichs 04/2015 + * + */ + + +#include "MassSpringDamper.h" +#include "String.h" +#include "Plectrum.h" + +#include <Bela.h> +#include <cmath> +#include <stdio.h> +#include <cstdlib> +#include <rtdk.h> + +#define ACCEL_BUF_SIZE 8 +#define NUMBER_OF_STRINGS 9 + +// PENTATONIC SCALE +float gMidinotes[NUMBER_OF_STRINGS] = {40,45,50,55,57,60,62,64,67}; + +float gInverseSampleRate; + +float out_gain = 5.0; + +int accelPin_x = 0; +int accelPin_y = 1; +int accelPin_z = 2; + +MassSpringDamper msd = MassSpringDamper(1,0.1,10);// (10,0.001,10); +String strings[NUMBER_OF_STRINGS]; +Plectrum plectrums[NUMBER_OF_STRINGS]; + +float gPlectrumDisplacement = 0; + +float gAccel_x[ACCEL_BUF_SIZE] = {0}; +int gAccelReadPtr = 0; + +// DC BLOCK BUTTERWORTH + +// Coefficients for 100hz cut-off +float a0_l = 0.9899759179893742; +float a1_l = -1.9799518359787485; +float a2_l = 0.9899759179893742; +float a3_l = -1.979851353142371; +float a4_l = 0.9800523188151258; + +float a0_r = a0_l; +float a1_r = a1_l; +float a2_r = a2_l; +float a3_r = a3_l; +float a4_r = a4_l; + +float x1_l = 0; +float x2_l = 0; +float y1_l = 0; +float y2_l = 0; + +float x1_r = 0; +float x2_r = 0; +float y1_r = 0; +float y2_r = 0; + + +bool setup(BelaContext *context, void *userData) +{ + + gInverseSampleRate = 1.0 / context->audioSampleRate; + + // initialise strings & plectrums + for(int i=0;i<NUMBER_OF_STRINGS;i++) { + + plectrums[i] = Plectrum(); + plectrums[i].setup(250,0.25,0.05); + + strings[i] = String(); + strings[i].setMidinote(gMidinotes[i]); + + float spacing = 2.0 / (NUMBER_OF_STRINGS+1); + + strings[i].setGlobalPosition( -1 + spacing*(i+1) ); + + rt_printf("STRING %d // midinote: %f position: %f\n",i,gMidinotes[i],( -1 + spacing*(i+1) )); + + } + + return true; +} + +void render(BelaContext *context, void *userData) +{ + + float lastAccel = 0; + + for(int n = 0; n < context->audioFrames; n++) { + + /* + * + * ACCELEROMETER DATA + * + */ + + // Read accelerometer data from analog input + float accel_x = 0; + if(n%2) { + accel_x = (float)context->analogIn[(n/2)*8+accelPin_x] * 2 - 1; // 15800 - 28300 - 41500 + lastAccel = accel_x; + } else { + // grab previous value if !n%2 + accel_x = lastAccel; + } + + // Dead-zone avoids noise when box is lying horizontally on a surface + + float accelDeadZone = 0.1; + + if(accel_x <= accelDeadZone && accel_x >= -accelDeadZone) + accel_x = 0; + + // Perform smoothing (moving average) on acceleration value + if(++gAccelReadPtr >= ACCEL_BUF_SIZE) + gAccelReadPtr = 0; + gAccel_x[gAccelReadPtr] = accel_x; + float gravity = 0; + for(int i=0;i<ACCEL_BUF_SIZE;i++) { + gravity = gAccel_x[(gAccelReadPtr-i+ACCEL_BUF_SIZE)%ACCEL_BUF_SIZE]; + } + gravity /= ACCEL_BUF_SIZE; + + /* + * + * PHYSICS SIMULATION + * + */ + + // The horizontal force (which can be gravity if box is tipped on its side) + // is used as the input to a Mass-Spring-Damper model + // Plectrum displacement (i.e. when interacting with string) is included + float massPosition = (float)msd.update(gravity - gPlectrumDisplacement); + + float out_l = 0; + float out_r = 0; + // Use this parameter to quickly adjust output gain + float gain = 0.0015; // 0.0015 is a good value or 12 strings + gPlectrumDisplacement = 0; + + for(int s=0;s<NUMBER_OF_STRINGS;s++) { + + float stringPosition = strings[s].getGlobalPosition(); + + float plectrumForce = plectrums[s].update(massPosition, stringPosition); + gPlectrumDisplacement += strings[s].getPlectrumDisplacement(); + + // calculate panning based on string position (-1->left / 1->right) + float panRight = map(stringPosition,1,-1,0.1,1); + float panLeft = map(stringPosition,-1,1,0.1,1); + panRight *= panRight; + panLeft *= panLeft; + + float out = strings[s].update(plectrumForce)*gain; + + out_l += out*panLeft; + out_r += out*panRight; + + } + + // APPLY DC-BLOCK FILTER TO OUTPUTS + + // LEFT CHANNEL + float temp_in = out_l; + /* compute result */ + out_l = a0_l * out_l + a1_l * x1_l + a2_l * x2_l - a3_l * y1_l - a4_l * y2_l; + /* shift x1 to x2, sample to x1 */ + x2_l = x1_l; + x1_l = temp_in; + /* shift y1 to y2, result to y1 */ + y2_l = y1_l; + y1_l = out_l; + + // RIGHT CHANNEL + temp_in = out_r; + /* compute result */ + out_r = a0_r * out_r + a1_r * x1_r + a2_r * x2_r - a3_r * y1_r - a4_r * y2_r; + /* shift x1 to x2, sample to x1 */ + x2_r = x1_r; + x1_r = temp_in; + /* shift y1 to y2, result to y1 */ + y2_r = y1_r; + y1_r = out_r; + + context->audioOut[n * context->audioChannels + 1] = out_l * out_gain; + context->audioOut[n * context->audioChannels + 0] = out_r * out_gain; + + } + +} + + +// cleanup_render() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in initialise_render(). + +void cleanup(BelaContext *context, void *userData) +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/ADSR.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,76 @@ +// +// ADSR.cpp +// +// Created by Nigel Redmon on 12/18/12. +// EarLevel Engineering: earlevel.com +// Copyright 2012 Nigel Redmon +// +// For a complete explanation of the ADSR envelope generator and code, +// read the series of articles by the author, starting here: +// http://www.earlevel.com/main/2013/06/01/envelope-generators/ +// +// License: +// +// This source code is provided as is, without warranty. +// You may copy and distribute verbatim copies of this document. +// You may modify and use this source code to create binary code for your own purposes, free or commercial. +// + +#include "ADSR.h" +#include <math.h> + + +ADSR::ADSR(void) { + reset(); + setAttackRate(0); + setDecayRate(0); + setReleaseRate(0); + setSustainLevel(1.0); + setTargetRatioA(0.3); + setTargetRatioDR(0.0001); +} + +ADSR::~ADSR(void) { +} + +void ADSR::setAttackRate(float rate) { + attackRate = rate; + attackCoef = calcCoef(rate, targetRatioA); + attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef); +} + +void ADSR::setDecayRate(float rate) { + decayRate = rate; + decayCoef = calcCoef(rate, targetRatioDR); + decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); +} + +void ADSR::setReleaseRate(float rate) { + releaseRate = rate; + releaseCoef = calcCoef(rate, targetRatioDR); + releaseBase = -targetRatioDR * (1.0 - releaseCoef); +} + +float ADSR::calcCoef(float rate, float targetRatio) { + return exp(-log((1.0 + targetRatio) / targetRatio) / rate); +} + +void ADSR::setSustainLevel(float level) { + sustainLevel = level; + decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); +} + +void ADSR::setTargetRatioA(float targetRatio) { + if (targetRatio < 0.000000001) + targetRatio = 0.000000001; // -180 dB + targetRatioA = targetRatio; + attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef); +} + +void ADSR::setTargetRatioDR(float targetRatio) { + if (targetRatio < 0.000000001) + targetRatio = 0.000000001; // -180 dB + targetRatioDR = targetRatio; + decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); + releaseBase = -targetRatioDR * (1.0 - releaseCoef); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/ADSR.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,137 @@ +// +// ADRS.h +// +// Created by Nigel Redmon on 12/18/12. +// EarLevel Engineering: earlevel.com +// Copyright 2012 Nigel Redmon +// +// For a complete explanation of the ADSR envelope generator and code, +// read the series of articles by the author, starting here: +// http://www.earlevel.com/main/2013/06/01/envelope-generators/ +// +// License: +// +// This source code is provided as is, without warranty. +// You may copy and distribute verbatim copies of this document. +// You may modify and use this source code to create binary code for your own purposes, free or commercial. +// + +#ifndef ADRS_h +#define ADRS_h + +#include <stdio.h> +#include <string> + +using namespace std; + +enum envState { + env_idle = 0, + env_attack, + env_decay, + env_sustain, + env_release +}; + +class ADSR { +public: + ADSR(void); + ~ADSR(void); + float process(void); + float process(int sampleCount); + float getOutput(void); + int getState(void); + void gate(int on); + void setAttackRate(float rate); + void setDecayRate(float rate); + void setReleaseRate(float rate); + void setSustainLevel(float level); + void setTargetRatioA(float targetRatio); + void setTargetRatioDR(float targetRatio); + void reset(void); + +protected: + int state; + float output; + float attackRate; + float decayRate; + float releaseRate; + float attackCoef; + float decayCoef; + float releaseCoef; + float sustainLevel; + float targetRatioA; + float targetRatioDR; + float attackBase; + float decayBase; + float releaseBase; + string name; + float calcCoef(float rate, float targetRatio); +}; + +inline float ADSR::process() { + switch (state) { + case env_idle: + break; + case env_attack: + output = attackBase + output * attackCoef; + if (output >= 1.0) { + output = 1.0; + state = env_decay; + } + break; + case env_decay: + output = decayBase + output * decayCoef; + if (output <= sustainLevel) { + output = sustainLevel; + state = env_sustain; + } + break; + case env_sustain: + break; + case env_release: + output = releaseBase + output * releaseCoef; + if (output <= 0.0) { + output = 0.0; + state = env_idle; + } + break; + } + return output; +} + +inline float ADSR::process(int sampleCount) +{ + float retVal = 0; + + if(state != env_idle) + { + for(int i=0; i<sampleCount; i++) + retVal = process(); + } + + return retVal; +} + +inline void ADSR::gate(int gate) { + + if (gate) + state = env_attack; + else if (state != env_idle) + state = env_release; +} + +inline int ADSR::getState() { + return state; +} + +inline void ADSR::reset() { + state = env_idle; + output = 0.0; +} + +inline float ADSR::getOutput() { + return output; +} + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/AnalogInput.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,163 @@ +/* + * AnalogInput.cpp + * + * Created on: Oct 17, 2013 + * Author: Victor Zappi + */ + + +#include "AnalogInput.h" + +using namespace std; + + +AnalogInput::AnalogInput() +{ + ActivateAnalogHnd = NULL; + activateAnalogPath = ""; + analogIsSet = false; + + AnalogInHnd = NULL; + analogInPath = ""; + helperNumFound = false; + + // support var for init + // these are fixed for BBB + startPath = "/sys/devices/bone_capemgr.*/slots"; + readPath = ""; + + buffer = (char*) malloc (sizeof(char)*lSize); // reading buffer + + verbose = false; +} + + +AnalogInput::~AnalogInput() +{ + free(buffer); +} + +int AnalogInput::initAnalogInputs() +{ + if(analogIsSet) + { + if(verbose) + cout << "Fine, but Analog Input already active..."<< endl; + return 0; + } + + // title + if(verbose) + cout << "Init Analog Input"<< endl; + + + // first: activate analog pins on cape manager + // cape-bone-iio > /sys/devices/bone_capemgr.*/slots + + // we have to look for the semi-random number the BBB has initialized the bone_capemgr with [value of *] + // to reach /slots and set cape-bone-iio. + // to do so, we use glob lib, which translates wildcards [*] into all the values found in paths + + + glob( startPath.c_str(), 0, NULL, &globbuf); + + if(globbuf.gl_pathc >0) + { + if (globbuf.gl_pathc == 1 ) + { + activateAnalogPath = globbuf.gl_pathv[0]; + + // check if file is existing + if((ActivateAnalogHnd = fopen(activateAnalogPath.c_str(), "r+")) != NULL) + { + // we found that current capemgr num + + fwrite("cape-bone-iio", sizeof(char), 13, ActivateAnalogHnd); // activate pins + + analogIsSet = true; + + if(verbose) + cout << "Analog Pins activated via cape-bone-iio at path " << activateAnalogPath << endl; + + fclose(ActivateAnalogHnd); // close file + } + } + //else + //printf("toomany", ); + } + + globfree(&globbuf); // self freeing + + + if(!analogIsSet) + { + cout << "cannot find bone_capemgr" << endl; + cout << "------Init failed------" << endl; + return 1; + } + + + // build read path + startPath = "/sys/devices/ocp.2/helper.*"; + + glob( startPath.c_str(), 0, NULL, &globbuf); + + if(globbuf.gl_pathc >0) + { + if (globbuf.gl_pathc == 1 ) + { + analogInPath = globbuf.gl_pathv[0] + (string)"/AIN"; + } + else + cout << "Too many analog inputs with this name! [I am puzzled...]" << endl; + } + else + cout << "Cannot find analog input dir...puzzled" << endl; + + + return 0; +} + + +int AnalogInput::read(int index) +{ + // convert int index into string + stringstream ss; + ss << index; + + readPath = analogInPath + ss.str(); // create pin0 file path + + + // check if file is existing + if((AnalogInHnd = fopen(readPath.c_str(), "rb")) != NULL) + { + // we found that current helper num + + // prepare read buffer to reading + fseek (AnalogInHnd , 0 , SEEK_END); + lSize = ftell (AnalogInHnd); + rewind (AnalogInHnd); + + result = fread (buffer, 1, lSize, AnalogInHnd); + + fclose(AnalogInHnd); // close file + + helperNumFound = true; + + //cout << "Analog Pins can be read at path " << analogInPath << endl; + //cout << "Test reading of Pin0 gives: " << buffer << endl; + } + + if(!helperNumFound) + { + cout << "cannot find helper" << endl; + cout << "------Analog Read failed------" << endl; + return -1; + } + + return atoi(buffer); + +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/AnalogInput.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,55 @@ +/* + * AnalogInput.h + * + * Created on: Oct 17, 2013 + * Author: Victor Zappi + */ + +#ifndef ANALOGINPUT_H_ +#define ANALOGINPUT_H_ + +#include <iostream> +#include <sstream> +#include <stdio.h> +#include <stdlib.h> +#include <glob.h> + +using namespace std; + +class AnalogInput +{ +private: + FILE *ActivateAnalogHnd; + string activateAnalogPath; + bool analogIsSet; + + FILE *AnalogInHnd; + string analogInPath; + bool helperNumFound; + + // suport var for init + string startPath; + string readPath; + + glob_t globbuf; + + // support vars for pin reading + long lSize; + char * buffer; + size_t result; + + bool verbose; + +public: + AnalogInput(); + ~AnalogInput(); + + int initAnalogInputs(); + int read(int index); + +}; + + + + +#endif /* ANALOGINPUT_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/Biquad.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,169 @@ +// +// Biquad.cpp +// +// Created by Nigel Redmon on 11/24/12 +// EarLevel Engineering: earlevel.com +// Copyright 2012 Nigel Redmon +// +// For a complete explanation of the Biquad code: +// http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ +// +// License: +// +// This source code is provided as is, without warranty. +// You may copy and distribute verbatim copies of this document. +// You may modify and use this source code to create binary code +// for your own purposes, free or commercial. +// + +#include <math.h> +#include "Biquad.h" +#include <iostream> + +Biquad::Biquad() { + type = bq_type_lowpass; + a0 = 1.0; + a1 = a2 = b1 = b2 = 0.0; + Fc = 0.50; + Q = 0.707; + peakGain = 0.0; + z1 = z2 = 0.0; +} + +Biquad::Biquad(int type, double Fc, double Q, double peakGainDB) { + setBiquad(type, Fc, Q, peakGainDB); + z1 = z2 = 0.0; +} + +Biquad::~Biquad() { +} + +void Biquad::setType(int type) { + this->type = type; + calcBiquad(); +} + +void Biquad::setQ(double Q) { + this->Q = Q; + calcBiquad(); +} + +void Biquad::setFc(double Fc) { + this->Fc = Fc; + calcBiquad(); +} + +void Biquad::setPeakGain(double peakGainDB) { + this->peakGain = peakGainDB; + calcBiquad(); +} + +void Biquad::setBiquad(int type, double Fc, double Q, double peakGainDB) { + this->type = type; + this->Q = Q; + this->Fc = Fc; + startFc = Fc; + startQ = Q; + startPeakGain = peakGainDB; + setPeakGain(peakGainDB); +} + +void Biquad::calcBiquad(void) { + double norm; + double V = pow(10, fabs(peakGain) / 20.0); + double K = tan(M_PI * Fc); + switch (this->type) { + case bq_type_lowpass: + norm = 1 / (1 + K / Q + K * K); + a0 = K * K * norm; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_highpass: + norm = 1 / (1 + K / Q + K * K); + a0 = 1 * norm; + a1 = -2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_bandpass: + norm = 1 / (1 + K / Q + K * K); + a0 = K / Q * norm; + a1 = 0; + a2 = -a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_notch: + norm = 1 / (1 + K / Q + K * K); + a0 = (1 + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = a0; + b1 = a1; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_peak: + if (peakGain >= 0) { // boost + norm = 1 / (1 + 1/Q * K + K * K); + a0 = (1 + V/Q * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - V/Q * K + K * K) * norm; + b1 = a1; + b2 = (1 - 1/Q * K + K * K) * norm; + } + else { // cut + norm = 1 / (1 + V/Q * K + K * K); + a0 = (1 + 1/Q * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - 1/Q * K + K * K) * norm; + b1 = a1; + b2 = (1 - V/Q * K + K * K) * norm; + } + break; + case bq_type_lowshelf: + if (peakGain >= 0) { // boost + norm = 1 / (1 + sqrt(2) * K + K * K); + a0 = (1 + sqrt(2*V) * K + V * K * K) * norm; + a1 = 2 * (V * K * K - 1) * norm; + a2 = (1 - sqrt(2*V) * K + V * K * K) * norm; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - sqrt(2) * K + K * K) * norm; + } + else { // cut + norm = 1 / (1 + sqrt(2*V) * K + V * K * K); + a0 = (1 + sqrt(2) * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - sqrt(2) * K + K * K) * norm; + b1 = 2 * (V * K * K - 1) * norm; + b2 = (1 - sqrt(2*V) * K + V * K * K) * norm; + } + break; + case bq_type_highshelf: + if (peakGain >= 0) { // boost + norm = 1 / (1 + sqrt(2) * K + K * K); + a0 = (V + sqrt(2*V) * K + K * K) * norm; + a1 = 2 * (K * K - V) * norm; + a2 = (V - sqrt(2*V) * K + K * K) * norm; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - sqrt(2) * K + K * K) * norm; + } + else { // cut + norm = 1 / (V + sqrt(2*V) * K + K * K); + a0 = (1 + sqrt(2) * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - sqrt(2) * K + K * K) * norm; + b1 = 2 * (K * K - V) * norm; + b2 = (V - sqrt(2*V) * K + K * K) * norm; + } + break; + } + + return; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/Biquad.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,99 @@ +// +// Biquad.h +// +// Created by Nigel Redmon on 11/24/12 +// EarLevel Engineering: earlevel.com +// Copyright 2012 Nigel Redmon +// +// For a complete explanation of the Biquad code: +// http://www.earlevel.com/main/2012/11/25/biquad-c-source-code/ +// +// License: +// +// This source code is provided as is, without warranty. +// You may copy and distribute verbatim copies of this document. +// You may modify and use this source code to create binary code +// for your own purposes, free or commercial. +// + +#ifndef Biquad_h +#define Biquad_h + +enum { + bq_type_lowpass = 0, + bq_type_highpass, + bq_type_bandpass, + bq_type_notch, + bq_type_peak, + bq_type_lowshelf, + bq_type_highshelf +}; + +class Biquad { +public: + Biquad(); + Biquad(int type, double Fc, double Q, double peakGainDB); + ~Biquad(); + void setType(int type); + void setQ(double Q); + void setFc(double Fc); + void setPeakGain(double peakGainDB); + void setBiquad(int type, double Fc, double Q, double peakGain); + float process(float in); + + double getQ(); + double getFc(); + double getPeakGain(); + + double getStartingQ(); + double getStartingFc(); + double getStartingPeakGain(); + +protected: + void calcBiquad(void); + + int type; + double a0, a1, a2, b1, b2; + double Fc, Q, peakGain; + double startFc, startQ, startPeakGain; + double z1, z2; +}; + +inline double Biquad::getQ() +{ + return Q; +} + +inline double Biquad::getFc() +{ + return Fc; +} + +inline double Biquad::getPeakGain() +{ + return peakGain; +} + +inline double Biquad::getStartingQ() +{ + return startQ; +} + +inline double Biquad::getStartingFc() +{ + return startFc; +} + +inline double Biquad::getStartingPeakGain() +{ + return startPeakGain; +} + +inline float Biquad::process(float in) { + double out = in * a0 + z1; + z1 = in * a1 + z2 - b1 * out; + z2 = in * a2 - b2 * out; + return out; +} + +#endif // Biquad_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/DBoxSynth.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,35 @@ +/* + * SimpleSynth.h + * + * Created on: Oct 22, 2013 + * Author: Victor Zappi + */ + +#ifndef DBOXSYNTH_H_ +#define DBOXSYNTH_H_ + +#include <iostream> +#include <string> +#include <stdio.h> +#include <stdlib.h> + +#include "Synth.h" + + +class DBoxSynth : public Synth +{ +public: + DBoxSynth(unsigned int rate, unsigned long buffer_size); + double getSample(); + double *getBlock(int block_size); + + +private: + Sampler *smp; + +}; + + + + +#endif /* DBOXSYNTH_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/DboxSensors.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,157 @@ +/* + * DboxSensors.cpp + * + * Created on: May 19, 2014 + * Author: Victor Zappi + */ + + +#include "DboxSensors.h" +#include "config.h" + +using namespace std; + + + +int DboxSensors::initSensors(int tk0_bus, int tk0_address, int tk1_bus, int tk1_address, int tk_file, int fsr_pin, int fsrmax, int sensorTypeToUse, int gpio_0, int gpio_1) +{ + sensorType = sensorTypeToUse; + // init first touch key on i2c bus + if(tk0_address >= 0) { + if(TK0.initI2C_RW(tk0_bus, tk0_address, tk_file)>0) + return 1; + if(TK0.initTouchKey(sensorType)>0) + return 2; + } + + // init second touch key on i2c bus + if(tk1_address >= 0) { + if(TK1.initI2C_RW(tk1_bus, tk1_address, tk_file)>0) + return 1; + if(TK1.initTouchKey(sensorType)>0) + return 2; + } + + // init fsr on analog input pin + fsr_pinNum = fsr_pin; + fsr_max = fsrmax; + + if(FSR.initAnalogInputs()>0) + return 3; + + gpio[0] = gpio_0; + if(gpio[0]!=-1) + { + fdDi[0] = gpio_export(gpio[0]); + if(fdDi[0] == -1) + return 4; + } + digitalIn[0] = 1; + + return 0; +} + + +int DboxSensors::readSensors() +{ + // write data into first touch key + if(TK0.ready()) { + if(TK0.readI2C()>0) + return 1; + + // retrieve data from first touch key + tk0_touchCnt = TK0.getTouchCount(); + } + else + tk0_touchCnt = 0; + + // write data into second touch key + if(TK1.ready()) { + if(TK1.readI2C()>0) + return 1; + // retrieve data from second touch key + tk1_touchCnt = TK1.getTouchCount(); + } + else + tk1_touchCnt = 0; + + + int max = 3; + if(sensorType != kSensorTypeTouchKey) + max = 5; + // if touches detected on main touch key + if(tk0_touchCnt == 0 && tk1_touchCnt == 0) + resetSensorsData(); + else + { + for(int i=0; i<max; i++) + { + tk0_touchPosX[i] = TK0.getSliderPosition()[i]; + tk0_touchSize[i] = TK0.getSlidersize()[i]; + + tk1_touchPosX[i] = TK1.getSliderPosition()[i]; + tk1_touchSize[i] = TK1.getSlidersize()[i]; + } + tk0_touchPosY = TK0.getSliderPositionH(); + tk1_touchPosY = TK1.getSliderPositionH(); + fsr_read = (double)FSR.read(fsr_pinNum); + } + + if(gpio[0]!=-1) + { + if(gpio_read(fdDi[0], &digitalIn[0])==-1) + return 1; + } + + return 0; +} + + + +DboxSensors::DboxSensors() +{ + resetSensorsData(); +} + + + +DboxSensors::~DboxSensors() +{ + if(gpio[0]!=-1) + gpio_dismiss(fdDi[0], gpio[0]); +} + + + +//-------------------------------------------------------------------------------------------------------- +// private methods +//-------------------------------------------------------------------------------------------------------- + +// idle values +void DboxSensors::resetSensorsData() +{ + int max = 3; + if(sensorType != kSensorTypeTouchKey) + max = 5; + + for(int i=0; i<max; i++) + { + tk0_touchPosX[i] = -1; + tk0_touchPosY = -1; + tk0_touchSize[i] = 0; + + tk1_touchPosX[i] = -1; + tk1_touchPosY = -1; + tk1_touchSize[i] = 0; + + fsr_read = 0; + } + + return; +} + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/DboxSensors.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,128 @@ +/* + * DboxSensors.h + * + * Created on: May 19, 2014 + * Author: Victor Zappi + */ + +#ifndef DBOXSENSORS_H_ +#define DBOXSENSORS_H_ + +#include <stdio.h> +#include <sys/mount.h> // mount() +#include <string.h> // strerror() +#include <fstream> // fstream +#include <iostream> +#include <unistd.h> // usleep() +#include <glob.h> // glob() +#include <sys/time.h> // elapsed time +#include <sys/stat.h> // mkdir() +#include <algorithm> // reverse() [string...] + +#include "I2c_TouchKey.h" +#include "AnalogInput.h" +#include <GPIOcontrol.h> // TODO wrap this into a class + +/*--------------------------------------------------------------------------------------------------------------------------------------------------- + * This class retrieves data from all the connected sensors, + * logs them + * and exposes to the main only the values needed to synthesize sound + * + * The simple instrument has: + * + * + * + *--------------------------------------------------------------------------------------------------------------------------------------------------- + */ +class DboxSensors +{ +public: + int initSensors(int tk0_bus, int tk0_address, int tk1_bus, int tk1_address, int tk_file, int fsr_pin, int fsrmax, int sensorTypeToUse, int gpio0=-1, int gpio1=-1); + int readSensors(); + int getTKTouchCount(int index); + float *getTKXPositions(int index); + float getTKYPosition(int index); + float *getTKTouchSize(int index); + double getFSRVAlue(); + int getDigitalIn(int index); + + DboxSensors(); + ~DboxSensors(); + +private: + int sensorType; + + I2c_TouchKey TK0; + int tk0_touchCnt; + float tk0_touchPosX[5]; + float tk0_touchPosY; + float tk0_touchSize[5]; + + I2c_TouchKey TK1; + int tk1_touchCnt; + float tk1_touchPosX[5]; + float tk1_touchPosY; + float tk1_touchSize[5]; + + AnalogInput FSR; + int fsr_pinNum; + double fsr_read; + int fsr_max; + + unsigned int digitalIn[2]; + int fdDi[2]; + int gpio[2]; + + void resetSensorsData(); + +}; + + + +//-------------------------------------------------------------------------------- +// read interface +inline int DboxSensors::getTKTouchCount(int index) +{ + if(index==0) + return tk0_touchCnt; + else + return tk1_touchCnt; +} + +inline float *DboxSensors::getTKXPositions(int index) +{ + if(index==0) + return tk0_touchPosX; + else + return tk1_touchPosX; +} + +inline float DboxSensors::getTKYPosition(int index) +{ + if(index==0) + return tk0_touchPosY; + else + return tk1_touchPosY; +} + +inline float *DboxSensors::getTKTouchSize(int index) +{ + if(index==0) + return tk0_touchSize; + else + return tk1_touchSize; +} + +inline double DboxSensors::getFSRVAlue() +{ + return fsr_read; +} + +inline int DboxSensors::getDigitalIn(int index) +{ + return digitalIn[index]; +} +//-------------------------------------------------------------------------------- + + +#endif /* DBOXSENSORS_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/FIRfilter.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,73 @@ +/* + * FIRfilter.h + * + * Created on: Aug 5, 2014 + * Author: Victor Zappi and Andrew McPherson + */ + +#ifndef FIRFILTER_H_ +#define FIRFILTER_H_ + +#define ENABLE_NE10_FIR_FLOAT_NEON // Define needed for Ne10 library +#include <ne10/NE10.h> + +//#define FILTER_TAP_NUM 21 +//ne10_float32_t filterTaps[FILTER_TAP_NUM] = { +// 0.000350, +// 0.001133, +// 0.002407, +// 0.004203, +// 0.006468, +// 0.009057, +// 0.011748, +// 0.014265, +// 0.016323, +// 0.017671, +// 0.018141, +// 0.017671, +// 0.016323, +// 0.014265, +// 0.011748, +// 0.009057, +// 0.006468, +// 0.004203, +// 0.002407, +// 0.001133, +// 0.000350 +//}; +#define FILTER_TAP_NUM 31 +ne10_float32_t filterTaps[FILTER_TAP_NUM] = { + 0.000018, + 0.000043, + 0.000078, + 0.000125, + 0.000183, + 0.000252, + 0.000330, + 0.000415, + 0.000504, + 0.000592, + 0.000677, + 0.000754, + 0.000818, + 0.000866, + 0.000897, + 0.000907, + 0.000897, + 0.000866, + 0.000818, + 0.000754, + 0.000677, + 0.000592, + 0.000504, + 0.000415, + 0.000330, + 0.000252, + 0.000183, + 0.000125, + 0.000078, + 0.000043, + 0.000018 +}; + +#endif /* FIRFILTER_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/FeedbackOscillator.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,105 @@ +/* + * FeedbackOscillator.cpp + * + * Recursive phase-shift oscillator implemented + * on the matrix + * + * Andrew McPherson 2014 + */ + +#include "FeedbackOscillator.h" +#include <cstdlib> +#include <cmath> + +#define COEFF_B0 0 +#define COEFF_B1 1 +#define COEFF_A1 2 + +FeedbackOscillator::FeedbackOscillator() +: wavetable1(0), wavetable2(0) +{ + +} + +FeedbackOscillator::~FeedbackOscillator() { + if(wavetable1 != 0) + free(wavetable1); + if(wavetable2 != 0) + free(wavetable2); + +} + +// Initialise the settings for the feedback oscillator +void FeedbackOscillator::initialise(int maxTableSize, float hpfCutoffFrequency, float matrixSampleRate) { + wavetableMaxLength = maxTableSize; + if(wavetable1 != 0) + free(wavetable1); + if(wavetable2 != 0) + free(wavetable2); + + wavetable1 = (float *)malloc(maxTableSize * sizeof(float)); + wavetable2 = (float *)malloc(maxTableSize * sizeof(float)); + + float omega = tan(M_PI * hpfCutoffFrequency / matrixSampleRate); + float n = 1.0f / (1.0f + omega); + + coeffs[COEFF_A1] = (omega - 1.0f) * n; + coeffs[COEFF_B0] = n; + coeffs[COEFF_B1] = -n; + + for(int n = 0; n < maxTableSize; n++) + wavetable1[n] = wavetable2[n] = 0; + + wavetableRead = wavetable1; + wavetableWrite = wavetable2; + wavetableWritePointer = 0; + sampleCount = lastTriggerCount = 0; +} + +// Process one sample and store the output value +// Returns true if the wavetable needs rendering +int FeedbackOscillator::process(float input, float *output) { + float outFloat = coeffs[COEFF_B0] * input + coeffs[COEFF_B1] * lastInput - coeffs[COEFF_A1] * lastOutput; + int requestRenderLength = 0; + + if(outFloat < -0.5) + *output = 0; + else if(outFloat > 0.5) + *output = 1; + else + *output = outFloat + 0.5; + + if(canTrigger && outFloat > 0 && lastOutput <= 0) { + triggered = true; + requestRenderLength = wavetableWritePointer; // How many samples stored thus far? + if(requestRenderLength < 4) + requestRenderLength = 0; // Ignore anything with fewer than 4 points + + lastTriggerCount = sampleCount; + canTrigger = false; + wavetableWritePointer = 0; + + // Swap buffers + float *temp = wavetableWrite; + wavetableWrite = wavetableRead; + wavetableRead = temp; + } + + if(triggered) { + wavetableWrite[wavetableWritePointer] = outFloat; + if(++wavetableWritePointer >= wavetableMaxLength) { + triggered = false; + wavetableWritePointer = 0; + } + } + + if(sampleCount - lastTriggerCount > 40) + canTrigger = true; + + sampleCount++; + + lastOutput = outFloat; + lastInput = input; + + return requestRenderLength; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/FeedbackOscillator.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,41 @@ +/* + * FeedbackOscillator.h + * + * Created on: June 8, 2014 + * Author: Andrew McPherson + */ + +#ifndef FEEDBACKOSCILLATOR_H +#define FEEDBACKOSCILLATOR_H + +class FeedbackOscillator +{ +public: + FeedbackOscillator(); + ~FeedbackOscillator(); + + // Initialise the settings for the feedback oscillator + void initialise(int maxTableSize, float hpfCutoffFrequency, float matrixSampleRate); + + // Process one sample and store the output value + // Returns the length of table to interpolate; or 0 if nothing to process further + int process(float input, float *output); + + float *wavetable() { return wavetableRead; } + +private: + float coeffs[3]; // Coefficients of first-order high-pass filter + float lastInput; // last input sample for HPF + float lastOutput; // last output sample of HPF + bool triggered; // whether we are currently saving samples + bool canTrigger; // whether we are able to begin saving samples + int wavetableMaxLength; // how long the stored wavetable can be + int sampleCount; // how many samples have elapsed + int lastTriggerCount; // sample count when we last triggered + + float *wavetable1, *wavetable2; // Two wavetables where we record samples + float *wavetableRead, *wavetableWrite; // Pointers to the above wavetables + int wavetableWritePointer; // Where we are currently writing +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/OscillatorBank.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,1016 @@ +/* + * OscillatorBank.cpp + * + * Created on: May 23, 2014 + * Author: Victor Zappi and Andrew McPherson + */ + + +/* + * There is a problem with name consistency between this class and the Parser class in spear_parser files. + * There, a "frame" is each of the time values where partials are sampled, while a "hop" is the actual jump between frames [calculated in samples] + * Here, "hop" is used with the meaning of "frame", while "frame" became the local frame of a partial + * + * example + * + * frames: 0 1 2 + * p0 p0_0 p0_1 + * p1 p1_0 p1_1 p1_2 + * p2 p2_0 p2_1 + * + * In this case: + * in Parser there are 2 hops, 3 total frames and the 3 partials have respectively 2, 3 and 2 local frames + * + * here there are 3 total hops [the concept of jumps is discarded, cos not in use] and the 3 partials have respectively 2, 3 and 2 frames + * + * This must be fixed +*/ + +// TODO: fix hop-frame name consistency + + +#include <stdlib.h> + +#include "OscillatorBank.h" + +OscillatorBank::OscillatorBank() { + loaded = false; +} + +OscillatorBank::OscillatorBank(string filename, int hopsize, int samplerate) { + loaded = false; + loadFile(filename.c_str(), hopsize, samplerate); +} + +OscillatorBank::OscillatorBank(char *filename, int hopsize, int samplerate) { + loaded = false; + loadFile(filename, hopsize, samplerate); +} + +OscillatorBank::~OscillatorBank() { + free(oscillatorPhases); + free(oscillatorNextNormFreq); + free(oscillatorNextAmp); + free(oscillatorNormFrequencies); + free(oscillatorAmplitudes); + free(oscillatorNormFreqDerivatives); + free(oscillatorAmplitudeDerivatives); + free(phaseCopies); + free(nextNormFreqCopies); + free(nextAmpCopies); + + delete[] oscStatNormFrequenciesMean; + delete[] oscStatNumHops; + delete[] lookupTable; + delete[] indicesMapping; + delete[] freqFixedDeltas; + delete[] ampFixedDeltas; + delete[] nyquistCut; +} + +bool OscillatorBank::initBank(int oversamp) { + if (!loaded) + return false; + + //---prepare look-up table + lookupTableSize = 1024; + lookupTable = new float[lookupTableSize + 1]; + for (int n = 0; n < (lookupTableSize + 1); n++) + lookupTable[n] = sin(2.0 * M_PI * (float) n / (float) lookupTableSize); + frequencyScaler = (float) lookupTableSize / rate; + nyqNorm = rate / 2 * frequencyScaler; + + if (oversamp < 1) + oversamp = 1; + + //---prepare oscillators + partials = &(parser.partials); // pointer to paser's partials + partialsHopSize = parser.getHopSize(); + lastHop = partials->getHopNum(); // last bank hop is equal to last partial frame, which is equal to partial hop num + overSampling = oversamp; + hopSize = partialsHopSize / overSampling; // if oversampling, osc bank hop num > partials hop num + hopSizeReminder = partialsHopSize % overSampling; + oscBankHopSize = hopSize; + numOfPartials = partials->getPartialNum(); + numOfOscillators = partials->getMaxActivePartialNum(); // get the maximum number of active partials at the same time + + // set to next multiple of 4 [NEON] + numOfOscillators = (numOfOscillators + 3) & ~0x3; // to be sure we can add up to 3 fake oscillators + + int err; + //---allocate buffers + // alligned buffers [NEON] + err = posix_memalign((void**) &oscillatorPhases, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &oscillatorNextNormFreq, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &oscillatorNextAmp, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &oscillatorNormFrequencies, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &oscillatorAmplitudes, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &oscillatorNormFreqDerivatives, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &oscillatorAmplitudeDerivatives, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &phaseCopies, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &nextNormFreqCopies, 16, + numOfOscillators * sizeof(float)); + err += posix_memalign((void**) &nextAmpCopies, 16, + numOfOscillators * sizeof(float)); + + // regular ones + oscStatNormFrequenciesMean = new float[numOfPartials]; + oscStatNumHops = new float[numOfPartials]; + indicesMapping = new int[numOfPartials]; + freqFixedDeltas = new float[numOfPartials]; + ampFixedDeltas = new float[numOfPartials]; + nyquistCut = new bool[numOfPartials]; + + if (err > 0) { + dbox_printf("Failed memory allocations %@#!\n"); + return false; + } + + // copy stats [they do not change] + for (int n = 0; n < numOfPartials; n++) { + oscStatNormFrequenciesMean[n] = partials->partialFreqMean[n] + * frequencyScaler; + oscStatNumHops[n] = partials->partialNumFrames[n]; // in Parser and Partials "frames" are what we call here "hops" [see comment at top of file] + } + + // deafult values + actPartNum = 0; + loopStartHop = 0; + loopEndHop = (parser.partials.getHopNum() - 2) * overSampling; + ampTh = 0.0001; + hopNumTh = 0; + pitchMultiplier = 1; + freqMovement = 1; + filterNum = 0; + note = false; + speed = 1; + nextSpeed = -1; + maxSpeed = 10; + minSpeed = 0.1; + jumpHop = -1; + + // filter + filterMaxF = 22000; + filterAmpMinF = 10 * frequencyScaler; + filterAmpMaxF = 5000 * frequencyScaler; + filterAmpMul = 10.0; + + // adsr + minAttackTime = .0001; + deltaAttackTime = 2.; + minReleaseTime = 1; + deltaReleaseTime = 2.5; + + adsr.setAttackRate(minAttackTime * rate); + adsr.setDecayRate(.0001 * rate); + adsr.setSustainLevel(1); + adsr.setReleaseRate(minReleaseTime * rate); + + state = bank_stopped; + return true; +} + +void OscillatorBank::resetOscillators() { + currentHop = -1; + loopDir = 1; + loopDirShift = 0; + fill(nyquistCut, nyquistCut + numOfPartials, false); + prevAdsrVal = 0; + prevAmpTh = ampTh; + prevHopNumTh = hopNumTh; + prevPitchMultiplier = pitchMultiplier; + prevFreqMovement = freqMovement; + prevFilterNum = filterNum; + memcpy(prevFilterFreqs, filterFreqs, filterNum * sizeof(float)); + memcpy(prevFilterQ, filterQ, filterNum * sizeof(float)); + + int activePNum = partials->activePartialNum[0]; + unsigned int *activeP = partials->activePartials[0]; + for (int i = 0; i < activePNum; i++) { + freqFixedDeltas[activeP[i]] = partials->partialFreqDelta[activeP[i]][0] + / overSampling; + ampFixedDeltas[activeP[i]] = partials->partialAmpDelta[activeP[i]][0] + / overSampling; + } + // attack! + adsr.gate(1); + note = true; + + nextHop(); + + state = bank_playing; +} + +void OscillatorBank::nextHop() { + hopSize = oscBankHopSize; + + // copy phases, next freqs and next amps from previous frame + memcpy(phaseCopies, oscillatorPhases, actPartNum * sizeof(float)); + memcpy(nextNormFreqCopies, oscillatorNextNormFreq, + actPartNum * sizeof(float)); + memcpy(nextAmpCopies, oscillatorNextAmp, actPartNum * sizeof(float)); + + // next frame is forward or backwards, cos we could be in the loop + currentHop += loopDir; + + checkDirection(); + +// if((currentHop/overSampling)%100 == 0) +// dbox_printf("currentHop %d, direction: %d\n", currentHop/overSampling, loopDir); + + // if needs jump, end here this method, cos jumpToHop() will do tee rest + if (checkJump() == 0) + return; + // otherwise, if jump is not needed or fails, continue regular stuff + + if (nextEnvState() != 0) + return; // release has ended! + + checkSpeed(); + + // now let's decide how to calculate next hop + if (!checkOversampling()) + nextOscBankHop(); + else + nextPartialHop(); +} + +void OscillatorBank::nextOscBankHop() { + int parIndex, localHop; + float parDamp = 1; + int currentPartialHop = (currentHop / overSampling) + loopDirShift; + + // if going backwards in the loop, get previous frame active partials... + actPartNum = partials->activePartialNum[currentPartialHop - loopDirShift]; + actPart = partials->activePartials[currentPartialHop - loopDirShift]; + //cout << "actPartNum: " << actPartNum << endl; + + envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release] + + int parCnt = 0; + int currentHopReminder = currentHop % overSampling; + // steps to reach next bank hop from previous partial hop + int steps = currentHopReminder + 1; + if (loopDir < 0) + steps = overSampling - currentHopReminder + 1; + + for (int i = 0; i < actPartNum; i++) { + // find partial and frame + parIndex = actPart[i]; + //localHop = partials->localPartialFrames[currentPartialHop][parIndex]; + localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file] + + //float delta = partials->partialFrequencies[parIndex][localHop+loopDir] - partials->partialFrequencies[parIndex][localHop]; + + // if this partial was over nyquist on previous hop... + if (nyquistCut[parIndex]) { + // ...restart from safe values + oscillatorPhases[parCnt] = 0; + //TODO add freqmove dependency + oscillatorNextNormFreq[parCnt] = + (partials->partialFrequencies[parIndex][localHop] + + freqFixedDeltas[parIndex] * (steps - 1)) + * frequencyScaler * prevPitchMultiplier; + oscillatorNextAmp[parCnt] = 0; + } else if (loopDir == 1) // otherwise recover phase, target freq and target amp from previous frame + { + if ((localHop != 0) || (currentHopReminder != 0)) { + oscillatorPhases[parCnt] = + phaseCopies[indicesMapping[parIndex]]; + oscillatorNextNormFreq[parCnt] = + nextNormFreqCopies[indicesMapping[parIndex]]; + oscillatorNextAmp[parCnt] = + nextAmpCopies[indicesMapping[parIndex]]; + } else // first oscillator hop [both for bank and partial], so no previous data are available + { + oscillatorPhases[parCnt] = 0; + //TODO add freqmove dependency + oscillatorNextNormFreq[parCnt] = + partials->partialFrequencies[parIndex][localHop] + * frequencyScaler * prevPitchMultiplier; + parDamp = calculateParDamping(parIndex, prevHopNumTh, + prevAdsrVal, oscillatorNextNormFreq[parCnt], + prevFilterNum, prevFilterFreqs, prevFilterQ); + oscillatorNextAmp[parCnt] = + partials->partialAmplitudes[parIndex][localHop] + * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + freqFixedDeltas[parIndex] = + partials->partialFreqDelta[parIndex][localHop + loopDir] + * loopDir / overSampling; + ampFixedDeltas[parIndex] = + partials->partialAmpDelta[parIndex][localHop + loopDir] + * loopDir / overSampling; + } + } else { + oscillatorPhases[parCnt] = phaseCopies[indicesMapping[parIndex]]; + oscillatorNextNormFreq[parCnt] = + nextNormFreqCopies[indicesMapping[parIndex]]; + oscillatorNextAmp[parCnt] = nextAmpCopies[indicesMapping[parIndex]]; + } + + // remove aliasing, skipping partial over nyquist freq + if (oscillatorNextNormFreq[parCnt] > nyqNorm) { + nyquistCut[parIndex] = true; + continue; + } + nyquistCut[parIndex] = false; + + // first set up freq, cos filter affects amplitude damping according to freq content + oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts + // save next values, current for next round + oscillatorNextNormFreq[parCnt] = (freqMovement + * (partials->partialFrequencies[parIndex][localHop] + + freqFixedDeltas[parIndex] * steps) * frequencyScaler + + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex]) + * pitchMultiplier; + // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials + oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt] + - oscillatorNormFrequencies[parCnt]) / hopCounter; + // this second weird passage handles dissonance control, morphing between regular and mean frequencies + oscillatorNormFreqDerivatives[parCnt] = freqMovement + * oscillatorNormFreqDerivatives[parCnt] + + (1 - freqMovement) + * ((oscStatNormFrequenciesMean[parIndex] + * pitchMultiplier) + - oscillatorNormFrequencies[parCnt]) + / hopCounter; + + parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal, + oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ); + + // now amplitudes + oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts + // save next values, current for next round + //delta = partials->partialAmplitudes[parIndex][localHop+loopDir] - partials->partialAmplitudes[parIndex][localHop]; + oscillatorNextAmp[parCnt] = + (partials->partialAmplitudes[parIndex][localHop] + + ampFixedDeltas[parIndex] * steps) * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + if ((loopDir == -1) && (localHop = 1) && (currentHopReminder == 1)) + oscillatorNextAmp[parCnt] = 0; + // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials + oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt] + - oscillatorAmplitudes[parCnt]) / hopCounter; + + // finally update current mapping between oscillators and partials + indicesMapping[parIndex] = parCnt; + parCnt++; + } + actPartNum = parCnt; + // [NEON] if not multiple of 4... + if (actPartNum % 4 != 0) + addFakeOsc(); +} + +void OscillatorBank::nextPartialHop() { + unsigned int parIndex, localHop; + float parDamp = 1; + int currentPartialHop = currentHop / overSampling; + + // if going backwards in the loop, get previous frame active partials... + actPartNum = partials->activePartialNum[currentPartialHop - loopDirShift]; + actPart = partials->activePartials[currentPartialHop - loopDirShift]; + + envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release] + + int parCnt = 0; + int steps = overSampling - 1; // steps to reach next hop [partial or bank] from previous partial hop + + for (int i = 0; i < actPartNum; i++) { + // find partial and frame + parIndex = actPart[i]; + //localHop = partials->localPartialFrames[currentPartialHop][parIndex]; + localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file] + + // if this partial was over nyquist on previous hop... + if (nyquistCut[parIndex]) { + // ...restart from safe values + oscillatorPhases[parCnt] = 0; + //TODO add freqmove dependency + oscillatorNextNormFreq[parCnt] = + (partials->partialFrequencies[parIndex][localHop] + + freqFixedDeltas[parIndex] * steps + * (1 - loopDirShift)) * frequencyScaler + * prevPitchMultiplier; + oscillatorNextAmp[parCnt] = 0; + } else if (loopDir == 1) // otherwise recover phase, target freq and target amp from previous frame + { + if ((localHop != 0) || (overSampling > 1)) { + oscillatorPhases[parCnt] = + phaseCopies[indicesMapping[parIndex]]; + oscillatorNextNormFreq[parCnt] = + nextNormFreqCopies[indicesMapping[parIndex]]; + oscillatorNextAmp[parCnt] = + nextAmpCopies[indicesMapping[parIndex]]; + } else // first oscillator hop [both for bank and partial], so no previous data are available + { + oscillatorPhases[parCnt] = 0; + //TODO add freqmove dependency + oscillatorNextNormFreq[parCnt] = + partials->partialFrequencies[parIndex][localHop] + * frequencyScaler * prevPitchMultiplier; + parDamp = calculateParDamping(parIndex, prevHopNumTh, + prevAdsrVal, oscillatorNextNormFreq[parCnt], + prevFilterNum, prevFilterFreqs, prevFilterQ); + oscillatorNextAmp[parCnt] = + partials->partialAmplitudes[parIndex][localHop] + * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + freqFixedDeltas[parIndex] = + partials->partialFreqDelta[parIndex][localHop + loopDir] + * loopDir / overSampling; + ampFixedDeltas[parIndex] = + partials->partialAmpDelta[parIndex][localHop + loopDir] + * loopDir / overSampling; + } + } else { + if (localHop != partials->partialNumFrames[parIndex] - 1) { + oscillatorPhases[parCnt] = + phaseCopies[indicesMapping[parIndex]]; + oscillatorNextNormFreq[parCnt] = + nextNormFreqCopies[indicesMapping[parIndex]]; + oscillatorNextAmp[parCnt] = + nextAmpCopies[indicesMapping[parIndex]]; + } else // first oscillator hop [going backwards - both for bank and partial] , so no previous data are available + { + oscillatorPhases[parCnt] = 0; + //TODO add freqmove dependency + oscillatorNextNormFreq[parCnt] = + partials->partialFrequencies[parIndex][localHop] + * frequencyScaler * prevPitchMultiplier; + parDamp = calculateParDamping(parIndex, prevHopNumTh, + prevAdsrVal, oscillatorNextNormFreq[parCnt], + prevFilterNum, prevFilterFreqs, prevFilterQ); + oscillatorNextAmp[parCnt] = + partials->partialAmplitudes[parIndex][localHop] + * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + freqFixedDeltas[parIndex] = + partials->partialFreqDelta[parIndex][localHop + loopDir] + * loopDir / overSampling; + ampFixedDeltas[parIndex] = + partials->partialAmpDelta[parIndex][localHop + loopDir] + * loopDir / overSampling; + } + } + // remove aliasing, skipping partial over nyquist freq + if (oscillatorNextNormFreq[parCnt] > nyqNorm) { + //cout << nyqNorm << endl; + nyquistCut[parIndex] = true; + continue; + } + nyquistCut[parIndex] = false; + + // first set up freq, cos filter affects amplitude damping according to freq content + oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts + // save next values, current for next round + oscillatorNextNormFreq[parCnt] = (freqMovement + * (partials->partialFrequencies[parIndex][localHop + loopDir] + - freqFixedDeltas[parIndex] * steps * loopDirShift) + * frequencyScaler + + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex]) + * pitchMultiplier; + // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials + oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt] + - oscillatorNormFrequencies[parCnt]) / hopCounter; + // this second weird passage handles dissonance control, morphing between regular and mean frequencies + oscillatorNormFreqDerivatives[parCnt] = freqMovement + * oscillatorNormFreqDerivatives[parCnt] + + (1 - freqMovement) + * ((oscStatNormFrequenciesMean[parIndex] + * pitchMultiplier) + - oscillatorNormFrequencies[parCnt]) + / hopCounter; + + parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal, + oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ); + + // now amplitudes + oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts + // save next values, current for next round + //delta = partials->partialAmplitudes[parIndex][localHop+loopDir] - partials->partialAmplitudes[parIndex][localHop]; + oscillatorNextAmp[parCnt] = + (partials->partialAmplitudes[parIndex][localHop + loopDir] + - (ampFixedDeltas[parIndex]) * steps * loopDirShift) + * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + + // to avoid bursts when transients are played backwards + if ((loopDir == -1) && (localHop - 1 == 0) && (overSampling == 1)) { + oscillatorNextAmp[parCnt] = 0; + } + // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials + oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt] + - oscillatorAmplitudes[parCnt]) / hopCounter; + + // if next is not going to loop boundaries, get next deltas [same direction] + if ((((currentPartialHop + loopDir) * overSampling != loopEndHop) + || (loopDir == -1)) + && (((currentPartialHop + loopDir) * overSampling + loopDir + != loopStartHop) || (loopDir == 1))) { + freqFixedDeltas[parIndex] = + partials->partialFreqDelta[parIndex][localHop + loopDir] + * loopDir / overSampling; + ampFixedDeltas[parIndex] = + partials->partialAmpDelta[parIndex][localHop + loopDir] + * loopDir / overSampling; + } else // .. otherwise, keep deltas but change sign [co swe change direction] + { + freqFixedDeltas[parIndex] = -freqFixedDeltas[parIndex]; + ampFixedDeltas[parIndex] = -ampFixedDeltas[parIndex]; + } + + // finally update current mapping between oscillators and partials + indicesMapping[parIndex] = parCnt; + parCnt++; + } + actPartNum = parCnt; + // [NEON] if not multiple of 4... + if (actPartNum % 4 != 0) + addFakeOsc(); + + updatePrevControls(); +} + +void OscillatorBank::addFakeOsc() { + // ...calculate difference + int newPartNum = (actPartNum + 3) & ~0x3; + // ...add fake oscillators until total num is multiple of 4 + for (int i = actPartNum; i < newPartNum; i++) { + oscillatorAmplitudes[i] = 0; + oscillatorNormFrequencies[i] = 0; + oscillatorAmplitudeDerivatives[i] = 0; + oscillatorNormFreqDerivatives[i] = 0; + oscillatorPhases[i] = 0; + } + // ...and update num of active partials + actPartNum = newPartNum; +} + +void OscillatorBank::play(float vel) { + // set attack and release params according to velocity + //adsr.setAttackRate((minAttackTime + ((1 - vel) * deltaAttackTime)) * rate); + adsr.setAttackRate(minAttackTime * rate); + //adsr.setReleaseRate((minReleaseTime + (1 - vel) * deltaReleaseTime) * rate); + adsr.setReleaseRate(minReleaseTime * rate); + + // set timbre + hopNumTh = log((1 - vel) + 1) / log(2) * 20000; + + state = bank_toreset; +} + +//--------------------------------------------------------------------------------------------------------------------------- +// private methods +//--------------------------------------------------------------------------------------------------------------------------- + +bool OscillatorBank::loader(char *filename, int hopsize, int samplerate) { + rate = samplerate; + loaded = parser.parseFile(filename, hopsize, samplerate); + return loaded; +} + +int OscillatorBank::jumpToHop() { + int jumpGap = abs(jumpHop - currentHop / overSampling); // gaps in partial reference + + // can't jump to self dude + if (jumpGap == 0) + return 1; + + // direction is in general maintained with jump + if (jumpHop == 0) + setDirection(1); + else if (jumpHop == lastHop) + setDirection(-1); + + dbox_printf("\tJump from %d to %d\n", currentHop / overSampling, jumpHop); + dbox_printf("\tdirection %d\n", loopDir); + + currentHop = jumpHop * overSampling; + + if (nextEnvState() != 0) + return 0; // release has ended! + + checkSpeed(); + + int parIndex, localHop, targetHop; + float parDamp = 1; + int currentPartialHop = currentHop / overSampling; + int targetPartialHop = jumpHop; + + actPartNum = partials->activePartialNum[currentPartialHop]; + actPart = partials->activePartials[currentPartialHop]; + int targetActParNum = partials->activePartialNum[targetPartialHop]; + unsigned int *targetActPar = partials->activePartials[targetPartialHop]; + + envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release] + + int parCnt = 0; + int currentHopReminder = currentHop % overSampling; + + // steps to walk where i am [bank of partial hop] from previous partial hop + int steps = currentHopReminder * (overSampling != 1); // no oversampling 0, oversampling and going ff currentHopReminder + + for (int i = 0; i < actPartNum; i++) { + // find partial and frame + parIndex = actPart[i]; + //localHop = partials->localPartialFrames[currentPartialHop][parIndex]; + localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file] + + // if this partial was over nyquist on previous hop... + if (nyquistCut[parIndex]) { + // ...restart from safe values + oscillatorPhases[parCnt] = 0; + //TODO add freqmove dependency + oscillatorNextNormFreq[parCnt] = + (partials->partialFrequencies[parIndex][localHop] + + freqFixedDeltas[parIndex] * steps * loopDir) + * frequencyScaler * prevPitchMultiplier; + oscillatorNextAmp[parCnt] = 0; + } else if (loopDir == 1) {// otherwise recover phase, target freq and target amp from previous frame + if ((localHop != 0) + || ((overSampling > 1) && (currentHopReminder != 0))) { + oscillatorPhases[parCnt] = + phaseCopies[indicesMapping[parIndex]]; + oscillatorNextNormFreq[parCnt] = + nextNormFreqCopies[indicesMapping[parIndex]]; + oscillatorNextAmp[parCnt] = + nextAmpCopies[indicesMapping[parIndex]]; + } else { // first oscillator hop [both for bank and partial], so no previous data are available + oscillatorPhases[parCnt] = 0; + //TODO add freqmove dependency + oscillatorNextNormFreq[parCnt] = + partials->partialFrequencies[parIndex][localHop] + * frequencyScaler * prevPitchMultiplier; + parDamp = calculateParDamping(parIndex, prevHopNumTh, + prevAdsrVal, oscillatorNextNormFreq[parCnt], + prevFilterNum, prevFilterFreqs, prevFilterQ); + oscillatorNextAmp[parCnt] = + partials->partialAmplitudes[parIndex][localHop] + * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + } + } else { + if (( (unsigned)localHop != partials->partialNumFrames[parIndex] - 1) + || ((overSampling > 1) && (currentHopReminder != 0))) { + oscillatorPhases[parCnt] = + phaseCopies[indicesMapping[parIndex]]; + oscillatorNextNormFreq[parCnt] = + nextNormFreqCopies[indicesMapping[parIndex]]; + oscillatorNextAmp[parCnt] = + nextAmpCopies[indicesMapping[parIndex]]; + } else // first oscillator hop [going backwards - both for bank and partial] , so no previous data are available, so retrieve where i am + { + oscillatorPhases[parCnt] = 0; + //TODO add freqmove dependency + oscillatorNextNormFreq[parCnt] = + partials->partialFrequencies[parIndex][localHop] + * frequencyScaler * prevPitchMultiplier; + parDamp = calculateParDamping(parIndex, prevHopNumTh, + prevAdsrVal, oscillatorNextNormFreq[parCnt], + prevFilterNum, prevFilterFreqs, prevFilterQ); + oscillatorNextAmp[parCnt] = + partials->partialAmplitudes[parIndex][localHop] + * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + } + } + // remove aliasing, skipping partial over nyquist freq + if (oscillatorNextNormFreq[parCnt] > nyqNorm) { + //cout << nyqNorm << endl; + nyquistCut[parIndex] = true; + continue; + } + nyquistCut[parIndex] = false; + + // check what happens of this partial at target hop + float targetFreqVal, targetAmpVal; + //targetHop = partials->localPartialFrames[targetPartialHop][parIndex]; + targetHop = targetPartialHop - partials->partialStartFrame[parIndex]; + + if (targetHop == -1) + targetFreqVal = targetAmpVal = 0; + else { + targetFreqVal = partials->partialFrequencies[parIndex][targetHop] + * frequencyScaler; // pitch shift will be multiplied later!!! + targetAmpVal = partials->partialFrequencies[parIndex][targetHop]; // parDamp will be multiplied later!!! + } + + // first set up freq, cos filter affects amplitude damping according to freq content + oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts + // save next values, current for next round + oscillatorNextNormFreq[parCnt] = (freqMovement * targetFreqVal + + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex]) + * pitchMultiplier; + // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials + oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt] + - oscillatorNormFrequencies[parCnt]) / hopCounter; + // this second weird passage handles dissonance control, morphing between regular and mean frequencies + oscillatorNormFreqDerivatives[parCnt] = freqMovement + * oscillatorNormFreqDerivatives[parCnt] + + (1 - freqMovement) + * ((oscStatNormFrequenciesMean[parIndex] + * pitchMultiplier) + - oscillatorNormFrequencies[parCnt]) + / hopCounter; + + parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal, + oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ); + + // now amplitudes + oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts + // save next values, current for next round + oscillatorNextAmp[parCnt] = targetAmpVal * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + // to avoid bursts when transients are played backwards + if ((loopDir == -1) && (targetHop == 0) + && ((overSampling == 1) || (currentHopReminder == 0))) { + oscillatorNextAmp[parCnt] = 0; + } + // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials + oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt] + - oscillatorAmplitudes[parCnt]) / hopCounter; + + //if partial does not die at target, calculate deltas according to direction + if (targetHop != -1) { + freqFixedDeltas[parIndex] = + partials->partialFreqDelta[parIndex][targetHop] * loopDir + / overSampling; + ampFixedDeltas[parIndex] = + partials->partialAmpDelta[parIndex][targetHop] * loopDir + / overSampling; + } + + // finally update current mapping between oscillators and partials + indicesMapping[parIndex] = parCnt; + parCnt++; + } + actPartNum = parCnt; + + // now add the ones that start at target hop! + for (int i = 0; i < targetActParNum; i++) { + // find partial and frame + parIndex = targetActPar[i]; + //targetHop = partials->localPartialFrames[targetPartialHop][parIndex]; + targetHop = targetPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file] + + // check if this partials was already active before the jump + //localHop = partials->localPartialFrames[currentPartialHop][parIndex]; + localHop = currentPartialHop - partials->partialStartFrame[parIndex]; + + // if yes, skip it + if (localHop != -1) + continue; + + // otherwise add it to active bunch and calcucalte values + + // first set up freq, cos filter affects amplitude damping according to freq content + oscillatorNormFrequencies[parCnt] = 0; + // save next values, current for next round + oscillatorNextNormFreq[parCnt] = (freqMovement + * partials->partialFrequencies[parIndex][targetHop] + * frequencyScaler + + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex]) + * pitchMultiplier; + // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials + oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt] + - oscillatorNormFrequencies[parCnt]) / hopCounter; + // this second weird passage handles dissonance control, morphing between regular and mean frequencies + oscillatorNormFreqDerivatives[parCnt] = freqMovement + * oscillatorNormFreqDerivatives[parCnt] + + (1 - freqMovement) + * ((oscStatNormFrequenciesMean[parIndex] + * pitchMultiplier) + - oscillatorNormFrequencies[parCnt]) + / hopCounter; + + parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal, + oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ); + + // now amplitudes + oscillatorAmplitudes[parCnt] = 0; + // save next values, current for next round + oscillatorNextAmp[parCnt] = + partials->partialFrequencies[parIndex][targetHop] * parDamp; + if(oscillatorNextAmp[parCnt] > 1) + oscillatorNextAmp[parCnt] = 1; + // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials + oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt] + - oscillatorAmplitudes[parCnt]) / hopCounter; + + //calculate deltas according to direction + freqFixedDeltas[parIndex] = + partials->partialFreqDelta[parIndex][targetHop] * loopDir + / overSampling; + ampFixedDeltas[parIndex] = + partials->partialAmpDelta[parIndex][targetHop] * loopDir + / overSampling; + + // finally update current mapping between oscillators and partials + indicesMapping[parIndex] = parCnt; + parCnt++; + + } + // [NEON] if not multiple of 4... + if (actPartNum % 4 != 0) + addFakeOsc(); + + updatePrevControls(); + + jumpHop = -1; + + return 0; +} + +int OscillatorBank::nextEnvState() { + /* + envState = Attack.getState(); // to determine what state we are in [attack, decay, sustain, release] + + // osc bank is playing the tail and the tail ends... + if( (state == bank_playing)&&(envState == env_idle) ) + { + state = bank_stopped; // ...stop bank + return 1; // and return immediately + } + else if( (envState == env_attack) || (envState == env_decay) ) + { + // run envelopes until next frame + dampWeight = Attack.process(hopSize); + } + else if(envState == env_release) + { + // run envelopes until next frame + dampWeight = Attack.process(hopSize); + releaseDamp = Release.process(hopSize); + }*/ + + envState = adsr.getState(); + // osc bank is playing the tail and the tail ends... + if ((state == bank_playing) && (envState == env_idle)) { + state = bank_stopped; // ...stop bank + adsrVal = 0; + return 1; // and return immediately + } else + adsrVal = adsr.process(hopSize); + + return 0; +} + +void OscillatorBank::checkDirection() { + // end of the loop or end of file + if (((currentHop >= loopEndHop) && (loopDir == 1)) + || ((currentHop >= lastHop) && (loopDir == 1))) { + // move backwards + setDirection(-1); + //dbox_printf("backward from %d\n", loopEndHop); + } else if (((currentHop <= loopStartHop) && (loopDir == -1)) + || ((currentHop <= 0) && (loopDir == -1))) // start of the loop or start of file + { + // move forward + setDirection(1); + //dbox_printf("forward from %d\n", loopStartHop); + } +} + +void OscillatorBank::checkSpeed() { + // speed control [alike on highways, LOL] + if (nextSpeed > 0) { + nextSpeed = (nextSpeed < maxSpeed) ? nextSpeed : maxSpeed; + nextSpeed = (nextSpeed > minSpeed) ? nextSpeed : minSpeed; + speed = nextSpeed; + nextSpeed = -1; + } + hopCounter = hopSize / speed; +} + +int OscillatorBank::checkJump() { + //check if has to jump somewhere + if (jumpHop > -1) { + // needs to jump! + if (jumpToHop() == 0) + return 0; + } + return 1; // no jump +} + +bool OscillatorBank::checkOversampling() { + //TODO fix this, but need andrew to fix oversampling multiple of period size + // if partialsHopSize is not a multiple of oversampling, change hop size to periodically match next partial hop + if (hopSizeReminder > 0) { + // if next osc bank hop overtakes next partial hop... + if ((currentHop + loopDir) * hopSize > partialsHopSize) { + hopSize = hopSizeReminder; // ...shrink osc bank hop size to match partial hop + return true; // and set next hop as matching with next partial hop + } + } else if (((currentHop + (1 - loopDirShift)) % overSampling) == 0) // if next osc bank hop matches next partial hop + return true; // ...mark next hop as partial hop + + return false; // ,otherwise mark next hop as osc bank hop +} + +void OscillatorBank::updatePrevControls() { + prevAdsrVal = adsrVal; + prevAmpTh = ampTh; + prevHopNumTh = hopNumTh; + prevPitchMultiplier = pitchMultiplier; + prevFreqMovement = freqMovement; + prevFilterNum = filterNum; + memcpy(prevFilterFreqs, filterFreqs, filterNum * sizeof(float)); + memcpy(prevFilterQ, filterQ, filterNum * sizeof(float)); +} + +float OscillatorBank::calculateParDamping(int parIndex, int hopNTh, + float adsrVl, float nextFreq, int filNum, float *filFreq, float *filQ) { + float parDamp = 1; + + // timbre + parDamp = ((float) (oscStatNumHops[parIndex] + 1)) / (hopNTh + 1); + parDamp = (parDamp > 1) ? 1 : parDamp; + parDamp = adsrVl * parDamp; + + //filters + + float filterWeights[MAX_TOUCHES]; + float filterDamp[MAX_TOUCHES]; + float filDist; + float filterWeightsAcc; + float filDmp; + float filAmp; + +// band reject notch filter +// float dist, dmp; +// for(int k=0; k<filterNum; k++) +// { +// dist = fabs(oscillatorNextNormFreq[parCnt]-filterFreqs[k]); +// if(dist<=filterQ[k]) +// { +// dmp = dist/filterQ[k]; +// parDamp *= dmp*dmp*dmp; +// } +// } + + + // each filter is a band pass notch filter + + // if at least one is active + if (filNum > 0) { + // reset values + filDist = 0; + filterWeightsAcc = 0; + filDmp = 0; + filAmp = 0; + // for each filter + for (int k = 0; k < filNum; k++) { + // here are a couple of kludges to boost sound output of hi freq filters + + // damping effect of filter increases with distance, but decreases with filter frequency [kludge] + float mul = ((filterMaxF-nextFreq)/filterMaxF) * 0.9 + 0.1 ; + //filDist = fabs(nextFreq - filFreq[k])*( ((exp(a*4)-1)/EXP_DENOM) * 0.9 + 0.1 ); + filDist = fabs(nextFreq - filFreq[k])*mul; + + // these to merge all filters contributions according to distance + filterWeights[k] = filterMaxF - filDist; + filterWeightsAcc += filterWeights[k]; + // freqs very close to filter center are slightly amplified + // the size of this amp area and the effect of amplification increase with frequency [kludge] + if (filDist + < filterAmpMinF + + (filterAmpMaxF*(1-mul) - filterAmpMinF) * (1 - filQ[k]) ) + filAmp = filQ[k] * filterAmpMul*(1-mul); + else + filAmp = 0; + // actual damping + filDmp = 1 / (filDist * filQ[k]); + filDmp = (filDmp > 1) ? 1 : filDmp; + // sum damp+amplification + filterDamp[k] = filDmp + filAmp; + } + // do weighted mean to merge all filters contributions + filDmp = 0; + for (int k = 0; k < filNum; k++) + filDmp += filterDamp[k] * filterWeights[k]; + filDmp /= filterWeightsAcc; + // apply + parDamp *= filDmp; + } + + + return parDamp; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/OscillatorBank.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,240 @@ +/* + * OscillatorBank.h + * + * Created on: May 23, 2014 + * Author: Victor Zappi and Andrew McPherson + */ + +#ifndef OSCILLATORBANK_H_ +#define OSCILLATORBANK_H_ + + +#include <string> + +#include "spear_parser.h" +#include "ADSR.h" +#include "config.h" + +using namespace std; + +enum OscBankstates {bank_stopped, bank_playing, bank_toreset}; + +class OscillatorBank +{ +public: + OscillatorBank(); + OscillatorBank(string filename, int hopsize=-1, int samplerate=44100); + OscillatorBank(char *filename, int hopsize=-1, int samplerate=44100); + ~OscillatorBank(); + float *oscillatorPhases; + float *oscillatorNormFrequencies; + float *oscillatorNormFreqDerivatives; + float *oscillatorAmplitudes; + float *oscillatorAmplitudeDerivatives; + float *oscStatNormFrequenciesMean; + float *oscStatNumHops; + OscBankstates state; + bool note; + int actPartNum; + unsigned int *actPart; + int hopCounter; + int lookupTableSize; + float *lookupTable; + float ampTh; + int hopNumTh; + float pitchMultiplier; + float freqMovement; + int filterNum; + float filterFreqs[5]; + float filterQ[5]; + float filterMaxF; + float filterAmpMinF; + float filterAmpMaxF; + float filterAmpMul; + + bool loadFile(string filename, int hopsize=-1, int samplerate=44100); + bool loadFile(char *filename, int hopsize=-1, int samplerate=44100); + bool initBank(int oversamp=1); + void resetOscillators(); + int getHopSize() { return hopSize; } + void nextHop(); + void setLoopHops(int start, int end); + void play(float vel); + void stop(); + void afterTouch(float vel); + int getEnvelopeState(); + float getFrequencyScaler(); + void setSpeed(float sp); + float getSpeed(); + float getMaxSpeed(); + float getMinSpeed(); + void setJumpHop(int hop); + int getLastHop(); + int getCurrentHop() { return currentHop; } + +private: + + bool loaded; + int numOfPartials; + int numOfOscillators; + int partialsHopSize; + int overSampling; + int hopSize; + int hopSizeReminder; + int oscBankHopSize; + float frequencyScaler; + float nyqNorm; + int lastHop; + int currentHop; + int loopDir; + int loopDirShift; + int loopStartHop; + int loopEndHop; + int *indicesMapping; + float *phaseCopies; + float *oscillatorNextNormFreq; + float *oscillatorNextAmp; + float *nextNormFreqCopies; + float *nextAmpCopies; + float *freqFixedDeltas; + float *ampFixedDeltas; + bool *nyquistCut; + Spear_parser parser; + Partials *partials; + ADSR adsr; + float minAttackTime; + float deltaAttackTime; + float minReleaseTime; + float deltaReleaseTime; + int envState; + int rate; + float speed; + float nextSpeed; + float maxSpeed; + float minSpeed; + int jumpHop; + float adsrVal; + float prevAdsrVal; + float prevAmpTh; + int prevHopNumTh; + float prevPitchMultiplier; + float prevFreqMovement; + int prevFilterNum; + float prevFilterFreqs[5]; + float prevFilterQ[5]; + + bool loader(char *filename, int hopsize=-1, int samplerate=44100); + void addFakeOsc(); + void nextOscBankHop(); + void nextPartialHop(); + int jumpToHop(); + void setDirection(int dir); + int nextEnvState(); + void checkDirection(); + void checkSpeed(); + int checkJump(); + bool checkOversampling(); + void updatePrevControls(); + float calculateParDamping(int parIndex, int hopNTh, float adsrVl, float nextFreq, + int filNum, float *filFreq, float *filQ); +}; + +inline bool OscillatorBank::loadFile(string filename, int hopsize, int samplerate) +{ + return loader((char *)filename.c_str(), hopsize, samplerate); +} + +inline bool OscillatorBank::loadFile(char *filename, int hopsize, int samplerate) +{ + return loader(filename, hopsize, samplerate); +} + +inline void OscillatorBank::setLoopHops(int start, int end) +{ + if(start > end) + end = start; + + if(start<0) + start = 0; + else if(start>lastHop) + start = 0; + if(end < 1) + end = 1; + end = (end<=lastHop) ? end : lastHop; + + // set it, take into consideration hop oversampling + loopStartHop = start*overSampling; + loopEndHop = end*overSampling; +} + +inline void OscillatorBank::stop() +{ + note = false; + adsr.gate(0); +} + +inline float OscillatorBank::getFrequencyScaler() +{ + return frequencyScaler; +} + +inline void OscillatorBank::afterTouch(float vel) +{ + hopNumTh = log((1-vel)+1)/log(2)*20000; + if(adsr.getState()==env_attack) + adsr.setAttackRate( (minAttackTime + ( (1-vel)*deltaAttackTime )) * rate ); + adsr.setReleaseRate( (minReleaseTime+(1-vel)*deltaReleaseTime)* rate ); +} + +inline int OscillatorBank::getEnvelopeState() +{ + return envState; +} + +inline void OscillatorBank::setSpeed(float sp) +{ + nextSpeed = sp; +} + +inline float OscillatorBank::getSpeed() +{ + return speed; +} + +inline float OscillatorBank::getMaxSpeed() +{ + return maxSpeed; +} + +inline float OscillatorBank::getMinSpeed() +{ + return minSpeed; +} + +inline void OscillatorBank::setJumpHop(int hop) +{ + if(hop<0) + return; + hop = (hop<=lastHop) ? hop : lastHop; + jumpHop = hop; +} + +inline void OscillatorBank::setDirection(int dir) +{ + if(dir>=0) + { + loopDir = 1; + loopDirShift = 0; + } + else + { + loopDir = -1; + loopDirShift = 1; + } +} + +inline int OscillatorBank::getLastHop() +{ + return lastHop; +} +#endif /* OSCILLATORBANK_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/PinkNoise.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,16 @@ +/* + * PinkNoise.cpp + * + * Created on: Oct 15, 2013 + * Author: Victor Zappi + */ + +#include "PinkNoise.h" + +// miserable definition to init static const array members...otherwise gets error when PinkNoise.h is included into another header file +const float PinkNoise::A[] = { 0.02109238, 0.07113478, 0.68873558 }; // rescaled by (1+P)/(1-P) +const float PinkNoise::P[] = { 0.3190, 0.7756, 0.9613 }; + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/PinkNoise.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,49 @@ +#ifndef _PinkNoise_H +#define _PinkNoise_H + +// Technique by Larry "RidgeRat" Trammell 3/2006 +// http://home.earthlink.net/~ltrammell/tech/pinkalg.htm +// implementation and optimization by David Lowenfels + +#include <cstdlib> +#include <ctime> +#include <stdlib.h> + +#define PINK_NOISE_NUM_STAGES 3 + +class PinkNoise { +public: + PinkNoise() { + srand ( time(NULL) ); // initialize random generator + clear(); + } + + void clear() { + for( size_t i=0; i< PINK_NOISE_NUM_STAGES; i++ ) + state[ i ] = 0.0; + } + + float tick() { + static const float RMI2 = 2.0 / float(RAND_MAX); // + 1.0; // change for range [0,1) + static const float offset = A[0] + A[1] + A[2]; + + // unrolled loop + float temp = float( rand() ); + state[0] = P[0] * (state[0] - temp) + temp; + temp = float( rand() ); + state[1] = P[1] * (state[1] - temp) + temp; + temp = float( rand() ); + state[2] = P[2] * (state[2] - temp) + temp; + return ( A[0]*state[0] + A[1]*state[1] + A[2]*state[2] )*RMI2 - offset; + } + +protected: + float state[ PINK_NOISE_NUM_STAGES ]; + static const float A[ PINK_NOISE_NUM_STAGES ]; + static const float P[ PINK_NOISE_NUM_STAGES ]; +}; + +//const float PinkNoise::A[] = { 0.02109238, 0.07113478, 0.68873558 }; // rescaled by (1+P)/(1-P) +//const float PinkNoise::P[] = { 0.3190, 0.7756, 0.9613 }; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/StatusLED.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,90 @@ +/* + * StatusLED.cpp + * + * Routines for manipulating the status LED + * + * (c) 2014 Andrew McPherson and Victor Zappi + * QMUL, Centre for Digital Music + */ + +#include <iostream> +#include "StatusLED.h" +#include <GPIOcontrol.h> + +extern int gShouldStop; +extern int gVerbose; + +using namespace std; + +StatusLED::StatusLED() { + gpio_number = -1; + milliseconds_on = 0; + milliseconds_off = 100; + blink_thread = -1; +} + +StatusLED::~StatusLED() { + if(gpio_number >= 0) { + this_should_stop = true; + pthread_join(blink_thread, NULL); + gpio_unexport(gpio_number); + } +} + +bool StatusLED::init(int gpio_pin) { + gpio_number = gpio_pin; + this_should_stop = false; + + if(gpio_export(gpio_number)) { + if(gVerbose) + cout << "Warning: couldn't export status LED pin\n"; + } + if(gpio_set_dir(gpio_number, OUTPUT_PIN)) { + if(gVerbose) + cout << "Couldn't set direction on status LED pin\n"; + return false; + } + if(gpio_set_value(gpio_number, LOW)) { + if(gVerbose) + cout << "Couldn't set value on status LED pin\n"; + return false; + } + + + if ( pthread_create(&blink_thread, NULL, static_blink_loop, this) ) + { + cout << "Error:unable to create status LED thread" << endl; + return false; + } + + return true; +} + +void StatusLED::on() { + milliseconds_on = 100; + milliseconds_off = 0; +} + +void StatusLED::off() { + milliseconds_on = 0; + milliseconds_off = 100; +} + +void StatusLED::blink(int ms_on, int ms_off) { + milliseconds_on = ms_on; + milliseconds_off = ms_off; +} + +void* StatusLED::blink_loop(void *) { + while(!gShouldStop && !this_should_stop) { + if(milliseconds_on != 0) + gpio_set_value(gpio_number, HIGH); + usleep(1000 * milliseconds_on); + if(gShouldStop) + break; + if(milliseconds_off != 0) + gpio_set_value(gpio_number, LOW); + usleep(1000 * milliseconds_off); + } + pthread_exit(NULL); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/StatusLED.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,39 @@ +/* + * StatusLED.h + * + * + */ + +#ifndef STATUSLED_H_ +#define STATUSLED_H_ + +#include <pthread.h> +#include <unistd.h> + +class StatusLED +{ +public: + StatusLED(); + ~StatusLED(); + + bool init(int gpio_pin); + + void on(); + void off(); + void blink(int ms_on, int ms_off); + + static void *static_blink_loop(void *data) { + ((StatusLED*)data)->blink_loop(NULL); + return 0; + } + + void* blink_loop(void *); + +private: + int gpio_number; + int milliseconds_on, milliseconds_off; + bool this_should_stop; + pthread_t blink_thread; +}; + +#endif // STATUSLED_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/audio_routines.S Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,185 @@ +@ +@ audio_routines.S +@ +@ NEON-based functions for time-critical audio processing +@ +@ Andrew McPherson 2014 +@ Queen Mary University of London +@ + + .syntax unified + .arch armv7-a + .fpu neon + +@ void oscillator_bank_neon(int numAudioFrames, float *audioOut, +@ int activePartialNum, int lookupTableSize, +@ float *phases, float *frequencies, float *amplitudes, +@ float *freqDerivatives, float *ampDerivatives, +@ float *lookupTable); + +@ Registers: +@ r0: numAudioFrames How many frames to render +@ r1: audioOut Buffer for audio output samples [stereo] +@ r2: activePartialNum How many active partials to render +@ r3: lookupTableSize Size of lookup table +@ ---- other arguments start on the stack and are moved: ----- +@ r4: phases Phase of each oscillator (pointer) +@ r5: frequencies Normalised frequency of each oscillator (pointer) +@ r6: amplitudes Normalised amplitude of each oscillator (pointer) +@ r7: freqDerivatives Derivative of frequency for each oscillator (pointer) +@ r8: ampDerivatives Derivative of amplitude for each oscillator (pointer) +@ r9: lookupTable Lookup table containing one oscillation +@ +@ Alignment requirements: +@ audioOut: 8-byte boundary +@ phases: 16-byte boundary +@ frequencies: 16-byte boundary +@ amplitudes: 16-byte boundary +@ freqDerivatives: 16-byte bounary +@ ampDerivatives: 16-byte boundary +@ lookupTable: 4-byte boundary (TODO: check this) + + .align 2 + .global oscillator_bank_neon + .thumb + .thumb_func + .type oscillator_bank_neon, %function +oscillator_bank_neon: + + +dSample .dn D6.F32 +qPhases .qn Q8.F32 +dPhases_0 .dn D16.F32 +dPhases_1 .dn D17.F32 +qFreqs .qn Q9.F32 +dFreqs_0 .dn D18.F32 +dFreqs_1 .dn D19.F32 +qAmps .qn Q10.F32 +dAmps_0 .dn D20.F32 +dAmps_1 .dn D21.F32 +qFreqDs .qn Q11.F32 +dFreqDs_0 .dn D22.F32 +dFreqDs_1 .dn D23.F32 +qAmpDs .qn Q12.F32 +dAmpDs_0 .dn D24.F32 +dAmpDs_1 .dn D25.F32 + +qBaseInts .qn Q13.U32 @ Base indexes: unsigned ints x4 +dBaseInts_0 .dn D26.U32 +dBaseInts_1 .dn D27.U32 +qFractions .qn Q14.F32 @ Fraction indexes: floats x4 +qTableBase .qn Q15.U32 @ Base of lookup table + + cmp r0, #0 @ Check for trivial case 1: zero frames + it eq + bxeq lr @ Return if that's the case (otherwise might have odd behaviour) + cmp r2, #4 @ Check for trivial case 2: zero oscillators + it lt + bxlt lr @ Return if that's the case + + push {r4-r11} @ Now arguments start 32 bytes above SP + add r11, sp, #32 @ Pointer to 32 bytes into the stack + ldm r11, {r4-r9} @ Load 6 arguments into registers + + vdup qTableBase, r9 @ Move lookup table base index into 4 ints + + @ Outer loop: iterate over the number of oscillators, choosing 4 at a + @ time to work with. +oscbank_oscillator_loop: + vld1 {dPhases_0, dPhases_1}, [r4] @ no increment; will store at end of sample loop + vld1 {dFreqs_0, dFreqs_1}, [r5] + vld1 {dAmps_0, dAmps_1}, [r6] + vld1 {dFreqDs_0, dFreqDs_1}, [r7]! @ increment; won't update at end of sample loop + vld1 {dAmpDs_0, dAmpDs_1}, [r8]! + + push {r0-r1,r4-r8} + @ --- inner loop: iterate over the number of samples --- +oscbank_sample_loop: + vcvt qBaseInts, qPhases @ Take floor(phases) + vmov q2.f32, #1.0 @ Load 1.0 into every slot of q2 + vshl q0.U32, qBaseInts, #2 @ Shift the indexes left 2 (*4 for float addressing) + vcvt qFractions, qBaseInts @ int back to float + vadd q0.U32, q0.U32, qTableBase @ Find memory addresses + + vmov r4, r5, d0 @ Move two indexes to ARM registers + vmov r6, r7, d1 @ Move two more indexes to ARM registers + vsub qFractions, qPhases, qFractions @ fraction = phase - floor(phase) + + vldr.64 d0, [r4] @ Load two consecutive floats at each location + vldr.64 d1, [r5] @ These hold the previous and following samples in the table + vldr.64 d2, [r6] @ TODO: check whether these work at 4-byte alignment + vldr.64 d3, [r7] + + @ Format at this point: + @ Osc0(before) Osc0(after) Osc1(before) Osc1(after) Osc2(before) Osc2(after) Osc3(before) Osc3(after) + @ We want: + @ Osc0(before) Osc1(before) Osc2(before) Osc3(before) Osc0(after) Osc1(after) Osc2(after) Osc3(after) + + vuzp.32 q0, q1 @ Now q0 contains before, q1 contains after + vsub q2.f32, q2.f32, qFractions @ q2 = 1.0 - fraction + vmul q1.f32, q1.f32, qFractions @ q1 = fraction * after + vmul q0.f32, q0.f32, q2.f32 @ q0 = (1.0 - fraction) * before + + vadd qPhases, qPhases, qFreqs @ Update phases + vadd qFreqs, qFreqs, qFreqDs @ Update frequencies + + vadd q0.f32, q0.f32, q1.f32 @ Add two interpolated components to get the final sample + vdup q2.u32, r3 @ Put lookup table size into each element of q2 + vcvt qBaseInts, qPhases @ Take floor of new phases + vmul q0.f32, q0.f32, qAmps @ Multiply samples by current amplitude + + vld1 dSample, [r1] @ Load the current stereo samples + vpadd d2.f32, d0.f32, d1.f32 @ Pairwise accumulate q0 (output sample) into d2 + + vand q2, q2, qBaseInts @ Logical AND of new phase int leaves 1 bit set only if phase >= table size + vpadd d3.f32, d2.f32, d2.f32 @ Pairwise accumulate d2 into d0 --> d0[0] and d0[1] both hold total of 4 oscillators + vadd qAmps, qAmps, qAmpDs @ Update amplitudes + vcvt q0.f32, q2.u32 @ Convert int back to float after AND operation + + vadd dSample, dSample, d3.f32 @ Add oscillator outputs to each channel + + subs r0, r0, #1 @ numFrames-- + vsub qPhases, qPhases, q0.f32 @ Keep phases in table range + vst1 dSample, [r1]! @ Store back in buffer and increment by 8 + + it gt + bgt oscbank_sample_loop @ Loop if numFrames > 0 + + @ --- end inner loop --- + pop {r0-r1,r4-r8} @ Restore registers: restores audioOut and numFrames, among others + + vst1 {dPhases_0, dPhases_1}, [r4]! @ Store phases back to array + vst1 {dFreqs_0, dFreqs_1}, [r5]! @ Store frequencies back to array + vst1 {dAmps_0, dAmps_1}, [r6]! @ Store amplitudes back to array + @ No need to update r7, r8 + + subs r2, r2, #4 @ numPartials -= 4 + it gt + bgt oscbank_oscillator_loop @ Loop if numPartials > 0 + + pop {r4-r11} + bx lr + + +@ void wavetable_interpolate_neon(int numSamplesIn, int numSamplesOut, +@ float *tableIn, float *tableOut); + +@ Registers: +@ r0: numSamplesIn Size of the input table +@ r1: numSamplesOut Size of the output table +@ r2: tableIn Pointer to input table +@ r3: tableOut Pointer to output table + +@ Alignment requirements: +@ tableIn: 8-byte boundary +@ tableOut: 8-byte boundary + + .align 2 + .global wavetable_interpolate_neon + .thumb + .thumb_func + .type wavetable_interpolate_neon, %function +wavetable_interpolate_neon: + @ TODO + + bx lr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/config.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,43 @@ +/* + * config.h + * + * Global settings for D-Box project + * + * Andrew McPherson and Victor Zappi 2014 + */ + + +#ifndef DBOX_CONFIG_H_ +#define DBOX_CONFIG_H_ + + +/* Number of maximum touches used by the TouchKey sensors */ +#define MAX_TOUCHES 5 + +// for sensor 1 filter +#define EXP_DENOM 53.5981500331 // exp(4)-1 + +/* Define this to use Xenomai real-time extensions */ +#define DBOX_USE_XENOMAI +//#define OLD_OSCBANK + +#ifdef DBOX_USE_XENOMAI +// Xenomai-specific includes +#include <sys/mman.h> + +#include <native/task.h> +#include <native/timer.h> +#include <rtdk.h> +#endif + +#ifdef DBOX_USE_XENOMAI + +#define dbox_printf rt_printf + +#else + +#define dbox_printf printf + +#endif + +#endif /* DBOX_CONFIG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/how_to_build_dbox.txt Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,35 @@ +The D-Box code can be built on the board using the scripts included with +Bela. To build the code, do the following from the scripts/ directory: + +./setup_board.sh # Only if Bela is not already copied to the board +./build_project.sh -n ../projects/d-box # -n means don't run yet + +You will now need to copy the .dbx sound files to the box. These need to +be in a directory: /root/d-box/sounds + +Log into the board via ssh to create the d-box directory, or run: + +ssh root@192.168.7.2 "mkdir /root/d-box" + +Now copy the .dbx files from a source of your choice to the board. Assuming +they are in a directory called "sounds": + +scp -r sounds root@192.168.7.2:/root/d-box/ + +Now you can run the D-Box program to make sure it plays. You will need the +sensors and matrix connected to the box (i.e. a complete hardware D-Box). +From the scripts/ directory: + +./run_project.sh -f -c "-q 24 -r 25 -t 2 -s -p 2 -l 0 -u 0 -i 1 -n f -g 3 -v" + +If this plays properly, the D-Box can then be set to run automatically on boot: + +./set_startup.sh -l -c "-q 24 -r 25 -t 2 -s -p 2 -l 0 -u 0 -i 1 -n f -g 3 -v" + +If at any time you want to stop the D-Box program running, you can run: + +./stop_running.sh + +To turn off further autoboot, run: + +./set_startup.sh -n
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/logger.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,188 @@ +/* + * logger.cpp + * + * Created on: Aug 6, 2014 + * Author: VIctor Zappi and Andrew McPherson + */ + +#include "logger.h" + +// main extern vars +extern int gShouldStop; +extern int gVerbose; + +// file nanme extern vars +extern char gId; +extern char gGroup; + + +// logged extern vars +extern int s0TouchNum; +extern float s0Touches_[MAX_TOUCHES]; +extern float s0Size_[MAX_TOUCHES]; +extern int s0LastIndex; + +extern int s1TouchNum; +extern float s1Touches_[MAX_TOUCHES]; +extern float s1Size_[MAX_TOUCHES]; +extern int s1LastIndex; + +extern int fsr; + + + +string logPath = "/boot/uboot/instrumentLog"; +string logFileIncipit = "/datalog"; +string logFileName = ""; +ofstream logFile; +timeval logTimeVal; +unsigned long long logTimeOrig; +int logCnt = 0; // counts how many lines so far +int logCntSwap = 50; // how many log lines before closing and re-opening the file + + +// create the log file, using incremental name convention +int initLogLoop() +{ + if(gVerbose==1) + cout << "---------------->Init Log Thread" << endl; + + + // transform chars into strings via stringstream objs + stringstream id_ss, group_ss, freedom_ss; + id_ss << gId; + group_ss << gGroup; + + int logNum = -1; + int logMax = -1; + int pathLen = logPath.length() + logFileIncipit.length() + 4; // + 4 is: "_", id, group, "_" + glob_t globbuf; + + // check how many log files are already there, and choose name according to this + glob( (logPath + logFileIncipit + "*").c_str(), 0, NULL, &globbuf); + + // cycle through all and find the highest index + for(unsigned int i=0; i<globbuf.gl_pathc; i++) + { + // playing with 0-9 char digits, forming a number from 0 to 9999 + logNum = (globbuf.gl_pathv[i][pathLen]-48) * 1000; // 42 to 45 are the indices of the chars forming the file index + logNum += (globbuf.gl_pathv[i][pathLen+1]-48) * 100; + logNum += (globbuf.gl_pathv[i][pathLen+2]-48) * 10; + logNum += globbuf.gl_pathv[i][pathLen+3]-48; + if(logNum > logMax) + logMax = logNum; + } + logNum = logMax + 1; // new index + + globfree(&globbuf); + + ostringstream numString; + numString << setw (4) << setfill ('0') << logNum; // set integer with 4 figures + + // here are the new names: PATH + DIR + INCIPIT + _ + id + group + freedom + _ + NUM (4figures) + _A.txt + logFileName = logPath + logFileIncipit; + logFileName += "_" + id_ss.str() + group_ss.str() + freedom_ss.str(); + logFileName += "_" + numString.str(); //static_cast<ostringstream*>( &(ostringstream() << logNum) )->str(); + logFileName += ".txt"; + + + // create new files + FILE *fp_a = fopen(logFileName.c_str(), "wb"); + if(!fp_a) + { + dbox_printf("Cannot create files...\n"); + return 2; + } + fclose(fp_a); + + // ready to append + logFile.open(logFileName.c_str(), ios::out | ios::app); + + dbox_printf("Logging on file %s\n", logFileName.c_str()); + + return 0; +} + + +void writeData(unsigned long long time) +{ + + float fsr_ = ((float)(1799-fsr)/1799.0); + logFile << time << "\t" // timestamp + << s0TouchNum << "\t"; // sensor 0 touch count + for(int i=0; i<MAX_TOUCHES; i++) + logFile << s0Touches_[i] << "\t"; // sensor 0 touch pos x + for(int i=0; i<MAX_TOUCHES; i++) + logFile << s0Size_[i] << "\t"; // sensor 0 touch size + logFile << s0LastIndex << "\t" // sensor 0 last index + << fsr_ << "\t" // sensor 0 FSR pressure + << s1TouchNum << "\t"; // sensor 1 touch count + for(int i=0; i<MAX_TOUCHES; i++) + logFile << s1Touches_[i] << "\t"; // sensor 1 touch pos x + for(int i=0; i<MAX_TOUCHES; i++) + logFile << s1Size_[i] << "\t"; // sensor 1 touch size + logFile << s1LastIndex << "\t" // sensor 1 last index + //... AND SO ON + << "\n"; + + //dbox_printf("%d\n", s0LastIndex); + //dbox_printf("s0TouchNum: %d\t s0Touches[0]: %f\t s0Size[0]: %f\t s0LastIndex: %d\n", s0TouchNum, s0Touches_[0], s0Size_[0], s0LastIndex); + +} + +void logData(unsigned long long time) +{ + // if it's time to change write-file + if(logCnt >= logCntSwap) + { + logFile.close(); // close file, dump stream + logCnt = 0; // ready for another whole round + + // open again, ready to append + logFile.open(logFileName.c_str(), ios::out | ios::app); + } + + writeData(time); + + logCnt++; +} + + + + +void *logLoop(void *) +{ + set_realtime_priority(10); + + if(gVerbose==1) + dbox_printf("_________________Log Thread!\n"); + + // get time reference + gettimeofday(&logTimeVal, NULL); + logData(0); + + logTimeOrig = logTimeVal.tv_usec; + logTimeOrig *= 0.001; // from usec to msec + logTimeOrig += logTimeVal.tv_sec*1000; // from sec to msec + + usleep(5000); + + while(!gShouldStop) + { + gettimeofday(&logTimeVal, NULL); + unsigned long long currentTime = logTimeVal.tv_usec; + currentTime *= 0.001; // from usec to msec + currentTime += logTimeVal.tv_sec*1000; // from sec to msec + + logData(currentTime-logTimeOrig); + + usleep(5000); + } + + if(logFile!=NULL) + logFile.close(); + + dbox_printf("log thread ended\n"); + + return (void *)0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/logger.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,31 @@ +/* + * logger.h + * + * Created on: Aug 6, 2014 + * Author: Victor Zappi and Andrew McPherson + */ + +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#include <string.h> +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <fstream> // file handle +#include <iostream> // stringstream +#include <sstream> // stringstream +#include <glob.h> // alternative to dirent.h to handle files in dirs +#include <iomanip> // setfill +#include <sys/time.h> // elapsed time + +#include "config.h" +#include "prio.h" + +using namespace std; + +int initLogLoop(); +void *logLoop(void *); + + +#endif /* LOGGER_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,491 @@ +/* + * RTAudio.cpp + * + * Central control code for hard real-time audio on BeagleBone Black + * using PRU and Xenomai Linux extensions. This code began as part + * of the Hackable Instruments project (EPSRC) at Queen Mary University + * of London, 2013-14. + * + * (c) 2014 Victor Zappi and Andrew McPherson + * Queen Mary University of London + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <math.h> +#include <iostream> +#include <signal.h> // interrupt handler +#include <assert.h> +#include <vector> +#include <dirent.h> // to handle files in dirs +#include <mntent.h> // to check if device is mounted +#include <sys/mount.h> // mount() +#include <sys/time.h> // elapsed time +#include <ne10/NE10.h> // neon library + +// thread priority +#include <pthread.h> +#include <sched.h> + +// get_opt_long +#include <getopt.h> + +#include <Bela.h> +#include "config.h" +#include "sensors.h" +#include "OscillatorBank.h" +#include "StatusLED.h" +#include "logger.h" + +using namespace std; + +//---------------------------------------- +// main variables +//---------------------------------------- +vector<OscillatorBank*> gOscBanks; +int gCurrentOscBank = 0; +int gNextOscBank = 0; +int oscBnkOversampling = 1; // oscillator bank frame oversampling + +const int kStatusLEDPin = 30; // P9-11 controls status LED +StatusLED gStatusLED; + +pthread_t keyboardThread; +pthread_t logThread; + +// general settings +int gVerbose = 0; // verbose flag +bool forceKeyboard = true; // activate/deactivate keyboard control +bool forceSensors = false; // activate/deactivate sensor control +bool forceLog = true; // activate/deactivate log on boot partition +bool useSD = true; // activate/deactivate file loading from SD [as opposed to emmc] +bool useAudioTest = false; // activate/deactivate sensors and test audio only + +// audio settings +unsigned int gPeriodSize = 8; // period size for audio +char* gPartialFilename = 0; // name of the partials file to load +bool gAudioIn = false; // stereo audio in status + +int touchSensor0Address = 0x0C; // I2C addresses of touch sensors +int touchSensor1Address = 0x0B; +int sensorType = 0; + +char sdPath[256] = "/dev/mmcblk0p2"; // system path of the SD, partition 2 +char mountPath[256] = "/root/d-box/usersounds"; // mount point of SD partition 2 [where user files are] +char gUserDirName[256] = "usersounds"; // Directory in which user analysis files can be found [dir of mountPath] +char gDefaultDirName[256] = "/root/d-box/sounds"; // Directory in which built in analysis files can be found +char *gDirName; +bool gIsLoading = false; +int fileCnt = 0; +std::vector <std::string> files; + +char gId = 'f'; // from 0 to 14, hexadecimal [0-d]! f means not set +char gGroup = '2'; // 0 is no info, 1 info. 2 is not set + +// audio in filter +extern ne10_float32_t *filterState[2]; +extern ne10_float32_t *filterIn[2]; +extern ne10_float32_t *filterOut[2]; + +struct arg_data +{ + int argc; + char **argv; +}; + +arg_data args; + + +int readFiles() +{ + if(useSD) + gDirName = gUserDirName; + else + gDirName = gDefaultDirName; + DIR *dir; + struct dirent *ent; + + // From http://stackoverflow.com/questions/612097/how-can-i-get-a-list-of-files-in-a-directory-using-c-or-c + if ((dir = opendir (gDirName)) != NULL) { + /* print all the files and directories within directory */ + while ((ent = readdir (dir)) != NULL) { + // Ignore dotfiles and . and .. paths + if(!strncmp(ent->d_name, ".", 1)) + continue; + + //dbox_printf("%s\n", ent->d_name); + + // take only .dbx and .txt files + string name = string(ent->d_name); + int len = name.length(); + + bool dboxFile = false; + + if( (name[len-4]=='.') && (name[len-3]=='d') && (name[len-2]=='b') && (name[len-1]=='x') ) + dboxFile = true; + if( (name[len-4]=='.') && (name[len-3]=='t') && (name[len-2]=='x') && (name[len-1]=='t') ) + dboxFile = true; + + if(dboxFile) + { + fileCnt++; + //dbox_printf("%s\n", ent->d_name); + files.push_back( std::string( ent->d_name ) ); + } + } + closedir (dir); + } else { + /* could not open directory */ + printf("Could not open directory %s\n", gDirName); + return 1; + } + + // order by name + std::sort( files.begin(), files.end() ); + + if(fileCnt==0) + { + printf("No .dbx or .txt files in %s!\n", gDirName); + return 1; + } + + return 0; +} + +/* Load sounds from the directory */ +void loadAudioFiles(bool loadFirstFile) +{ + char fullFileName[256]; + + if(loadFirstFile) { + strcpy(fullFileName, gDirName); + strcat(fullFileName, "/"); + strncat(fullFileName, files[0].c_str(), 255 - strlen(gDirName)); + dbox_printf("Loading first file %s...\n", fullFileName); + OscillatorBank *bank = new OscillatorBank(fullFileName); + if(bank->initBank(oscBnkOversampling)) { + bank->setLoopHops(100, bank->getLastHop()); + gOscBanks.push_back(bank); + } + } + + else { + for(int i=1; i<fileCnt; i++){ + strcpy(fullFileName, gDirName); + strcat(fullFileName, "/"); + strncat(fullFileName, files[i].c_str(), 255 - strlen(gDirName)); + dbox_printf("Loading file %s...\n", fullFileName); + OscillatorBank *bank = new OscillatorBank(fullFileName); + if(bank->initBank(oscBnkOversampling)) { + bank->setLoopHops(100, bank->getLastHop()); + gOscBanks.push_back(bank); + } + } + } +} + +// adapted from http://program-nix.blogspot.co.uk/2008/08/c-language-check-filesystem-is-mounted.html +int checkIfMounted (char * dev_path) +{ + FILE * mtab = NULL; + struct mntent * part = NULL; + int is_mounted = 0; + + if ( ( mtab = setmntent ("/etc/mtab", "r") ) != NULL) + { + while ( ( part = getmntent ( mtab) ) != NULL) + { + if ( ( part->mnt_fsname != NULL ) && ( strcmp ( part->mnt_fsname, dev_path ) ) == 0 ) + is_mounted = 1; + } + endmntent(mtab); + } + return is_mounted; +} + +int mountSDuserPartition() +{ + if(checkIfMounted(sdPath)) + { + printf("device %s already mounted, fair enough, let's move on\n", sdPath); + return 0; + } + // if mount rootfs from SD [rootfs eMMC not used] or from eMMC via properly formatted SD [SD rootfs used as storage volume] + // we always use rootfs on SD as storage volume ----> "/dev/mmcblk0p2" + int ret = mount(sdPath, "/root/d-box/usersounds", "vfat", 0, NULL); + if (ret!=0) + { + printf("Error in mount...%s\n", strerror(ret)); + return 1; + } + return 0; +} + +int initSoundFiles() +{ + if(gVerbose==1) + cout << "---------------->Init Audio Thread" << endl; + + if(useSD) + { + // mount the SD partition where user sounds are located + // [this is p2, p1 is already mounted and we will log data there] + if(mountSDuserPartition()!=0) + return -1; + } + + gIsLoading = true; + + // read files from SD and order them alphabetically + if(readFiles()!=0) + return 1; + + // load first file into oscBank + loadAudioFiles(true); + + return 0; +} + +//--------------------------------------------------------------------------------------------------------- + +// Handle Ctrl-C +void interrupt_handler(int var) +{ + // kill keyboard thread mercilessly + if(forceKeyboard) + pthread_cancel(keyboardThread); + + gShouldStop = true; +} + + +void parseArguments(arg_data args, BelaInitSettings *settings) +{ + // Default filename; + gPartialFilename = strdup("D-Box_sound_250_60_40_h88_2.txt"); + + const int kOptionAudioTest = 1000; + + // TODO: complete this + struct option long_option[] = + { + {"help", 0, NULL, 'h'}, + {"audioin", 1, NULL, 'i'}, + {"file", 1, NULL, 'f'}, + {"keyboard", 1, NULL, 'k'}, + {"audio-test", 0, NULL, kOptionAudioTest}, + {"sensor-type", 1, NULL, 't'}, + {"sensor0", 1, NULL, 'q'}, + {"sensor1", 1, NULL, 'r'}, + {"log", 1, NULL, 'l'}, + {"usesd", 1, NULL, 'u'}, + {"oversamp", 1, NULL, 'o'}, + {"boxnumber", 1, NULL, 'n'}, + {"group", 1, NULL, 'g'}, + {NULL, 0, NULL, 0}, + }; + int morehelp = 0; + int tmp = -1; + + Bela_defaultSettings(settings); + + while (1) + { + int c; + if ((c = Bela_getopt_long(args.argc, args.argv, "hf:ki:sq:r:t:l:u:o:n:g:", long_option, settings)) < 0) + break; + switch (c) + { + case 'h': + morehelp++; + break; + case 'f': + free(gPartialFilename); + gPartialFilename = strdup(optarg); + break; + case 'k': + forceKeyboard = true; + break; + case 'i': + gAudioIn = (atoi(optarg)==0) ? false : true; + break; + case 's': + forceSensors = true; + break; + case kOptionAudioTest: + useAudioTest = true; + break; + case 't': + sensorType = atoi(optarg); + break; + case 'q': + touchSensor0Address = atoi(optarg); + break; + case 'r': + touchSensor1Address = atoi(optarg); + break; + case 'l': + tmp = atoi(optarg); + if(tmp==0) + forceLog = false; + else if(tmp>0) + forceLog = true; + break; + case 'u': + tmp = atoi(optarg); + if(tmp==0) + useSD = false; + else if(tmp>0) + useSD = true; + break; + case 'o': + oscBnkOversampling = atoi(optarg); + break; + case 'n': + gId = *optarg; + cout << "-set box number to: " << gId << endl; + break; + case 'g': + gGroup = *optarg; + cout << "-set group to: " << gId << endl; + break; + default: + break; + } + } + + gPeriodSize = settings->periodSize; + gVerbose = settings->verbose; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + RT_TASK rtSensorThread; + const char rtSensorThreadName[] = "dbox-sensor"; + int oscBankHopSize; + + // Parse command-line arguments + args.argc = argc; + args.argv = argv; + parseArguments(args, &settings); + + Bela_setVerboseLevel(gVerbose); + if(gVerbose == 1 && useAudioTest) + cout << "main() : running in audio test mode" << endl; + + // Load sound files from directory + if(initSoundFiles() != 0) + return -1; + + oscBankHopSize = gOscBanks[gCurrentOscBank]->getHopSize()/gOscBanks[gCurrentOscBank]->getMinSpeed(); + + // Initialise the audio device + if(Bela_initAudio(&settings, &oscBankHopSize) != 0) + return -1; + + // Initialise the status LED + if(!gStatusLED.init(kStatusLEDPin)) { + if(gVerbose) + cout << "Couldn't initialise status LED pin\n"; + } + + // Free file name string which is no longer needed + if(gPartialFilename != 0) + free(gPartialFilename); + + if(!useAudioTest) { + if(initSensorLoop(touchSensor0Address, touchSensor1Address, sensorType) != 0) + return -1; + } + + if(gVerbose == 1) + cout << "main() : creating audio thread" << endl; + + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // LED on... + gStatusLED.on(); + + if(forceSensors && !useAudioTest) { + if(gVerbose==1) + cout << "main() : creating control thread" << endl; + + if(rt_task_create(&rtSensorThread, rtSensorThreadName, 0, BELA_AUDIO_PRIORITY - 5, T_JOINABLE | T_FPU)) { + cout << "Error:unable to create Xenomai control thread" << endl; + return -1; + } + if(rt_task_start(&rtSensorThread, &sensorLoop, 0)) { + cout << "Error:unable to start Xenomai control thread" << endl; + return -1; + } + } + + if(forceKeyboard) { + if(gVerbose==1) + cout << "main() : creating keyboard thread" << endl; + + if ( pthread_create(&keyboardThread, NULL, keyboardLoop, NULL) ) { + cout << "Error:unable to create keyboard thread" << endl; + return -1; + } + } + + if(forceLog) { + if(gVerbose==1) + cout << "main() : creating log thread" << endl; + + if(initLogLoop()!=0) { + cout << "Error:unable to create log thread" << endl; + return -1; + } + + if ( pthread_create(&logThread, NULL, logLoop, NULL) ) { + cout << "Error:unable to create keyboard thread" << endl; + return -1; + } + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // load all other files into oscBanks + loadAudioFiles(false); + cout << "Finished loading analysis files\n"; + gIsLoading = false; + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + Bela_stopAudio(); + + if(!useAudioTest) + rt_task_join(&rtSensorThread); + + Bela_cleanupAudio(); + + pthread_join( keyboardThread, NULL); + pthread_join( logThread, NULL); + + for(unsigned int i = 0; i < gOscBanks.size(); i++) + delete gOscBanks[i]; + + NE10_FREE(filterState[0]); + NE10_FREE(filterState[1]); + NE10_FREE(filterIn[0]); + NE10_FREE(filterIn[1]); + NE10_FREE(filterOut[0]); + NE10_FREE(filterOut[1]); + + printf("Program ended\nBye bye\n"); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/prio.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,48 @@ +/* + * prio.cpp + * + * Created on: May 14, 2014 + * Author: Victor Zappi + */ + +#include "prio.h" +using namespace std; +//----------------------------------------------------------------------------------------------------------- +// set wanted real-time priority to this thread +//----------------------------------------------------------------------------------------------------------- +void set_realtime_priority(int order) +{ + int ret; + + // We'll operate on the currently running thread. + pthread_t this_thread = pthread_self(); + // struct sched_param is used to store the scheduling priority + struct sched_param params; + // We'll set the priority to the maximum. + params.sched_priority = sched_get_priority_max(SCHED_FIFO) - order; + + // Attempt to set thread real-time priority to the SCHED_FIFO policy + ret = pthread_setschedparam(this_thread, SCHED_FIFO, ¶ms); + if (ret != 0) { + // Print the error + cout << "Unsuccessful in setting thread realtime prio" << endl; + return; + } + + // Now verify the change in thread priority + int policy = 0; + ret = pthread_getschedparam(this_thread, &policy, ¶ms); + if (ret != 0) { + cout << "Couldn't retrieve real-time scheduling parameters" << endl; + return; + } + + // Check the correct policy was applied + if(policy != SCHED_FIFO) { + cout << "Scheduling is NOT SCHED_FIFO!" << endl; + } +} + +//----------------------------------------------------------------------------------------------------------- + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/prio.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,22 @@ +/* + * prio.h + * + * Created on: May 14, 2014 + * Author: Victor Zappi + */ + +#ifndef PRIO_H_ +#define PRIO_H_ + + +#include <pthread.h> +#include <sched.h> +#include <iostream> + +//----------------------------------------------------------------------------------------------------------- +// set maximum real-time priority to this thread +//----------------------------------------------------------------------------------------------------------- +void set_realtime_priority(int order); +//----------------------------------------------------------------------------------------------------------- + +#endif /* PRIO_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,870 @@ +/* + * render.cpp + * + * Created on: May 28, 2014 + * Author: Victor Zappi + */ + +#include <Bela.h> +#include <PRU.h> + +#include "StatusLED.h" +#include "config.h" +#include "OscillatorBank.h" +#include "FeedbackOscillator.h" +#include "ADSR.h" +#include "FIRfilter.h" +#include <assert.h> +#include <cmath> +#include <vector> + +#undef DBOX_CAPE_TEST + +// Mappings from pin numbers on PCB to actual DAC channels +// This gives the DAC and ADC connectors the same effective pinout +// Update June 2016: this is no longer needed in the latest Bela +// release, but is kept here for convenience: it used to be +// 6 4 2 0 1 3 5 7 for the DAC pins +#define DAC_PIN0 0 +#define DAC_PIN1 1 +#define DAC_PIN2 2 +#define DAC_PIN3 3 +#define DAC_PIN4 4 +#define DAC_PIN5 5 +#define DAC_PIN6 6 +#define DAC_PIN7 7 + +#define ADC_PIN0 0 +#define ADC_PIN1 1 +#define ADC_PIN2 2 +#define ADC_PIN3 3 +#define ADC_PIN4 4 +#define ADC_PIN5 5 +#define ADC_PIN6 6 +#define ADC_PIN7 7 + +#define N_OCT 4.0 // maximum number of octaves on sensor 1 + +extern vector<OscillatorBank*> gOscBanks; +extern int gCurrentOscBank; +extern int gNextOscBank; +extern PRU *gPRU; +extern StatusLED gStatusLED; +extern bool gIsLoading; +extern bool gAudioIn; + +float *gOscillatorBuffer1, *gOscillatorBuffer2; +float *gOscillatorBufferRead, *gOscillatorBufferWrite; +int gOscillatorBufferReadPointer = 0; +int gOscillatorBufferReadCurrentSize = 0; +int gOscillatorBufferWriteCurrentSize = 0; +bool gOscillatorNeedsRender = false; + +int gMatrixSampleCount = 0; // How many samples have elapsed on the matrix + +// Wavetable which changes in response to an oscillator +float *gDynamicWavetable; +int gDynamicWavetableLength; +bool gDynamicWavetableNeedsRender = false; + +// These variables handle the hysteresis oscillator used for setting the playback speed +bool gSpeedHysteresisOscillatorRising = false; +int gSpeedHysteresisLastTrigger = 0; + +// These variables handle the feedback oscillator used for controlling the wavetable +FeedbackOscillator gFeedbackOscillator; +float *gFeedbackOscillatorTable; +int gFeedbackOscillatorTableLength; + +// This comes from sensor.cpp where it records the most recent touch location on +// sensor 0. +extern float gSensor0LatestTouchPos; +extern int gSensor0LatestTouchNum; +float gPitchLatestInput = 0; + +extern float gSensor1LatestTouchPos[]; +//extern float gSensor1LatestTouchSizes[]; +extern int gSensor1LatestTouchCount; +extern int gSensor1LatestTouchIndex; +int gSensor1LastTouchIndex = -1; +int gSensor1InputDelayCounter = -1; +int gSensor1InputIndex = 0; +float gSensor1MatrixTouchPos[5] = {0}; + +// FSR value from matrix input +extern int gLastFSRValue; + +// Loop points from matrix input 4 +const int gLoopPointsInputBufferSize = 256; +float gLoopPointsInputBuffer[gLoopPointsInputBufferSize]; +int gLoopPointsInputBufferPointer = 0; +float gLoopPointMin = 0, gLoopPointMax = 0; + +// multiplier to activate or mute audio in +int audioInStatus = 0; + +// xenomai timer +SRTIME prevChangeNs = 0; + +// pitch vars +float octaveSplitter; +float semitones[((int)N_OCT*12)+1]; +float deltaTouch = 0; +float deltaWeightP = 0.5 / 65536.0; +float deltaWeightI = 0.0005 / 65536.0; + +// filter vars +ne10_fir_instance_f32_t filter[2]; +ne10_float32_t *filterIn[2]; +ne10_float32_t *filterOut[2]; +ne10_uint32_t blockSize; +ne10_float32_t *filterState[2]; +ne10_float32_t prevFiltered[2]; +int filterGain = 80; +ADSR PeakBurst[2]; +float peak[2]; +float peakThresh = 0.2; + +// Tasks for lower-priority calculation +AuxiliaryTask gMediumPriorityRender, gLowPriorityRender; + + +extern "C" { + // Function prototype for ARM assembly implementation of oscillator bank + void oscillator_bank_neon(int numAudioFrames, float *audioOut, + int activePartialNum, int lookupTableSize, + float *phases, float *frequencies, float *amplitudes, + float *freqDerivatives, float *ampDerivatives, + float *lookupTable); + + void wavetable_interpolate_neon(int numSamplesIn, int numSamplesOut, + float *tableIn, float *tableOut); +} + +void wavetable_interpolate(int numSamplesIn, int numSamplesOut, + float *tableIn, float *tableOut, + float *sineTable, float sineMix); + +inline float hysteresis_oscillator(float input, float risingThreshold, + float fallingThreshold, bool *rising); + +void render_medium_prio(); +void render_low_prio(); + +#ifdef DBOX_CAPE_TEST +void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, + uint16_t *matrixIn, uint16_t *matrixOut); +#endif + +bool setup(BelaContext *context, void *userData) { + int oscBankHopSize = *(int *)userData; + + if(context->analogChannels != 8) { + printf("Error: D-Box needs matrix enabled with 8 channels.\n"); + return false; + } + + // Allocate two buffers for rendering oscillator bank samples + // One will be used for writing in the background while the other is used for reading + // on the audio thread. 8-byte alignment needed for the NEON code. + if(posix_memalign((void **)&gOscillatorBuffer1, 8, oscBankHopSize * context->audioChannels * sizeof(float))) { + printf("Error allocating render buffers\n"); + return false; + } + if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * context->audioChannels * sizeof(float))) { + printf("Error allocating render buffers\n"); + return false; + } + gOscillatorBufferWrite = gOscillatorBuffer1; + gOscillatorBufferRead = gOscillatorBuffer2; + + memset(gOscillatorBuffer1, 0, oscBankHopSize * context->audioChannels * sizeof(float)); + memset(gOscillatorBuffer2, 0, oscBankHopSize * context->audioChannels * sizeof(float)); + + // Initialise the dynamic wavetable used by the oscillator bank + // It should match the size of the static one already allocated in the OscillatorBank object + // Don't forget a guard point at the end of the table + gDynamicWavetableLength = gOscBanks[gCurrentOscBank]->lookupTableSize; + if(posix_memalign((void **)&gDynamicWavetable, 8, (gDynamicWavetableLength + 1) * sizeof(float))) { + printf("Error allocating wavetable\n"); + return false; + } + + gFeedbackOscillator.initialise(8192, 10.0, context->analogSampleRate); + + for(int n = 0; n < gDynamicWavetableLength + 1; n++) + gDynamicWavetable[n] = 0; + + // pitch + float midPos = 0.5; + octaveSplitter = 1.0 / N_OCT; + int numOfSemi = 12*N_OCT; + int middleSemitone = 12*N_OCT/2; + int lastSemitone = middleSemitone+numOfSemi/2; + float inc = 1.0 / (N_OCT*12.0); + int i = -1; + for(int semi=middleSemitone; semi<=lastSemitone; semi++) + semitones[semi] = ( midPos + (++i)*inc) + 0.5; + i = 0; + for(int semi=middleSemitone-1; semi>=0; semi--) + semitones[semi] = ( midPos - (++i)*inc) + 0.5; + + if(gAudioIn) + audioInStatus = 1; + + // filter + blockSize = context->audioFrames; + filterState[0] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); + filterState[1] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); + filterIn[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); + filterIn[1] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); + filterOut[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); + filterOut[1] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); + ne10_fir_init_float(&filter[0], FILTER_TAP_NUM, filterTaps, filterState[0], blockSize); + ne10_fir_init_float(&filter[1], FILTER_TAP_NUM, filterTaps, filterState[1], blockSize); + + // peak outputs + PeakBurst[0].setAttackRate(.00001 * context->analogSampleRate); + PeakBurst[1].setAttackRate(.00001 * context->analogSampleRate); + PeakBurst[0].setDecayRate(.5 * context->analogSampleRate); + PeakBurst[1].setDecayRate(.5 * context->analogSampleRate); + PeakBurst[0].setSustainLevel(0.0); + PeakBurst[1].setSustainLevel(0.0); + + // Initialise auxiliary tasks + if((gMediumPriorityRender = Bela_createAuxiliaryTask(&render_medium_prio, BELA_AUDIO_PRIORITY - 10, "dbox-calculation-medium")) == 0) + return false; + if((gLowPriorityRender = Bela_createAuxiliaryTask(&render_low_prio, BELA_AUDIO_PRIORITY - 15, "dbox-calculation-low")) == 0) + return false; + + return true; +} + +void render(BelaContext *context, void *userData) +{ +#ifdef DBOX_CAPE_TEST + render_capetest(numMatrixFrames, numAudioFrames, audioIn, audioOut, matrixIn, matrixOut); +#else + if(gOscBanks[gCurrentOscBank]->state==bank_toreset) + gOscBanks[gCurrentOscBank]->resetOscillators(); + + if(gOscBanks[gCurrentOscBank]->state==bank_playing) + { + assert(context->audioChannels == 2); + +#ifdef OLD_OSCBANK + memset(audioOut, 0, numAudioFrames * * sizeof(float)); + + /* Render the oscillator bank. The oscillator bank function is written in NEON assembly + * and it strips out all extra checks, so find out in advance whether we can render a whole + * block or whether the frame will increment in the middle of this buffer. + */ + + int framesRemaining = numAudioFrames; + float *audioOutWithOffset = audioOut; + + while(framesRemaining > 0) { + if(gOscBanks[gCurrentOscBank]->hopCounter >= framesRemaining) { + /* More frames left in this hop than we need this time. Render and finish */ + oscillator_bank_neon(framesRemaining, audioOutWithOffset, + gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, + gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies, + gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, + gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, + gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, + gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/); + gOscBanks[gCurrentOscBank]->hopCounter -= framesRemaining; + if(gOscBanks[gCurrentOscBank]->hopCounter <= 0) + gOscBanks[gCurrentOscBank]->nextHop(); + framesRemaining = 0; + } + else { + /* More frames to render than are left in this hop. Render and decrement the + * number of remaining frames; then advance to the next oscillator frame. + */ + oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, audioOutWithOffset, + gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, + gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies, + gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, + gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, + gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, + gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/); + framesRemaining -= gOscBanks[gCurrentOscBank]->hopCounter; + audioOutWithOffset += * gOscBanks[gCurrentOscBank]->hopCounter; + gOscBanks[gCurrentOscBank]->sampleCount += gOscBanks[gCurrentOscBank]->hopCounter; + gOscBanks[gCurrentOscBank]->nextHop(); + } + } +#else + for(unsigned int n = 0; n < context->audioFrames; n++) { + context->audioOut[2*n] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n]*audioInStatus; + context->audioOut[2*n + 1] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n+1]*audioInStatus; + + filterIn[0][n] = fabs(context->audioIn[2*n]); // rectify for peak detection in 1 + filterIn[1][n] = fabs(context->audioIn[2*n+1]); // rectify for peak detection in 2 + + /* FIXME why doesn't this work? */ + /* + if(gOscillatorBufferReadPointer == gOscillatorBufferCurrentSize/2) { + gOscillatorNeedsRender = true; + scheduleAuxiliaryTask(gLowPriorityRender); + } */ + + if(gOscillatorBufferReadPointer >= gOscillatorBufferReadCurrentSize) { + // Finished reading from the buffer: swap to the next buffer + if(gOscillatorBufferRead == gOscillatorBuffer1) { + gOscillatorBufferRead = gOscillatorBuffer2; + gOscillatorBufferWrite = gOscillatorBuffer1; + } + else { + gOscillatorBufferRead = gOscillatorBuffer1; + gOscillatorBufferWrite = gOscillatorBuffer2; + } + + // New buffer size is whatever finished writing last hop + gOscillatorBufferReadCurrentSize = gOscillatorBufferWriteCurrentSize; + gOscillatorBufferReadPointer = 0; + + gOscillatorNeedsRender = true; + Bela_scheduleAuxiliaryTask(gMediumPriorityRender); + } + } +#endif + } + else + { + for(unsigned int n = 0; n < context->audioFrames; n++) { + context->audioOut[2*n] = context->audioIn[2*n]*audioInStatus; + context->audioOut[2*n + 1] = context->audioIn[2*n+1]*audioInStatus; + + filterIn[0][n] = fabs(context->audioIn[2*n]); // rectify for peak detection in 1 + filterIn[1][n] = fabs(context->audioIn[2*n+1]); // rectify for peak detection in 2 + } + } + + // low pass filter audio in 1 and 2 for peak detection + ne10_fir_float_neon(&filter[0], filterIn[0], filterOut[0], blockSize); + ne10_fir_float_neon(&filter[1], filterIn[1], filterOut[1], blockSize); + + for(unsigned int n = 0; n < context->analogFrames; n++) { + + + /* Matrix Out 0, In 0 + * + * CV loop + * Controls pitch of sound + */ + float touchPosInt = gSensor0LatestTouchPos; + if(touchPosInt < 0) touchPosInt = 0; + if(touchPosInt > 1.0) touchPosInt = 1.0; + context->analogOut[n*8 + DAC_PIN0] = touchPosInt; + + gPitchLatestInput = context->analogIn[n*8 + ADC_PIN0]; + + + /* Matrix Out 7 + * + * Loop feedback with Matrix In 0 + * Controls discreet pitch + */ + float deltaTarget = 0; + int semitoneIndex = 0; + if(gSensor0LatestTouchNum>0) + { + // current pitch is gPitchLatestInput, already retrieved + semitoneIndex = ( gPitchLatestInput * 12 * N_OCT )+0.5; // closest semitone + deltaTarget = (semitones[semitoneIndex]-gPitchLatestInput); // delta between pitch and target + deltaTouch += deltaTarget*(deltaWeightI); // update feedback [previous + current] + } + else + deltaTouch = 0; + + float nextOut = touchPosInt + deltaTarget*deltaWeightP + deltaTouch; // add feedback to touch -> next out + if(nextOut < 0) nextOut = 0; // clamp + if(nextOut > 1.0) nextOut = 1.0; // clamp + context->analogOut[n*8 + DAC_PIN7] = nextOut; // send next nextOut + + + /* + * Matrix Out 1, In 1 + * + * Hysteresis (comparator) oscillator + * Controls speed of playback + */ + bool wasRising = gSpeedHysteresisOscillatorRising; + context->analogOut[n*8 + DAC_PIN1] = hysteresis_oscillator(context->analogIn[n*8 + ADC_PIN1], 48000.0/65536.0, + 16000.0/65536.0, &gSpeedHysteresisOscillatorRising); + + // Find interval of zero crossing + if(wasRising && !gSpeedHysteresisOscillatorRising) { + int interval = gMatrixSampleCount - gSpeedHysteresisLastTrigger; + + // Interval since last trigger will be the new hop size; calculate to set speed + if(interval < 1) + interval = 1; + //float speed = (float)gOscBanks[gCurrentOscBank]->getHopSize() / (float)interval; + float speed = 144.0 / interval; // Normalise to a fixed expected speed + gOscBanks[gCurrentOscBank]->setSpeed(speed); + + gSpeedHysteresisLastTrigger = gMatrixSampleCount; + } + + /* + * Matrix Out 2, In 2 + * + * Feedback (phase shift) oscillator + * Controls wavetable used for oscillator bank + */ + + int tableLength = gFeedbackOscillator.process(context->analogIn[n*8 + ADC_PIN2], &context->analogOut[n*8 + DAC_PIN2]); + if(tableLength != 0) { + gFeedbackOscillatorTableLength = tableLength; + gFeedbackOscillatorTable = gFeedbackOscillator.wavetable(); + gDynamicWavetableNeedsRender = true; + Bela_scheduleAuxiliaryTask(gLowPriorityRender); + } + + /* + * Matrix Out 3, In 3 + * + * CV loop with delay for time alignment + * Touch positions from sensor 1 + * Change every 32 samples (ca. 1.5 ms) + */ + volatile int touchCount = gSensor1LatestTouchCount; + if(touchCount == 0) + context->analogOut[n*8 + DAC_PIN3] = 0; + else { + int touchIndex = (gMatrixSampleCount >> 5) % touchCount; + context->analogOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f / 65536.0f; + if(touchIndex != gSensor1LastTouchIndex) { + // Just changed to a new touch output. Reset the counter. + // It will take 2*matrixFrames samples for this output to come back to the + // ADC input. But we also want to read near the end of the 32 sample block; + // let's say 24 samples into it. + + // FIXME this won't work for p > 2 + gSensor1InputDelayCounter = 24 + 2*context->analogFrames; + gSensor1InputIndex = touchIndex; + } + gSensor1LastTouchIndex = touchIndex; + } + + if(gSensor1InputDelayCounter-- >= 0 && touchCount > 0) { + gSensor1MatrixTouchPos[gSensor1InputIndex] = context->analogIn[n*8 + ADC_PIN3]; + } + + /* Matrix Out 4 + * + * Sensor 1 last pos + */ + touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex]; + if(touchPosInt < 0) touchPosInt = 0; + if(touchPosInt > 1.0) touchPosInt = 1.0; + context->analogOut[n*8 + DAC_PIN4] = touchPosInt; + + /* Matrix In 4 + * + * Loop points selector + */ + gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = context->analogIn[n*8 + ADC_PIN4]; + if(gLoopPointsInputBufferPointer >= gLoopPointsInputBufferSize) { + // Find min and max values + float loopMax = 0, loopMin = 1.0; + for(int i = 0; i < gLoopPointsInputBufferSize; i++) { + if(gLoopPointsInputBuffer[i] < loopMin) + loopMin = gLoopPointsInputBuffer[i]; + if(gLoopPointsInputBuffer[i] > loopMax/* && gLoopPointsInputBuffer[i] != 65535*/) + loopMax = gLoopPointsInputBuffer[i]; + } + + if(loopMin >= loopMax) + loopMax = loopMin; + + gLoopPointMax = loopMax; + gLoopPointMin = loopMin; + gLoopPointsInputBufferPointer = 0; + } + + /* Matrix Out 5 + * + * Audio In 1 peak detection and peak burst output + */ + + filterOut[0][n*2+1] *= filterGain; + float burstOut = PeakBurst[0].getOutput(); + if( burstOut < 0.1) + { + if( (prevFiltered[0]>=peakThresh) && (prevFiltered[0]>=filterOut[0][n*2+1]) ) + { + peak[0] = prevFiltered[0]; + PeakBurst[0].gate(1); + } + } + + PeakBurst[0].process(1); + + float convAudio = burstOut*peak[0]; + context->analogOut[n*8 + DAC_PIN5] = convAudio; + prevFiltered[0] = filterOut[0][n*2+1]; + if(prevFiltered[0]>1) + prevFiltered[0] = 1; + + /* Matrix In 5 + * + * Dissonance, via changing frequency motion of partials + */ + float amount = (float)context->analogIn[n*8 + ADC_PIN5]; + gOscBanks[gCurrentOscBank]->freqMovement = 1.0 - amount; + + + + + /* Matrix Out 6 + * + * Audio In 2 peak detection and peak burst output + */ + + filterOut[1][n*2+1] *= filterGain; + burstOut = PeakBurst[1].getOutput(); + if( burstOut < 0.1) + { + if( (prevFiltered[1]>=peakThresh) && (prevFiltered[1]>=filterOut[1][n*2+1]) ) + { + peak[1] = prevFiltered[1]; + PeakBurst[1].gate(1); + } + } + + PeakBurst[1].process(1); + + convAudio = burstOut*peak[1]; + context->analogOut[n*8 + DAC_PIN6] = convAudio; + prevFiltered[1] = filterOut[1][n*2+1]; + if(prevFiltered[1]>1) + prevFiltered[1] = 1; + + /* Matrix In 6 + * + * Sound selector + */ + if(!gIsLoading) { + // Use hysteresis to avoid jumping back and forth between sounds + if(gOscBanks.size() > 1) { + float input = context->analogIn[n*8 + ADC_PIN6]; + const float hystValue = 16000.0 / 65536.0; + + float upHysteresisValue = ((gCurrentOscBank + 1) + hystValue) / gOscBanks.size(); + float downHysteresisValue = (gCurrentOscBank - hystValue) / gOscBanks.size(); + + if(input > upHysteresisValue || input < downHysteresisValue) { + gNextOscBank = input * gOscBanks.size(); + if(gNextOscBank < 0) + gNextOscBank = 0; + if((unsigned)gNextOscBank >= gOscBanks.size()) + gNextOscBank = gOscBanks.size() - 1; + } + } + } + + /* + * Matrix In 7 + * + * FSR from primary touch sensor + * Value ranges from 0-1799 + */ + gLastFSRValue = context->analogIn[n*8 + ADC_PIN7] * 1799.0; + //gLastFSRValue = 1799 - context->analogIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0); + //dbox_printf("%i\n",gLastFSRValue); + + gMatrixSampleCount++; + } + +#endif /* DBOX_CAPE_TEST */ +} + +// Medium-priority render function used for audio hop calculations +void render_medium_prio() +{ + + if(gOscillatorNeedsRender) { + gOscillatorNeedsRender = false; + + /* Render one frame into the write buffer */ + memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * 2 * sizeof(float)); /* assumes 2 audio channels */ + + oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, gOscillatorBufferWrite, + gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, + gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies, + gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, + gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, + gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, + /*gOscBanks[gCurrentOscBank]->lookupTable*/gDynamicWavetable); + + gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * 2; + + /* Update the pitch right before the hop + * Total CV range +/- N_OCT octaves + */ + float pitch = (float)gPitchLatestInput / octaveSplitter - N_OCT/2; + //gOscBanks[gCurrentOscBank]->pitchMultiplier = powf(2.0f, pitch); + gOscBanks[gCurrentOscBank]->pitchMultiplier = pow(2.0f, pitch); + +#ifdef FIXME_LATER // This doesn't work very well yet + gOscBanks[gCurrentOscBank]->filterNum = gSensor1LatestTouchCount; + float freqScaler = gOscBanks[gCurrentOscBank]->getFrequencyScaler(); + for(int i=0; i < gOscBanks[gCurrentOscBank]->filterNum; i++) + { + // touch pos is linear but freqs are log + gOscBanks[gCurrentOscBank]->filterFreqs[i] = ((expf(gSensor1MatrixTouchPos[i]*4)-1)/(expf(4)-1))*gOscBanks[gCurrentOscBank]->filterMaxF*freqScaler; + gOscBanks[gCurrentOscBank]->filterQ[i] = gSensor1LatestTouchSizes[i]; + if(gOscBanks[gCurrentOscBank]->filterFreqs[i]>500*freqScaler) + gOscBanks[gCurrentOscBank]->filterPadding[i] = 1+100000*( (gOscBanks[gCurrentOscBank]->filterFreqs[i]-500*freqScaler)/(gOscBanks[gCurrentOscBank]->filterMaxF-500)*freqScaler ); + else + gOscBanks[gCurrentOscBank]->filterPadding[i] = 1; + } +#endif + + RTIME ticks = rt_timer_read(); + SRTIME ns = rt_timer_tsc2ns(ticks); + SRTIME delta = ns-prevChangeNs; + + // switch to next bank cannot be too frequent, to avoid seg fault! [for example sef fault happens when removing both VDD and GND from breadboard] + if(gNextOscBank != gCurrentOscBank && delta>100000000) { + + /*printf("ticks %llu\n", (unsigned long long)ticks); + printf("ns %llu\n", (unsigned long long)ns); + printf("prevChangeNs %llu\n", (unsigned long long)prevChangeNs); + printf("-------------------------->%llud\n", (unsigned long long)(ns-prevChangeNs));*/ + + prevChangeNs = ns; + dbox_printf("Changing to bank %d...\n", gNextOscBank); + if(gOscBanks[gCurrentOscBank]->state==bank_playing){ + gOscBanks[gCurrentOscBank]->stop(); + } + + gCurrentOscBank = gNextOscBank; + gOscBanks[gCurrentOscBank]->hopNumTh = 0; + } + else { + /* Advance to the next oscillator frame */ + gOscBanks[gCurrentOscBank]->nextHop(); + } + } +} + +// Lower-priority render function which performs matrix calculations +// State should be transferred in via global variables +void render_low_prio() +{ + gPRU->setGPIOTestPin(); + if(gDynamicWavetableNeedsRender) { + // Find amplitude of wavetable + float meanAmplitude = 0; + float sineMix; + + for(int i = 0; i < gFeedbackOscillatorTableLength; i++) { + //meanAmplitude += fabsf(gFeedbackOscillatorTable[i]); + meanAmplitude += fabs(gFeedbackOscillatorTable[i]); + } + meanAmplitude /= (float)gFeedbackOscillatorTableLength; + + if(meanAmplitude > 0.35) + sineMix = 0; + else + sineMix = (.35 - meanAmplitude) / .35; + + //dbox_printf("amp %f mix %f\n", meanAmplitude, sineMix); + + // Copy to main wavetable + wavetable_interpolate(gFeedbackOscillatorTableLength, gDynamicWavetableLength, + gFeedbackOscillatorTable, gDynamicWavetable, + gOscBanks[gCurrentOscBank]->lookupTable, sineMix); + } + + if(gLoopPointMin >= 60000.0/65536.0 && gLoopPointMax >= 60000.0/65536.0) { + // KLUDGE! + if(gCurrentOscBank == 0) + gOscBanks[gCurrentOscBank]->setLoopHops(50, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.6) - 1); + else + gOscBanks[gCurrentOscBank]->setLoopHops(5, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.7) - 1); + } + else { + float normLoopPointMin = (float)gLoopPointMin * gOscBanks[gCurrentOscBank]->getLastHop(); + float normLoopPointMax = (float)gLoopPointMax * gOscBanks[gCurrentOscBank]->getLastHop(); + + int intLoopPointMin = normLoopPointMin; + if(intLoopPointMin < 1) + intLoopPointMin = 1; + int intLoopPointMax = normLoopPointMax; + if(intLoopPointMax <= intLoopPointMin) + intLoopPointMax = intLoopPointMin + 1; + if(intLoopPointMax > gOscBanks[gCurrentOscBank]->getLastHop() - 1) + intLoopPointMax = gOscBanks[gCurrentOscBank]->getLastHop() - 1; + + //dbox_printf("Loop points %d-%d / %d-%d\n", gLoopPointMin, gLoopPointMax, intLoopPointMin, intLoopPointMax); + + /* WORKS, jsut need to fix the glitch when jumps! + * *int currentHop = gOscBanks[gCurrentOscBank]->getCurrentHop(); + if(currentHop < intLoopPointMin -1 ) + gOscBanks[gCurrentOscBank]->setJumpHop(intLoopPointMin + 1); + else if(currentHop > intLoopPointMax + 1) + gOscBanks[gCurrentOscBank]->setJumpHop(intLoopPointMax - 1);*/ + gOscBanks[gCurrentOscBank]->setLoopHops(intLoopPointMin, intLoopPointMax); + } + + if(gIsLoading) + gStatusLED.blink(25, 75); // Blink quickly until load finished + else + gStatusLED.blink(250 / gOscBanks[gCurrentOscBank]->getSpeed(), 250 / gOscBanks[gCurrentOscBank]->getSpeed()); + gPRU->clearGPIOTestPin(); + +// static int counter = 32; +// if(--counter == 0) { +// for(int i = 0; i < gLoopPointsInputBufferSize; i++) { +// dbox_printf("%d ", gLoopPointsInputBuffer[i]); +// if(i % 32 == 31) +// dbox_printf("\n"); +// } +// dbox_printf("\n\n"); +// counter = 32; +// } + + //dbox_printf("min %d max %d\n", gLoopPointMin, gLoopPointMax); +} + +// Clean up at the end of render +void cleanup(BelaContext *context, void *userData) +{ + free(gOscillatorBuffer1); + free(gOscillatorBuffer2); + free(gDynamicWavetable); +} + +// Interpolate one wavetable into another. The output size +// does not include the guard point at the end which will be identical +// to the first point +void wavetable_interpolate(int numSamplesIn, int numSamplesOut, + float *tableIn, float *tableOut, + float *sineTable, float sineMix) +{ + float fractionalScaler = (float)numSamplesIn / (float)numSamplesOut; + + for(int k = 0; k < numSamplesOut; k++) { + float fractionalIndex = (float) k * fractionalScaler; + //int sB = (int)floorf(fractionalIndex); + int sB = (int)floor(fractionalIndex); + int sA = sB + 1; + if(sA >= numSamplesIn) + sA = 0; + float fraction = fractionalIndex - sB; + tableOut[k] = fraction * tableIn[sA] + (1.0f - fraction) * tableIn[sB]; + tableOut[k] = sineMix * sineTable[k] + (1.0 - sineMix) * tableOut[k]; + } + + tableOut[numSamplesOut] = tableOut[0]; +} + +// Create a hysteresis oscillator with a matrix input and output +inline float hysteresis_oscillator(float input, float risingThreshold, float fallingThreshold, bool *rising) +{ + float value; + + if(*rising) { + if(input > risingThreshold) { + *rising = false; + value = 0; + } + else + value = 1.0; + } + else { + if(input < fallingThreshold) { + *rising = true; + value = 1.0; + } + else + value = 0; + } + + return value; +} + +#ifdef DBOX_CAPE_TEST +// Test the functionality of the D-Box cape by checking each input and output +// Loopback cable from ADC to DAC needed +void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, + uint16_t *matrixIn, uint16_t *matrixOut) +{ + static float phase = 0.0; + static int sampleCounter = 0; + static int invertChannel = 0; + + // Play a sine wave on the audio output + for(int n = 0; n < numAudioFrames; n++) { + audioOut[2*n] = audioOut[2*n + 1] = 0.5*sinf(phase); + phase += 2.0 * M_PI * 440.0 / 44100.0; + if(phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + } + + for(int n = 0; n < numMatrixFrames; n++) { + // Change outputs every 512 samples + if(sampleCounter < 512) { + for(int k = 0; k < 8; k++) { + if(k == invertChannel) + matrixOut[n*8 + k] = 50000; + else + matrixOut[n*8 + k] = 0; + } + } + else { + for(int k = 0; k < 8; k++) { + if(k == invertChannel) + matrixOut[n*8 + k] = 0; + else + matrixOut[n*8 + k] = 50000; + } + } + + // Read after 256 samples: input should be low + if(sampleCounter == 256) { + for(int k = 0; k < 8; k++) { + if(k == invertChannel) { + if(matrixIn[n*8 + k] < 50000) { + dbox_printf("FAIL channel %d -- output HIGH input %d (inverted)\n", k, matrixIn[n*8 + k]); + } + } + else { + if(matrixIn[n*8 + k] > 2048) { + dbox_printf("FAIL channel %d -- output LOW input %d\n", k, matrixIn[n*8 + k]); + } + } + } + } + else if(sampleCounter == 768) { + for(int k = 0; k < 8; k++) { + if(k == invertChannel) { + if(matrixIn[n*8 + k] > 2048) { + dbox_printf("FAIL channel %d -- output LOW input %d (inverted)\n", k, matrixIn[n*8 + k]); + } + } + else { + if(matrixIn[n*8 + k] < 50000) { + dbox_printf("FAIL channel %d -- output HIGH input %d\n", k, matrixIn[n*8 + k]); + } + } + } + } + + if(++sampleCounter >= 1024) { + sampleCounter = 0; + invertChannel++; + if(invertChannel >= 8) + invertChannel = 0; + } + } +} +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/sensors.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,642 @@ +/* + * sensors.cpp + * + * Created on: May 28, 2014 + * Author: Victor Zappi + */ + +#include <stdio.h> +#include <pthread.h> +#include <unistd.h> +#include <math.h> +#include <vector> +#include "prio.h" +#include "sensors.h" +#include "OscillatorBank.h" +#include "DboxSensors.h" + + +//---------------------------------------- +// main extern variables +//---------------------------------------- +extern vector<OscillatorBank*> gOscBanks; +extern int gCurrentOscBank; +extern int gNextOscBank; +extern int gShouldStop; +extern int gVerbose; + +float gSensor0LatestTouchPos = 0; // most recent pitch touch location [0-1] on sensor 0, used by render.cpp +int gSensor0LatestTouchNum = 0; // most recent num of touches on sensor 0, used by render.cpp +float gSensor1LatestTouchPos[5]; // most recent touche locations on sensor 1, used by render.cpp +//float gSensor1LatestTouchSizes[5]; +int gSensor1LatestTouchCount; // most recent number touches on sensor 1, used by render.cpp +int gSensor1LatestTouchIndex = 0; // index of last touch in gSensor1LatestTouchPos[5], used by render.cpp +int gLastFSRValue = 1799; // most recent fsr value, used by render.cpp + + +DboxSensors Sensors; + + +//---------------------------------------- +// var shared with logger +//---------------------------------------- +int s0TouchNum = 0; +float s0Touches_[MAX_TOUCHES]; +float s0Size_[MAX_TOUCHES]; +int s0LastIndex; + +int s1TouchNum = 0; +float s1Touches_[MAX_TOUCHES]; +float s1Size_[MAX_TOUCHES]; +int s1LastIndex; + +int fsr = 1799; + + + +using namespace std; + +int initSensorLoop(int sensorAddress0, int sensorAddress1, int sensorType) +{ + int tk0_bus = 1; + int tk0_address = sensorAddress0; + int tk1_bus = 1; + int tk1_address = sensorAddress1; + int tk_file = 0; + int fsr_max = 1799; + int fsr_pinNum = 4; + + if(gVerbose==1) + cout << "---------------->Init Control Thread" << endl; + + if(Sensors.initSensors(tk0_bus, tk0_address, tk1_bus, tk1_address, tk_file, fsr_pinNum, fsr_max, sensorType)>0) + { + gShouldStop = 1; + cout << "control cannot start" << endl; + return -1; + } + + for(int i=0; i<MAX_TOUCHES; i++) + { + s0Touches_[i] = 0.0; + s0Size_[i] = 0.0; + + s1Touches_[i] = 0.0; + s1Size_[i] = 0.0; + } + + return 0; +} + +void sensorLoop(void *) +{ + timeval start, end; + unsigned long elapsedTime; + //float touchSize = 0; // once used for timbre + + + + float *s0Touches; + float *s0Size; + int s0PrevTouchNum = 0; + int s0SortedTouchIndices[MAX_TOUCHES]; + float s0SortedTouches[MAX_TOUCHES]; + float s0PrevSortedTouches[MAX_TOUCHES]; + + float *s1Touches; + float *s1Size; + int s1PrevTouchNum = 0; + int s1SortedTouchIndices[MAX_TOUCHES]; + float s1SortedTouches[MAX_TOUCHES]; + float s1PrevSortedTouches[MAX_TOUCHES]; + + float freqScaler = 0; + int fsrMin = 0;//50; // was 200 + int fsrMax = 1799;//1300; // was 800 + float vel = 0; + float prevVel = 0; + float filterMaxF = 0; + if(gVerbose==1) + dbox_printf("__________set Control Thread priority\n"); + + if(gVerbose==1) + dbox_printf("_________________Control Thread!\n"); + + // get freq scaler, cos freqs must be scaled according to the wavetable used in the oscillator bank + freqScaler = gOscBanks[gCurrentOscBank]->getFrequencyScaler(); + filterMaxF = gOscBanks[gCurrentOscBank]->filterMaxF; + + // init time vals + gettimeofday(&start, NULL); + + // here we go, sensor loop until the end of the application + while(!gShouldStop) + { + gettimeofday(&end, NULL); + elapsedTime = ( (end.tv_sec*1000000+end.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); + if( elapsedTime<4000 ) + usleep(4000-elapsedTime); + else + dbox_printf("%d\n", (int)elapsedTime); // this print happens when something's gone bad... + + if(Sensors.readSensors()==0) + { + s0TouchNum = Sensors.getTKTouchCount(0); + s0Touches = Sensors.getTKXPositions(0); + s0Size = Sensors.getTKTouchSize(0); + + s1TouchNum = Sensors.getTKTouchCount(1); + s1Touches = Sensors.getTKXPositions(1); + s1Size = Sensors.getTKTouchSize(1); + + for(int i=0; i<MAX_TOUCHES; i++) + { + s0Touches_[i] = s0Touches[i]; + s0Size_[i] = s0Size[i]; + + s1Touches_[i] = s1Touches[i]; + s1Size_[i] = s1Size[i]; + } + + gSensor0LatestTouchNum = s0TouchNum; + if(s0TouchNum > 0) + { + //----------------------------------------------------------------------------------- + // timbre, speed and pitch + //touchSize = 0; \\ once used for timbre + + // if we have a number of touches different from previous round, track their order of arrival [calculated using distance comparison] + if(s0PrevTouchNum!=s0TouchNum) + { + float distances[MAX_TOUCHES*(MAX_TOUCHES-1)]; // maximum number of current+previous touches between rounds with different num of touches + int ids[MAX_TOUCHES*(MAX_TOUCHES-1)]; + // calculate all distance permutations between previous and current touches + for(int i=0; i<s0TouchNum; i++) + { + for(int p=0; p<s0PrevTouchNum; p++) + { + int index = i*s0PrevTouchNum+p; // permutation id [says between which touches we are calculating distance] + distances[index] = fabs(s0Touches[i]-s0PrevSortedTouches[p]); + ids[index] = index; + if(index>0) + { + // sort, from min to max distance + float tmp; + while(distances[index]<distances[index-1]) + { + tmp = ids[index-1]; + ids[index-1] = ids[index]; + ids[index] = tmp; + + tmp = distances[index-1]; + distances[index-1] = distances[index]; + distances[index] = tmp; + + index--; + + if(index == 0) + break; + } + } + } + } + + int sorted = 0; + bool currAssigned[MAX_TOUCHES] = {false}; + bool prevAssigned[MAX_TOUCHES] = {false}; + + // track touches assigning index according to shortest distance + for(int i=0; i<s0TouchNum*s0PrevTouchNum; i++) + { + int currentIndex = ids[i]/s0PrevTouchNum; + int prevIndex = ids[i]%s0PrevTouchNum; + // avoid double assignment + if(!currAssigned[currentIndex] && !prevAssigned[prevIndex]) + { + currAssigned[currentIndex] = true; + prevAssigned[prevIndex] = true; + s0SortedTouchIndices[currentIndex] = prevIndex; + sorted++; + } + } + // we still have to assign a free index to new touches + if(s0PrevTouchNum<s0TouchNum) + { + for(int i=0; i<s0TouchNum; i++) + { + if(!currAssigned[i]) + s0SortedTouchIndices[i] = sorted++; // assign next free index + + // update tracked value + s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i]; + s0PrevSortedTouches[i] = s0SortedTouches[i]; + if(s0SortedTouchIndices[i]==s0TouchNum-1) + s0LastIndex = i; + + // accumulate sizes for timbre + //touchSize += s0Size[i]; + } + } + else // some touches have disappeared... + { + // ...we have to shift all indices... + for(int i=s0PrevTouchNum-1; i>=0; i--) + { + if(!prevAssigned[i]) + { + for(int j=0; j<s0TouchNum; j++) + { + // ...only if touches that disappeared were before the current one + if(s0SortedTouchIndices[j]>i) + s0SortedTouchIndices[j]--; + } + } + } + // done! now update + for(int i=0; i<s0TouchNum; i++) + { + // update tracked value + s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i]; + s0PrevSortedTouches[i] = s0SortedTouches[i]; + if(s0SortedTouchIndices[i]==s0TouchNum-1) + s0LastIndex = i; + + // accumulate sizes for timbre + //touchSize += s0Size[i]; + } + } + } + else // nothing's changed since last round + { + for(int i=0; i<s0TouchNum; i++) + { + // update tracked value + s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i]; + s0PrevSortedTouches[i] = s0SortedTouches[i]; + + // accumulate sizes for timbre + //touchSize += s0Size[i]; + } + } + + if(s0TouchNum == 0) + s0LastIndex = -1; + + // timbre + //touchSize = (touchSize > 0.7) ? 1 : touchSize/0.7; + //gOscBanks[gCurrentOscBank]->hopNumTh = log((1-touchSize)+1)/log(2)*20000; + //gOscBanks[gCurrentOscBank]->hopNumTh = 0; + + + // pitch, controlled by last touch + //prevTouchPos = touch[touchIndex]; + //touchPos = (s0SortedTouches[s0TouchNum-1]-0.5)/0.5; // from [0,1] to [-1,1] + gSensor0LatestTouchPos = s0SortedTouches[s0TouchNum-1]; + //touchPos = s0Touches[0]; + //gOscBanks[gCurrentOscBank]->pitchMultiplier = pow(2, touchPos); + //----------------------------------------------------------------------------------- + + + + //----------------------------------------------------------------------------------- + // note on + //if(s0PrevTouchNum == 0) + // gOscBanks[gCurrentOscBank]->play(); + // fsr = Sensors.getFSRVAlue(); + fsr = gLastFSRValue; + //dbox_printf("fsr: %d\n", fsr); + if(!gOscBanks[gCurrentOscBank]->note) + { + vel = fsr; + vel /= (float)(fsrMax-fsrMin); + + vel = 1-vel; + dbox_printf("Attack vel: %f\n", vel); + gOscBanks[gCurrentOscBank]->play(vel); + prevVel = vel; + } + else if(gOscBanks[gCurrentOscBank]->getEnvelopeState() != env_release) + { + fsr = (fsr > fsrMax) ? fsrMax : fsr; + vel = (fsr < fsrMin) ? fsrMin : fsr; + vel -= fsrMin; + vel /= (float)(fsrMax-fsrMin); + vel = 1-vel; + if(vel > prevVel) + { + gOscBanks[gCurrentOscBank]->afterTouch(vel); + prevVel = vel; + } + } + //----------------------------------------------------------------------------------- + } + else + { + //prevFsr = 1799; + //prevTouchPos = -1; + //----------------------------------------------------------------------------------- + // note off + if(s0PrevTouchNum > 0) + { + if(gOscBanks[gCurrentOscBank]->state==bank_playing) + gOscBanks[gCurrentOscBank]->stop(); + } + //----------------------------------------------------------------------------------- + } + + + + // sensor 2 + //----------------------------------------------------------------------------------- + //filter - calculated even when no touches on first sensor, to filter also release tail + gOscBanks[gCurrentOscBank]->filterNum = s1TouchNum; + + gSensor1LatestTouchCount = gOscBanks[gCurrentOscBank]->filterNum; + for(int i = 0; i < gSensor1LatestTouchCount; i++) { + gSensor1LatestTouchPos[i] = s1Touches[i]; + //gSensor1LatestTouchSizes[i] = s1Size[i]; + } + +/* for(int i=0; i<gOscBanks[gCurrentOscBank]->filterNum; i++) + { + // touch pos is linear but freqs are log + gOscBanks[gCurrentOscBank]->filterFreqs[i] = ((exp(s0Touches[i]*4)-1)/(exp(4)-1))*filterMaxF*freqScaler; + //gOscBanks[gCurrentOscBank]->filterQ[i] = size[i]*5*(1+touch[i]*1000)*freqScaler; + gOscBanks[gCurrentOscBank]->filterQ[i] = s0Size[i]; + if(gOscBanks[gCurrentOscBank]->filterFreqs[i]>500*freqScaler) + gOscBanks[gCurrentOscBank]->filterPadding[i] = 1+100000*( (gOscBanks[gCurrentOscBank]->filterFreqs[i]-500*freqScaler)/(filterMaxF-500)*freqScaler ); + else + gOscBanks[gCurrentOscBank]->filterPadding[i] = 1; + }*/ + + // each touch on sensor 2 is a notch filter, whose Q is determined by touch size + for(int i=0; i<gOscBanks[gCurrentOscBank]->filterNum; i++) + { + // map touch pos [which is linear] on freqs exponentially + float freq = ((exp(s1Touches[i]*4)-1)/EXP_DENOM)*filterMaxF; + gOscBanks[gCurrentOscBank]->filterFreqs[i] = freq*freqScaler; + // also size is mapped exponentially on Q + float siz = (exp(s1Size[i])-1)/1.71828; + gOscBanks[gCurrentOscBank]->filterQ[i] = siz*( (filterMaxF-freq)/filterMaxF * 0.9 + 0.1 ); // size weight on Q decreases with frequency + } + //----------------------------------------------------------------------------------- + + + + //----------------------------------------------------------------------------------- + // sort touches on sensor 2 + if(s1TouchNum > 0) + { + // if we have a number of touches different from previous round, track their order of arrival [calculated using distance comparison] + if(s1PrevTouchNum!=s1TouchNum) + { + float distances[MAX_TOUCHES*(MAX_TOUCHES-1)]; // maximum number of current+previous touches between rounds with different num of touches + int ids[MAX_TOUCHES*(MAX_TOUCHES-1)]; + // calculate all distance permutations between previous and current touches + for(int i=0; i<s1TouchNum; i++) + { + for(int p=0; p<s1PrevTouchNum; p++) + { + int index = i*s1PrevTouchNum+p; // permutation id [says between which touches we are calculating distance] + distances[index] = fabs(s1Touches[i]-s1PrevSortedTouches[p]); + ids[index] = index; + if(index>0) + { + // sort, from min to max distance + float tmp; + while(distances[index]<distances[index-1]) + { + tmp = ids[index-1]; + ids[index-1] = ids[index]; + ids[index] = tmp; + + tmp = distances[index-1]; + distances[index-1] = distances[index]; + distances[index] = tmp; + + index--; + + if(index == 0) + break; + } + } + } + } + + int sorted = 0; + bool currAssigned[MAX_TOUCHES] = {false}; + bool prevAssigned[MAX_TOUCHES] = {false}; + + // track touches assigning index according to shortest distance + for(int i=0; i<s1TouchNum*s1PrevTouchNum; i++) + { + int currentIndex = ids[i]/s1PrevTouchNum; + int prevIndex = ids[i]%s1PrevTouchNum; + // avoid double assignment + if(!currAssigned[currentIndex] && !prevAssigned[prevIndex]) + { + currAssigned[currentIndex] = true; + prevAssigned[prevIndex] = true; + s1SortedTouchIndices[currentIndex] = prevIndex; + sorted++; + } + } + // we still have to assign a free index to new touches + if(s1PrevTouchNum<s1TouchNum) + { + for(int i=0; i<s1TouchNum; i++) + { + if(!currAssigned[i]) + s1SortedTouchIndices[i] = sorted++; // assign next free index + + // update tracked value + s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i]; + s1PrevSortedTouches[i] = s1SortedTouches[i]; + if(s1SortedTouchIndices[i]==s1TouchNum-1) + s1LastIndex = i; + } + } + else // some touches have disappeared... + { + // ...we have to shift all indices... + for(int i=s1PrevTouchNum-1; i>=0; i--) + { + if(!prevAssigned[i]) + { + for(int j=0; j<s1TouchNum; j++) + { + // ...only if touches that disappeared were before the current one + if(s1SortedTouchIndices[j]>i) + s1SortedTouchIndices[j]--; + } + } + } + // done! now update + for(int i=0; i<s1TouchNum; i++) + { + // update tracked value + s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i]; + s1PrevSortedTouches[i] = s1SortedTouches[i]; + if(s1SortedTouchIndices[i]==s1TouchNum-1) + s1LastIndex = i; + } + } + } + else // nothing's changed since last round + { + for(int i=0; i<s1TouchNum; i++) + { + // update tracked value + s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i]; + s1PrevSortedTouches[i] = s1SortedTouches[i]; + } + } + } + + if(s1TouchNum > 0) + { + gSensor1LatestTouchIndex = s1LastIndex; + } + else + s1LastIndex = -1; + +/* dbox_printf("-----------------------------\nnum: %d, latest: %d\n", s1TouchNum, gSensor1LatestTouchIndex); + for(int i=0; i<s1TouchNum; i++) + dbox_printf("\t%f\n", gSensor1LatestTouchPos[i]); + dbox_printf("------\n"); + for(int i=0; i<s1TouchNum; i++) + dbox_printf("\t%f\n", s1SortedTouches[i]);*/ + + + + // update variables for both sensors + s0PrevTouchNum = s0TouchNum; + s1PrevTouchNum = s1TouchNum; + } + else + dbox_printf("Come on instrument!\n"); //break + + gettimeofday(&start, NULL); + } + + dbox_printf("sensor thread ended\n"); +} + +void *keyboardLoop(void *) +{ + if(gVerbose==1) + cout << "_________________Keyboard Control Thread!" << endl; + + char keyStroke = '.'; + cout << "Press q to quit." << endl; + + float speed; + + do + { + keyStroke = getchar(); + while(getchar()!='\n'); // to read the first stroke + + switch (keyStroke) + { + //---------------------------------------------------------------------------- + case 'a': + gOscBanks[gCurrentOscBank]->hopNumTh = 0; + gOscBanks[gCurrentOscBank]->play(1); + //cout << "Note on" << endl; + break; + case 's': + if(gOscBanks[gCurrentOscBank]->state==bank_playing) + { + gOscBanks[gCurrentOscBank]->stop(); + //cout << "Note off" << endl; + } + break; + //---------------------------------------------------------------------------- + case '[': + gOscBanks[gCurrentOscBank]->freqMovement-=0.05; + if(gOscBanks[gCurrentOscBank]->freqMovement<0) + gOscBanks[gCurrentOscBank]->freqMovement = 0; + //cout << "gOscBanks[gCurrentOscBank]->FreqMov: " << gOscBanks[gCurrentOscBank]->freqMovement << endl; + break; + case ']': + gOscBanks[gCurrentOscBank]->freqMovement+=0.05; + if(gOscBanks[gCurrentOscBank]->freqMovement>1) + gOscBanks[gCurrentOscBank]->freqMovement = 1; + //cout << "gOscBanks[gCurrentOscBank]->FreqMov: " << gOscBanks[gCurrentOscBank]->freqMovement << endl; + break; + //---------------------------------------------------------------------------- + case '<': + speed = gOscBanks[gCurrentOscBank]->getSpeed() - 0.1 ; + gOscBanks[gCurrentOscBank]->setSpeed(speed); + dbox_printf("Speed: %f\n", speed); + + break; + case '>': + speed = gOscBanks[gCurrentOscBank]->getSpeed() + 0.1 ; + gOscBanks[gCurrentOscBank]->setSpeed(speed); + dbox_printf("Speed: %f\n", speed); + break; + case '0': + speed = 0.1; + gOscBanks[gCurrentOscBank]->setSpeed(speed); + dbox_printf("Speed: %f\n", speed); + break; + case '1': + speed = 0.5; + gOscBanks[gCurrentOscBank]->setSpeed(speed); + dbox_printf("Speed: %f\n", speed); + break; + case '2': + speed = 1; + gOscBanks[gCurrentOscBank]->setSpeed(speed); + dbox_printf("Speed: %f\n", speed); + break; + case '3': + speed = 2; + gOscBanks[gCurrentOscBank]->setSpeed(speed); + dbox_printf("Speed: %f\n", speed); + break; + case '4': + speed = 3; + gOscBanks[gCurrentOscBank]->setSpeed(speed); + dbox_printf("Speed: %f\n", speed); + break; + //---------------------------------------------------------------------------- + case 'z': + gOscBanks[gCurrentOscBank]->setJumpHop(0); + break; + case 'x': + gOscBanks[gCurrentOscBank]->setJumpHop(100); + break; + case 'c': + gOscBanks[gCurrentOscBank]->setJumpHop(600); + break; + case 'v': + gOscBanks[gCurrentOscBank]->setJumpHop(1100); + break; + case 'b': + gOscBanks[gCurrentOscBank]->setJumpHop(2000); + break; + case 'n': + gOscBanks[gCurrentOscBank]->setJumpHop(gOscBanks[gCurrentOscBank]->getLastHop()); + break; + //---------------------------------------------------------------------------- + case 'q': + gShouldStop = true; + break; + case 'o': + gNextOscBank = (gCurrentOscBank + 1) % gOscBanks.size(); + break; + default: + break; + //---------------------------------------------------------------------------- + } + usleep(1000); /* Wait 1ms to avoid checking too quickly */ + } + while (keyStroke!='q'); + + cout << "keyboard thread ended" << endl; + + return (void *)0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/sensors.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,19 @@ +/* + * sensors.h + * + * Created on: May 28, 2014 + * Author: Victor Zappi + */ + +#ifndef SENSORS_H_ +#define SENSORS_H_ + +#include "config.h" + +int initSensorLoop(int sensorAddress0, int sensorAddress1, int sensorType); + +void sensorLoop(void *); +void *keyboardLoop(void *); + + +#endif /* SENSORS_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/spear_parser.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,641 @@ +/* + * spear_parser.cpp v1.2 + * + * Created on: May 6, 2014 + * Author: Victor Zappi + */ + +#include "spear_parser.h" + +using namespace std; + +//#define DO_CHECKS + +//------------------------------------------------------------------------------------------------ +// partials +//------------------------------------------------------------------------------------------------ + +Partials::Partials() +{ + partialFrequencies = NULL; +// partialAmplitudes = NULL; +// partialNumFrames = NULL; +// partialStartSample = NULL; +// partialEndSample = NULL; +// partialCurrentFrame = NULL; +// partialFreqDelta = NULL; +// partialAmpDelta = NULL; + + + activePartialNum = NULL; +// activePartials = NULL; + + currentSample = -1; +} + +Partials::~Partials() +{ + if(partialFrequencies != NULL) // check on one is enough + { + if(partialFrequencies[0] != NULL) // check on one is enough + { + for(unsigned int i=0; i<parNum; i++) + { + delete[] partialFrequencies[i]; + delete[] partialAmplitudes[i]; + delete[] partialFreqDelta[i]; + delete[] partialAmpDelta[i]; + + } + } + + delete[] partialFrequencies; + delete[] partialAmplitudes; + delete[] partialNumFrames; + delete[] partialFreqDelta; + delete[] partialAmpDelta; + delete[] partialFreqMean; + } + + if(activePartialNum != NULL) + { + for(unsigned int i=0; i<hopNum+1; i++) + delete[] activePartials[i]; + + delete[] activePartialNum; + delete[] activePartials ; + } +} + +void Partials::init(int parN, int hopS, bool isDBX) +{ + if(!isDBX) + { + parNum = parN; + hopSize = hopS; + + partialFrequencies = new float *[parNum]; + partialAmplitudes = new float *[parNum]; + partialNumFrames = new unsigned int[parNum]; + partialStartFrame = new unsigned int[parNum]; + partialStartSample = new unsigned int[parNum]; + partialEndSample = new unsigned int[parNum]; + partialFreqDelta = new float *[parNum]; + partialAmpDelta = new float *[parNum]; + partialFreqMean = new float[parNum]; + + + + // init in one shot + fill(partialFreqMean, partialFreqMean+parNum, 0); // mean is zero + + partialFrequencies[0] = NULL; // for free check + } + else + { + parNum = parN; + hopSize = hopS; + + partialFrequencies = new float *[parNum]; + partialAmplitudes = new float *[parNum]; + partialNumFrames = new unsigned int[parNum]; + partialStartFrame = new unsigned int[parNum]; + partialFreqDelta = new float *[parNum]; + partialAmpDelta = new float *[parNum]; + partialFreqMean = new float[parNum]; + + partialFrequencies[0] = NULL; // for free check + } +} + + + +void Partials::update(int parIndex, int frameNum) +{ + partialFrequencies[parIndex] = new float[frameNum]; + partialAmplitudes[parIndex] = new float[frameNum]; + partialFreqDelta[parIndex] = new float[frameNum]; + partialAmpDelta[parIndex] = new float[frameNum]; + + fill(partialFreqDelta[parIndex], partialFreqDelta[parIndex]+frameNum, 99999.0); // in the end, only the last one will have 99999 + fill(partialAmpDelta[parIndex], partialAmpDelta[parIndex]+frameNum, 99999.0); // in the end, only the last one will have 99999 +} + + + + + + + + + + + + + + + + + + + + +//------------------------------------------------------------------------------------------------ +// spear parser +//------------------------------------------------------------------------------------------------ +Spear_parser::Spear_parser() +{ + // some default values + hopSize = -1; + fileSampleRate = -1; +} + +Spear_parser::~Spear_parser() +{ +} + +void Spear_parser::calculateHopSize(char *filename) +{ + int index = 0; + bool prevWas_ = false; + bool found_h = false; + int n = 0; + + hopSize = 0; + + do + { + // check if '_' + if(filename[index] == '_') + prevWas_ = true; + else if( (filename[index] == 'h') && prevWas_) // if it is not, but it is 'h' and previous was '_', found "_h"! + { + found_h = true; + while(filename[index] != '\0') + { + index++; + if( (filename[index] == '.') || (filename[index] == '_')) + break; + else // i am not checking if char are digits...! + { + n = filename[index]; + hopSize = hopSize*10+(n-48); + } + } + } + else // else, nothing + prevWas_ = false; + index++; + } + while( (filename[index] != '\0') && !found_h ); + + if( !found_h || (hopSize<1) ) + hopSize = 551; // default val + +} + + +bool Spear_parser::parser(char *filename, int hopsize, int samplerate) +{ + string name = string(filename); + int len = name.length(); + // invoke correct parser according to the type of file...just checking the extension, crude but functional + if( (name[len-4]=='.') && (name[len-3]=='d') && (name[len-2]=='b') && (name[len-1]=='x') ) + return DBXparser(filename, samplerate); // .dbox + else + return TXTparser(filename, hopSize, samplerate); // .txt, or whatever +} + + +bool Spear_parser::DBXparser(char *filename, int samplerate) +{ + fileSampleRate = samplerate; + + // working vars + int parNum = 0; // total num of partials + int hopNum = 0; // total num of hops + + //---------------------------------------------------------------------------------------- + // open a file + ifstream fin; + fin.open(filename, ios::in | ios::binary); + if (!fin.good()) + { + cout << "Parser Error: file not found" << endl; // exit if file not found + return false; + } + + gettimeofday(&start, NULL); + //---------------------------------------------------------------------------------------- + // general data + + // look for partial count + fin.read((char *) &parNum, sizeof(int)); + partials.parNum = parNum; + + // look for hop count + fin.read((char *) &hopNum, sizeof(int)); + partials.setHopNum(hopNum); + + // look for hop size + fin.read((char *) &hopSize, sizeof(int)); + partials.hopSize = hopSize; // it's handy for both classes to know it + + // init partials data structure + partials.init(parNum, hopSize, true); + + // look for max active par num + fin.read((char *) &(partials.maxActiveParNum), sizeof(int)); + + + + // partial data + + // start frame of each partial + fin.read((char *) partials.partialStartFrame, sizeof(int)*parNum); + + // num of frames of each partial + fin.read((char *) partials.partialNumFrames, sizeof(int)*parNum); + + // frequency mean of each partial + fin.read((char *) partials.partialFreqMean, sizeof(int)*parNum); + + for(int par=0; par<parNum; par++) + { + int frameNum = partials.partialNumFrames[par]; + partials.update(par, frameNum); + fin.read((char *)partials.partialAmplitudes[par], sizeof(float)*frameNum); // amplitude of each partial in each frame + fin.read((char *)partials.partialFrequencies[par], sizeof(float)*frameNum); // frequency of each partial in each frame + fin.read((char *)partials.partialAmpDelta[par], sizeof(float)*frameNum); // amplitude delta of each partial in each frame + fin.read((char *)partials.partialFreqDelta[par], sizeof(float)*frameNum); // frequency delta of each partial in each frame + } + + + + + // frame data + + // number of active partial per each frame + fin.read((char *) partials.activePartialNum, sizeof(short)*(hopNum+1)); + // init array + for(int frame=0; frame<hopNum+1; frame++) + { + partials.activePartials[frame] = new unsigned int[partials.activePartialNum[frame]]; + fin.read((char *)partials.activePartials[frame], sizeof(int)*partials.activePartialNum[frame]); // active partials per each frame + } + + + + + + gettimeofday(&stop, NULL); + parserT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); + + + printf("\n-----------------------\n"); + printf("\nFile: %s\n", filename); + printf("\n-----------------------\n"); + printf("Profiler\n"); + printf("-----------------------\n"); + printf("File parser:\t\t\t%lu usec\n", parserT); + printf("\n\nTotal:\t\t%lu usec\n", parserT); + printf("-----------------------\n"); + + fin.close(); + + return true; +} + + + + +bool Spear_parser::TXTparser(char *filename, int hopsize, int samplerate) +{ + hopSize = hopsize; + fileSampleRate = samplerate; + if(hopsize<0) + { + gettimeofday(&start, NULL); + calculateHopSize(filename); + gettimeofday(&stop, NULL); + hopSizeT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); + } + else + hopSizeT = 0; + + calculateDeltaTime(); + + // working vars + char * token; // where to save single figures from file + string s = ""; // where to save lines from file + int parNum = 0; // total num of partials + int parIndex = -1; // index of current partial + int frameNum = 0; // total num of frames + int frameIndex = -1; // index of current frame + int startSample = -1; // sample value for first frame of partials + int endSample = -1; // sample value for last frame of partials + int maxSample = 0; // to calculate total number of hops in file + int missSampCnt = 0; // number of mising samples + double freq = 0; // to calculate frequency delta + double prevFreq = 0; // to calculate frequency delta + double amp = 0; // to calculate amplitude delta + double prevAmp = 0; // to calculate amplitude delta + + + //---------------------------------------------------------------------------------------- + // open a file + ifstream fin; + fin.open(filename); + if (!fin.good()) + { + cout << "Parser Error: file not found" << endl; // exit if file not found + return false; + } + + gettimeofday(&start, NULL); + //---------------------------------------------------------------------------------------- + // init partials data structure + getline(fin, s); + getline(fin, s); + getline(fin, s); // third line is the first we are interested into + + // look for partial count + token = strtok((char *)s.c_str(), " "); + // check if first token is there + if(token) + { + token = strtok(0, " "); + // check if second token is there + if(token) + parNum = atoi(token); + #ifdef DO_CHECKS + else + { + cout << "Parser Error: partial count not found, bad file format" << endl; // exit if value not found + return false; + } + #endif + } + #ifdef DO_CHECKS + else + { + cout << "Parser Error: partial count not found, bad file format" << endl; // exit if value not found + return false; + } + #endif + // from now on we take for granted that format is correct + + // init partials data structure + partials.init(parNum, hopSize); + + //---------------------------------------------------------------------------------------- + // fill in partials data structure + getline(fin, s); // get rid of intro line "partials-data" + getline(fin, s); // first important line + + while (!fin.eof()) + { + //------------------------------------- + // partial specific info + token = strtok((char *)s.c_str(), " "); + parIndex = atoi(token); // partial index + + token = strtok(0, " "); // num of frames, not used, cos we will do linear interpolation for missing frames +// frameNum = atoi(token); +// partials.partialNumFrames[parIndex] = frameNum; + + token = strtok(0, " "); // time of first frame, still char * + startSample = fromTimeToSamples(atof(token)); // convert time to samples + partials.partialStartSample[parIndex] = startSample; + + token = strtok(0, " "); // time of last frame, still char * + endSample = fromTimeToSamples(atof(token)); // convert time to samples + partials.partialEndSample[parIndex] = endSample; + + frameNum = ((endSample-startSample)/hopSize) + 1; // num of frames, including missing consecutive ones [+1 one cos we count frames, not hops] + partials.partialNumFrames[parIndex] = frameNum; + + + // check if this is the highest sample value so far + if(endSample > maxSample) + maxSample = endSample; + + // update data structure + partials.update(parIndex, frameNum); + + + //------------------------------------- + // frames + getline(fin, s); + token = strtok((char *)s.c_str(), " "); // frame time + frameIndex = -1; + + // unroll first iteration, so that in the following loop we save the check on the last frame to calculate increments + if(token) // all frames data are on one line, in groups of 3 entries + { + frameIndex++; + + endSample = fromTimeToSamples(atof(token)); + + token = strtok(0, " "); // frame frequency + prevFreq = atof(token); + partials.partialFrequencies[parIndex][frameIndex] = (float)prevFreq; + partials.partialFreqMean[parIndex] += prevFreq; // for frequency mean + + token = strtok(0, " "); // frame amplitude + prevAmp = atof(token); + partials.partialAmplitudes[parIndex][frameIndex] = (float)prevAmp; + + token = strtok(0, " "); // next frame frequency, to be checked + } + + // here the loop starts + while(token) // all frames data are on one line, in groups of 3 entries + { + frameIndex++; + missSampCnt = 0; + + startSample = fromTimeToSamples(atof(token)); + + token = strtok(0, " "); // frame frequency + freq = atof(token); + + token = strtok(0, " "); // frame amplitude + amp = atof(token); + // now we know all about the current frame, but we want to know if some frames are missing between this and the last one + + // while current frame sample is farther than one hopsize... + while(startSample > endSample+hopSize) + { + missSampCnt++; // ...one sample is missing + endSample += hopSize; // move to next hop + } + + // if frames are missing do interpolation and update indices + if(missSampCnt>0) + startSample = interpolateSamples(parIndex, &frameIndex, missSampCnt, endSample+hopSize, freq, amp, &prevFreq, &prevAmp); + + partials.partialFrequencies[parIndex][frameIndex] = (float)freq; + partials.partialFreqMean[parIndex] += freq; // for frequency mean + partials.setFreqDelta(parIndex, frameIndex-1, (freq-prevFreq)/hopSize); // freq delta between prev and current frame + prevFreq = freq; + + partials.partialAmplitudes[parIndex][frameIndex] = (float)amp; + partials.setAmpDelta(parIndex, frameIndex-1, (amp-prevAmp)/hopSize); // amp delta between prev and current frame + prevAmp = amp; + + endSample = startSample; + token = strtok(0, " "); // next frame frequency, to be checked + } + #ifdef DO_CHECKS + if(frameIndex != (frameNum-1)) + { + cout << "Parser Error: frame count mismatch on partial " << parIndex << ", bad file format" << endl; // exit if mismatch + cout << "frameIndex: " << frameIndex << endl; + cout << "frameNum: " << frameNum << endl; + return false; + } + #endif + + partials.partialFreqMean[parIndex] /= partials.partialNumFrames[parIndex]; // frequency mean + + getline(fin, s); // next partial line, to check + } + #ifdef DO_CHECKS + if(parIndex != (parNum-1)) + { + cout << "Parser Error: partial count mismatch, bad file format" << endl; // exit if mismatch + return false; + } + #endif + + partials.setHopNum(maxSample/hopSize); + + gettimeofday(&stop, NULL); + parserT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); + + gettimeofday(&start, NULL); + staticCalculations(); + gettimeofday(&stop, NULL); + staticT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); + + fin.close(); + + + printf("\n-----------------------\n"); + printf("\nFile: %s\n", filename); + printf("\n-----------------------\n"); + printf("Profiler\n"); + printf("-----------------------\n"); + printf("Hop size parser:\t\t%lu usec\n", hopSizeT); + printf("File parser:\t\t\t%lu usec\n", parserT); + printf("Static calculations:\t\t%lu usec\n", staticT); + printf("\n\nTotal:\t\t%lu usec\n", hopSizeT+parserT+staticT); + printf("-----------------------\n"); + + return true; +} + + +int Spear_parser::interpolateSamples(int parIndex, int *frameIndex, int missCnt, int nextSample, double nextFreq, double nextAmp, double *prevFreq, double *prevAmp) +{ + int frame = *frameIndex; // current frame index + int sample = nextSample - (hopSize*(missCnt)); // move from next real frame sample to first missing frame sample + double freq = *prevFreq; // freq of the prev real frame + double freqStep = (nextFreq-*prevFreq)/(missCnt+1); // fixed freq step between hops, for missing frames [linear interpolation] + double deltaFreq = freqStep/hopSize; // fixed hop freq step in samples + double amp = *prevAmp; // same for amp... + double ampStep = (nextAmp-*prevAmp)/(missCnt+1); + double deltaAmp = ampStep/hopSize; + + // for each missing frame + for(int i=0; i<missCnt; i++) + { + // calculate values for current missing frame + freq += freqStep; + amp += ampStep; + // save values + partials.partialFrequencies[parIndex][frame] = freq; + partials.partialAmplitudes[parIndex][frame] = amp; + partials.partialFreqMean[parIndex] += freq; // for frequency mean + // set deltas of previous frame [real or missing] + partials.setFreqDelta(parIndex, frame-1, deltaFreq); + partials.setAmpDelta(parIndex, frame-1, deltaAmp); + // move to next frame [missing or real] + sample += hopSize; + frame++; + } + + // update global values + *frameIndex = frame; + *prevFreq = freq; + *prevAmp = amp; + + return sample; // return the frame sample of the next real frame +} + + + +// for each frame, statically calculate: +// - which partial is active [and the total num of active partials] +// - at which local frame each partial is +void Spear_parser::staticCalculations() +{ + partials.maxActiveParNum = 0; // init to find maximum + + unsigned short *indices = new unsigned short[partials.parNum]; // temp array to store up to the maximum num of active partial indices + unsigned int activeCnt = 0; // counts the num of active partials in each frame + + unsigned int frameSample = 0; // current frame in samples + + char *partialStarted = new char [partials.parNum]; // index of the last local frame found per each partial + fill(partialStarted, partialStarted+partials.parNum, 0); + + for(unsigned int i=0; i<partials.hopNum+1; i++) // for each frame [not hops, this explains the +1] + { + //partials.localPartialFrames[i] = new int[partials.parNum]; // init all local frames to -1 + //fill(partials.localPartialFrames[i], partials.localPartialFrames[i]+partials.parNum, -1); + + frameSample = i*hopSize; // current frame, expressed in samples + activeCnt = 0; // reset a each frame + + for(unsigned int j=0; j<partials.parNum; j++) // for each partial + { + // check if inside active time region [expressed in samples] + if( (frameSample>=partials.partialStartSample[j]) && (frameSample<partials.partialEndSample[j]) ) // frame sample not equal to end sample, this filters out last frames and partials with one frame only + { + // activity + indices[activeCnt] = j; // save active index + activeCnt++; // increase counter + + // partial local frames + if(partialStarted[j]==0) // this partial has just started, so current local frame is first frame + { + partialStarted[j] = 1; + partials.partialStartFrame[j] = i; // here is the number of the first frame + } + } + } + + // activity + partials.activePartialNum[i] = activeCnt; // save number of active partials for this frame + partials.activePartials[i] = new unsigned int[activeCnt]; // set correct size to save all indices + + // look for maximum number of active partials at the same time + if(activeCnt > partials.maxActiveParNum) + partials.maxActiveParNum = activeCnt; + + // copy indices + for(unsigned int k=0; k<activeCnt; k++) + partials.activePartials[i][k] = indices[k]; + } + + delete[] indices; + delete[] partialStarted; + + delete[] partials.partialStartSample; + delete[] partials.partialEndSample; +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/d-box/spear_parser.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,188 @@ +/* + * spear_parser.h v1.2 + * + * Created on: May 6, 2014 + * Author: Victor Zappi + */ + +#ifndef SPEAR_PARSER_H_ +#define SPEAR_PARSER_H_ + +#include <iostream> +#include <fstream> +#include <cstring> +#include <string> +#include <stdlib.h> // atoi, atof +#include <math.h> +#include <algorithm> // std::fill + +#include <sys/time.h> + +using namespace std; + + +//------------------------------------------------------------------------------------------------ +// partials +//------------------------------------------------------------------------------------------------ + +class Spear_parser; // for class friendship + +class Partials +{ + friend class Spear_parser; + friend class Dbox_parser; + +public: + int **partialSamples; // sample at which each frame is + float **partialFrequencies; // frequencies at each frame + float **partialAmplitudes; // amplitudes at each frame + unsigned int *partialNumFrames; // Length of each partial in frames + unsigned int *partialStartFrame; // frame at which each partial begins + float **partialFreqDelta; // constant frequency slope for each partial in each frame interval + float **partialAmpDelta; // constant amplitude slope for each partial in each frame interval + float *partialFreqMean; // frequency mean for each partial, over all its frames + + unsigned short *activePartialNum; // num of each active partial at each frame + unsigned int **activePartials; // indices of all active partials at each frame + + + int getPartialNum(); + int getHopNum(); + int getMaxActivePartialNum(); + +private: + Partials(); + ~Partials(); + + unsigned int *partialStartSample; // sample at which each partial begins + unsigned int *partialEndSample; // sample at which each partial ends [sample gap between 2 consecutive frames can be an integer multiple of hopSize] + unsigned int parNum; + unsigned int currentSample; + unsigned int hopSize; + unsigned int hopNum; + unsigned int maxActiveParNum; + + void init(int parNum, int hopSize, bool isDBX=false); + void update(int parIndex, int frameNum); + void setFreqDelta(int parIndex, int frameNum, double delta); + void setAmpDelta(int parIndex, int frameNum, double delta); + void setHopNum(int hopNum); +}; + +inline int Partials::getPartialNum() +{ + return parNum; +} + +inline void Partials::setHopNum(int hopN) +{ + hopNum = hopN; + + // prepare data structures + activePartialNum = new unsigned short[hopNum+1]; // +1 cos total num of frames = num of hops+1 + activePartials = new unsigned int *[hopNum+1]; +} + +// useful to increase current sample using a modulo on the total number of samples [easy to be deduced from the total num or hops] +inline int Partials::getHopNum() +{ + return hopNum; +} + +inline void Partials::setFreqDelta(int parIndex, int frameNum, double delta) +{ + partialFreqDelta[parIndex][frameNum] = delta; +} + +inline void Partials::setAmpDelta(int parIndex, int frameNum, double delta) +{ + partialAmpDelta[parIndex][frameNum] = delta; +} + +inline int Partials::getMaxActivePartialNum() +{ + return maxActiveParNum; +} + + + + + + + +//------------------------------------------------------------------------------------------------ +// spear parser +//------------------------------------------------------------------------------------------------ + +class Spear_parser +{ +public: + Spear_parser(); + ~Spear_parser(); + + Partials partials; + + bool parseFile(string filename, int hopsize=-1, int samplerate = 44100); + bool parseFile(char *filename, int hopsize=-1, int samplerate = 44100); + int getHopSize(); + int getFileSampleRate(); + double getDeltaTime(); + +private: + + int hopSize; + int fileSampleRate; + double deltaTime; // min time gap between consecutive frames + + timeval start, stop; + unsigned long hopSizeT, parserT, staticT; + + void calculateDeltaTime(); + void calculateHopSize(char *filename); + bool parser(char *filename, int hopsize=-1, int samplerate=44100); + bool DBXparser(char *filename, int samplerate=44100); + bool TXTparser(char *filename, int hopsize=-1, int samplerate=44100); + int fromTimeToSamples(float time); + int interpolateSamples(int parIndex, int *frameIndex, int missCnt, int nextSample, + double nextFreq, double nextAmp, double *prevFreq, double *prevAmp); + void staticCalculations(); + +}; + +inline bool Spear_parser::parseFile(string filename, int hopsize, int samplerate) +{ + return parser((char *)filename.c_str(), hopsize, samplerate); +} + +inline bool Spear_parser::parseFile(char *filename, int hopsize, int samplerate) +{ + return parser(filename, hopsize, samplerate); +} + +inline void Spear_parser::calculateDeltaTime() +{ + deltaTime = (double)hopSize/ (double)fileSampleRate; +} + +// each time value in the file is rounded, and 2 consecutive frames can differ of a time gap = i*deltaTime, where i is a positive integer +inline int Spear_parser::fromTimeToSamples(float time) +{ + return round(time/deltaTime)*hopSize; // round is necessary since in the file log time values are rounded, so they do not apparently look like integer multiples of deltaTime +} + +inline int Spear_parser::getHopSize() +{ + return hopSize; +} + +inline int Spear_parser::getFileSampleRate() +{ + return fileSampleRate; +} + +inline double Spear_parser::getDeltaTime() +{ + return deltaTime; +} + +#endif /* SPEAR_PARSER_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/oscillator_bank/audio_routines.S Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,161 @@ +@ +@ audio_routines.S +@ +@ NEON-based functions for time-critical audio processing +@ +@ Andrew McPherson 2014 +@ Queen Mary University of London +@ + + .syntax unified + .arch armv7-a + .fpu neon + +@ void oscillator_bank_neon(int numAudioFrames, float *audioOut, +@ int activePartialNum, int lookupTableSize, +@ float *phases, float *frequencies, float *amplitudes, +@ float *freqDerivatives, float *ampDerivatives, +@ float *lookupTable); + +@ Registers: +@ r0: numAudioFrames How many frames to render +@ r1: audioOut Buffer for audio output samples [stereo] +@ r2: activePartialNum How many active partials to render +@ r3: lookupTableSize Size of lookup table +@ ---- other arguments start on the stack and are moved: ----- +@ r4: phases Phase of each oscillator (pointer) +@ r5: frequencies Normalised frequency of each oscillator (pointer) +@ r6: amplitudes Normalised amplitude of each oscillator (pointer) +@ r7: freqDerivatives Derivative of frequency for each oscillator (pointer) +@ r8: ampDerivatives Derivative of amplitude for each oscillator (pointer) +@ r9: lookupTable Lookup table containing one oscillation +@ +@ Alignment requirements: +@ audioOut: 8-byte boundary +@ phases: 16-byte boundary +@ frequencies: 16-byte boundary +@ amplitudes: 16-byte boundary +@ freqDerivatives: 16-byte bounary +@ ampDerivatives: 16-byte boundary +@ lookupTable: 4-byte boundary (TODO: check this) + + .align 2 + .global oscillator_bank_neon + .thumb + .thumb_func + .type oscillator_bank_neon, %function +oscillator_bank_neon: + + +dSample .dn D6.F32 +qPhases .qn Q8.F32 +dPhases_0 .dn D16.F32 +dPhases_1 .dn D17.F32 +qFreqs .qn Q9.F32 +dFreqs_0 .dn D18.F32 +dFreqs_1 .dn D19.F32 +qAmps .qn Q10.F32 +dAmps_0 .dn D20.F32 +dAmps_1 .dn D21.F32 +qFreqDs .qn Q11.F32 +dFreqDs_0 .dn D22.F32 +dFreqDs_1 .dn D23.F32 +qAmpDs .qn Q12.F32 +dAmpDs_0 .dn D24.F32 +dAmpDs_1 .dn D25.F32 + +qBaseInts .qn Q13.U32 @ Base indexes: unsigned ints x4 +dBaseInts_0 .dn D26.U32 +dBaseInts_1 .dn D27.U32 +qFractions .qn Q14.F32 @ Fraction indexes: floats x4 +qTableBase .qn Q15.U32 @ Base of lookup table + + cmp r0, #0 @ Check for trivial case 1: zero frames + it eq + bxeq lr @ Return if that's the case (otherwise might have odd behaviour) + cmp r2, #4 @ Check for trivial case 2: zero oscillators + it lt + bxlt lr @ Return if that's the case + + push {r4-r11} @ Now arguments start 32 bytes above SP + add r11, sp, #32 @ Pointer to 32 bytes into the stack + ldm r11, {r4-r9} @ Load 6 arguments into registers + + vdup qTableBase, r9 @ Move lookup table base index into 4 ints + + @ Outer loop: iterate over the number of oscillators, choosing 4 at a + @ time to work with. +oscbank_oscillator_loop: + vld1 {dPhases_0, dPhases_1}, [r4] @ no increment; will store at end of sample loop + vld1 {dFreqs_0, dFreqs_1}, [r5] + vld1 {dAmps_0, dAmps_1}, [r6] + vld1 {dFreqDs_0, dFreqDs_1}, [r7]! @ increment; won't update at end of sample loop + vld1 {dAmpDs_0, dAmpDs_1}, [r8]! + + push {r0-r1,r4-r8} + @ --- inner loop: iterate over the number of samples --- +oscbank_sample_loop: + vcvt qBaseInts, qPhases @ Take floor(phases) + vmov q2.f32, #1.0 @ Load 1.0 into every slot of q2 + vshl q0.U32, qBaseInts, #2 @ Shift the indexes left 2 (*4 for float addressing) + vcvt qFractions, qBaseInts @ int back to float + vadd q0.U32, q0.U32, qTableBase @ Find memory addresses + + vmov r4, r5, d0 @ Move two indexes to ARM registers + vmov r6, r7, d1 @ Move two more indexes to ARM registers + vsub qFractions, qPhases, qFractions @ fraction = phase - floor(phase) + + vldr.64 d0, [r4] @ Load two consecutive floats at each location + vldr.64 d1, [r5] @ These hold the previous and following samples in the table + vldr.64 d2, [r6] @ TODO: check whether these work at 4-byte alignment + vldr.64 d3, [r7] + + @ Format at this point: + @ Osc0(before) Osc0(after) Osc1(before) Osc1(after) Osc2(before) Osc2(after) Osc3(before) Osc3(after) + @ We want: + @ Osc0(before) Osc1(before) Osc2(before) Osc3(before) Osc0(after) Osc1(after) Osc2(after) Osc3(after) + + vuzp.32 q0, q1 @ Now q0 contains before, q1 contains after + vsub q2.f32, q2.f32, qFractions @ q2 = 1.0 - fraction + vmul q1.f32, q1.f32, qFractions @ q1 = fraction * after + vmul q0.f32, q0.f32, q2.f32 @ q0 = (1.0 - fraction) * before + + vadd qPhases, qPhases, qFreqs @ Update phases + vadd qFreqs, qFreqs, qFreqDs @ Update frequencies + + vadd q0.f32, q0.f32, q1.f32 @ Add two interpolated components to get the final sample + vdup q2.u32, r3 @ Put lookup table size into each element of q2 + vcvt qBaseInts, qPhases @ Take floor of new phases + vmul q0.f32, q0.f32, qAmps @ Multiply samples by current amplitude + + vld1 dSample, [r1] @ Load the current stereo samples + vpadd d2.f32, d0.f32, d1.f32 @ Pairwise accumulate q0 (output sample) into d2 + + vand q2, q2, qBaseInts @ Logical AND of new phase int leaves 1 bit set only if phase >= table size + vpadd d3.f32, d2.f32, d2.f32 @ Pairwise accumulate d2 into d0 --> d0[0] and d0[1] both hold total of 4 oscillators + vadd qAmps, qAmps, qAmpDs @ Update amplitudes + vcvt q0.f32, q2.u32 @ Convert int back to float after AND operation + + vadd dSample, dSample, d3.f32 @ Add oscillator outputs to each channel + + subs r0, r0, #1 @ numFrames-- + vsub qPhases, qPhases, q0.f32 @ Keep phases in table range + vst1 dSample, [r1]! @ Store back in buffer and increment by 8 + + it gt + bgt oscbank_sample_loop @ Loop if numFrames > 0 + + @ --- end inner loop --- + pop {r0-r1,r4-r8} @ Restore registers: restores audioOut and numFrames, among others + + vst1 {dPhases_0, dPhases_1}, [r4]! @ Store phases back to array + vst1 {dFreqs_0, dFreqs_1}, [r5]! @ Store frequencies back to array + vst1 {dAmps_0, dAmps_1}, [r6]! @ Store amplitudes back to array + @ No need to update r7, r8 + + subs r2, r2, #4 @ numPartials -= 4 + it gt + bgt oscbank_oscillator_loop @ Loop if numPartials > 0 + + pop {r4-r11} + bx lr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/oscillator_bank/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,116 @@ +/* + * main.cpp + * + * Created on: Oct 24, 2014 + * Author: parallels + */ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +int gNumOscillators = 32; +int gWavetableLength = 1024; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --num-oscillators [-n] oscs: Set the number of oscillators to use (default: 32)\n"; + cerr << " --wavetable [-w] length: Set the wavetable length in samples (default: 1024)\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"num-oscillators", 1, NULL, 'n'}, + {"wavetable", 1, NULL, 'w'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hn:w:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'n': + gNumOscillators = atoi(optarg); + if(gNumOscillators <= 0) { + usage(basename(argv[0])); + exit(0); + } + break; + case 'w': + gWavetableLength = atoi(optarg); + if(gWavetableLength < 4) + gWavetableLength = 4; + if(gWavetableLength > 16384) + gWavetableLength = 16384; + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, 0) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + if(settings.verbose) { + cout << "--> Using " << gNumOscillators << " oscillators and wavetable of " << gWavetableLength << " samples\n"; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/oscillator_bank/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,238 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\.io + + */ + +/* + * render.cpp + * + * Created on: Oct 24, 2014 + * Author: parallels + */ + +/** +\example 4_oscillator_bank + +Oscillator Bank +---------------------- + +These files demonstrate an oscillator bank implemented in assembly code +that is used as part of the d-box project. +*/ + +#include <Bela.h> +#include <rtdk.h> +#include <cstdlib> +#include <cmath> +#include <cstring> +#include <time.h> + +const float kMinimumFrequency = 20.0f; +const float kMaximumFrequency = 8000.0f; + +float *gWavetable; // Buffer holding the precalculated sine lookup table +float *gPhases; // Buffer holding the phase of each oscillator +float *gFrequencies; // Buffer holding the frequencies of each oscillator +float *gAmplitudes; // Buffer holding the amplitudes of each oscillator +float *gDFrequencies; // Buffer holding the derivatives of frequency +float *gDAmplitudes; // Buffer holding the derivatives of amplitude + +float gAudioSampleRate; +int gSampleCount; // Sample counter for indicating when to update frequencies +float gNewMinFrequency; +float gNewMaxFrequency; + +// Task for handling the update of the frequencies using the matrix +AuxiliaryTask gFrequencyUpdateTask; + +// These settings are carried over from main.cpp +// Setting global variables is an alternative approach +// to passing a structure to userData in setup() + +extern int gNumOscillators; +extern int gWavetableLength; + +void recalculate_frequencies(); + +extern "C" { + // Function prototype for ARM assembly implementation of oscillator bank + void oscillator_bank_neon(int numAudioFrames, float *audioOut, + int activePartialNum, int lookupTableSize, + float *phases, float *frequencies, float *amplitudes, + float *freqDerivatives, float *ampDerivatives, + float *lookupTable); +} + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. +bool setup(BelaContext *context, void *userData) +{ + srandom(time(NULL)); + + if(context->audioChannels != 2) { + rt_printf("Error: this example needs stereo audio enabled\n"); + return false; + } + + // Initialise the sine wavetable + if(posix_memalign((void **)&gWavetable, 8, (gWavetableLength + 1) * sizeof(float))) { + rt_printf("Error allocating wavetable\n"); + return false; + } + for(int n = 0; n < gWavetableLength + 1; n++) + gWavetable[n] = sinf(2.0 * M_PI * (float)n / (float)gWavetableLength); + + // Allocate the other buffers + if(posix_memalign((void **)&gPhases, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating phase buffer\n"); + return false; + } + if(posix_memalign((void **)&gFrequencies, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating frequency buffer\n"); + return false; + } + if(posix_memalign((void **)&gAmplitudes, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating amplitude buffer\n"); + return false; + } + if(posix_memalign((void **)&gDFrequencies, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating frequency derivative buffer\n"); + return false; + } + if(posix_memalign((void **)&gDAmplitudes, 16, gNumOscillators * sizeof(float))) { + rt_printf("Error allocating amplitude derivative buffer\n"); + return false; + } + + // Initialise buffer contents + + float freq = kMinimumFrequency; + float increment = (kMaximumFrequency - kMinimumFrequency) / (float)gNumOscillators; + + for(int n = 0; n < gNumOscillators; n++) { + gPhases[n] = 0.0; + + if(context->analogFrames == 0) { + // Random frequencies when used without matrix + gFrequencies[n] = kMinimumFrequency + (kMaximumFrequency - kMinimumFrequency) * ((float)random() / (float)RAND_MAX); + } + else { + // Constant spread of frequencies when used with matrix + gFrequencies[n] = freq; + freq += increment; + } + + // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians + gFrequencies[n] *= (float)gWavetableLength / context->audioSampleRate; + gAmplitudes[n] = ((float)random() / (float)RAND_MAX) / (float)gNumOscillators; + gDFrequencies[n] = gDAmplitudes[n] = 0.0; + } + + increment = 0; + freq = 440.0; + + for(int n = 0; n < gNumOscillators; n++) { + // Update the frequencies to a regular spread, plus a small amount of randomness + // to avoid weird phase effects + float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; + float newFreq = freq * randScale; + + // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians + gFrequencies[n] = newFreq * (float)gWavetableLength / context->audioSampleRate; + + freq += increment; + } + + // Initialise auxiliary tasks + if((gFrequencyUpdateTask = Bela_createAuxiliaryTask(&recalculate_frequencies, 85, "bela-update-frequencies")) == 0) + return false; + + //for(int n = 0; n < gNumOscillators; n++) + // rt_printf("%f\n", gFrequencies[n]); + + gAudioSampleRate = context->audioSampleRate; + gSampleCount = 0; + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + // Initialise buffer to 0 + memset(context->audioOut, 0, 2 * context->audioFrames * sizeof(float)); + + // Render audio frames + oscillator_bank_neon(context->audioFrames, context->audioOut, + gNumOscillators, gWavetableLength, + gPhases, gFrequencies, gAmplitudes, + gDFrequencies, gDAmplitudes, + gWavetable); + + if(context->analogFrames != 0 && (gSampleCount += context->audioFrames) >= 128) { + gSampleCount = 0; + gNewMinFrequency = map(context->analogIn[0], 0, 1.0, 1000.0f, 8000.0f); + gNewMaxFrequency = map(context->analogIn[1], 0, 1.0, 1000.0f, 8000.0f); + + // Make sure max >= min + if(gNewMaxFrequency < gNewMinFrequency) { + float temp = gNewMaxFrequency; + gNewMaxFrequency = gNewMinFrequency; + gNewMinFrequency = temp; + } + + // Request that the lower-priority task run at next opportunity + //Bela_scheduleAuxiliaryTask(gFrequencyUpdateTask); + } +} + +// This is a lower-priority call to update the frequencies which will happen +// periodically when the matrix is enabled. By placing it at a lower priority, +// it has minimal effect on the audio performance but it will take longer to +// complete if the system is under heavy audio load. + +void recalculate_frequencies() +{ + float freq = gNewMinFrequency; + float increment = (gNewMaxFrequency - gNewMinFrequency) / (float)gNumOscillators; + + for(int n = 0; n < gNumOscillators; n++) { + // Update the frequencies to a regular spread, plus a small amount of randomness + // to avoid weird phase effects + float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; + float newFreq = freq * randScale; + + // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians + gFrequencies[n] = newFreq * (float)gWavetableLength / gAudioSampleRate; + + freq += increment; + } +} + + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + free(gWavetable); + free(gPhases); + free(gFrequencies); + free(gAmplitudes); + free(gDFrequencies); + free(gDAmplitudes); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/tank_wars/game.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,339 @@ +/* + * game.cpp + * + * Created on: Nov 10, 2014 + * Author: parallels + */ + +#include <cmath> +#include <cstdlib> +#include "vector_graphics.h" +#include <Utilities.h> + +// Virtual screen size +int screenWidth, screenHeight; + +// Basic information on the terrain and the tanks +float *groundLevel; // Y coordinate of the ground for each X coordinate +float tank1X, tank1Y, tank2X, tank2Y; // Positions of the two tanks +float tankRadius = 20; // Radius of the tanks +float cannonLength = 40; // How long the cannon on each tank extends +float gravity = 0.05; // Strength of gravity + +// Current state of the game +int playerHasWon = 0; // 1 if player 1 wins, 2 if player 2 wins, 0 if game in progress +bool player1Turn = true; // true if it's player 1's turn; false otherwise +float tank1CannonAngle = M_PI/2; +float tank2CannonAngle = M_PI/2; // Direction the tank cannons are pointing +float tank1CannonStrength = 3; +float tank2CannonStrength = 3; // Strength of intended projectile launch + +// Location of the projectile +bool projectileInMotion = false; +float projectilePositionX, projectilePositionY; +float projectileVelocityX, projectileVelocityY; + +// Infor needed for sound rendering +bool collisionJustOccurred = false; +bool tankHitJustOccurred = false; + +// Useful utility function for generating random floating-point values +float randomFloat(float low, float hi) +{ + float r = (float)random() / (float)RAND_MAX; + return map(r, 0, 1, low, hi); +} + +// Restart the game, without reallocating memory +void restartGame() +{ + float player1Height = screenHeight * 3/4; // randomFloat(screenHeight/2, screenHeight-5); + float player2Height = screenHeight - 5; // randomFloat(screenHeight/2, screenHeight-5); + for(int i = 0; i < screenWidth * 0.2; i++) { + groundLevel[i] = player1Height; + } + for(int i = screenWidth * 0.2; i < screenWidth * 0.8; i++) { + groundLevel[i] = player1Height + (player2Height - player1Height) * (i - screenWidth*0.2)/(screenWidth*0.6); + } + for(int i = screenWidth * 0.8; i < screenWidth; i++) { + groundLevel[i] = player2Height; + } + + // Set the location of the two tanks so they rest on the ground at opposite sides + tank1X = screenWidth * 0.1; + tank1Y = player1Height; + tank2X = screenWidth * 0.9; + tank2Y = player2Height; + + playerHasWon = 0; + projectileInMotion = false; +} + +// Initialise the game +void setupGame(int width, int height) +{ + // Set the screen size + screenWidth = width; + screenHeight = height; + + // Initialize the ground level + groundLevel = new float[screenWidth]; + + restartGame(); +} + +// Advance the turn to the next player +void nextPlayersTurn() { + player1Turn = !player1Turn; +} + + +// Move forward one frame on the game physics +void nextGameFrame() +{ + if(!projectileInMotion) + return; + + // Update position of projectile + projectilePositionX += projectileVelocityX; + projectilePositionY += projectileVelocityY; + projectileVelocityY += gravity; + + // Check collision with tanks first: a collision with tank 1 means player 2 wins and vice-versa + if((tank1X - projectilePositionX)*(tank1X - projectilePositionX) + + (tank1Y - projectilePositionY)*(tank1Y - projectilePositionY) + <= tankRadius * tankRadius) + { + projectileInMotion = false; + collisionJustOccurred = false; + tankHitJustOccurred = true; + playerHasWon = 2; + } + else if((tank2X - projectilePositionX)*(tank2X - projectilePositionX) + + (tank2Y - projectilePositionY)*(tank2Y - projectilePositionY) + <= tankRadius * tankRadius) + { + projectileInMotion = false; + collisionJustOccurred = false; + tankHitJustOccurred = true; + playerHasWon = 1; + } + else if(projectilePositionX < 0 || projectilePositionX >= screenWidth) { + // Check collision whether projectile has exited the screen to the left or right + projectileInMotion = false; + collisionJustOccurred = true; + nextPlayersTurn(); + } + else if(projectilePositionY >= groundLevel[(int)floorf(projectilePositionX)]) { + // Check for projectile collision with ground + projectileInMotion = false; + collisionJustOccurred = true; + nextPlayersTurn(); + } +} + +// Updates for game state +void setTank1CannonAngle(float angle) +{ + tank1CannonAngle = angle; +} + +void setTank2CannonAngle(float angle) +{ + tank2CannonAngle = angle; +} + +void setTank1CannonStrength(float strength) +{ + tank1CannonStrength = strength; +} + +void setTank2CannonStrength(float strength) +{ + tank2CannonStrength = strength; +} + +// FIRE! +void fireProjectile() +{ + // Can't fire while projectile is already moving, or if someone has won + if(projectileInMotion) + return; + if(playerHasWon != 0) + return; + + if(player1Turn) { + projectilePositionX = tank1X + cannonLength * cosf(tank1CannonAngle); + projectilePositionY = tank1Y - cannonLength * sinf(tank1CannonAngle); + projectileVelocityX = tank1CannonStrength * cosf(tank1CannonAngle); + projectileVelocityY = -tank1CannonStrength * sinf(tank1CannonAngle); + } + else { + projectilePositionX = tank2X + cannonLength * cosf(tank2CannonAngle); + projectilePositionY = tank2Y - cannonLength * sinf(tank2CannonAngle); + projectileVelocityX = tank2CannonStrength * cosf(tank2CannonAngle); + projectileVelocityY = -tank2CannonStrength * sinf(tank2CannonAngle); + } + + // GO! + projectileInMotion = true; +} + +// Game state queries +bool gameStatusPlayer1Turn() +{ + return player1Turn; +} + +bool gameStatusProjectileInMotion() +{ + return projectileInMotion; +} + +int gameStatusWinner() +{ + return playerHasWon; +} + +bool gameStatusCollisionOccurred() +{ + if(collisionJustOccurred) { + collisionJustOccurred = false; + return true; + } + return false; +} + +bool gameStatusTankHitOccurred() +{ + if(tankHitJustOccurred) { + tankHitJustOccurred = false; + return true; + } + return false; +} + + +float gameStatusProjectileHeight() +{ + return projectilePositionY / (float)screenHeight; +} + +// Clean up any allocated memory for the game +void cleanupGame() +{ + delete groundLevel; +} + +// Drawing routines. Arguments are (interleaved) buffer to render +// into, the available size, and the target for how many samples +// to use (actual usage might vary slightly). Regardless of +// lengthTarget, never use more than bufferSize samples. + +int drawGround(float *buffer, int bufferSize, int framesTarget) +{ + int length; + + // Calculate total length of ground line, to arrive at a speed calculation + float totalLineLength = 0.4f*screenWidth + + sqrtf(0.36f*screenWidth*screenWidth + + (tank2Y-tank1Y)*(tank2Y-tank1Y)); + + // Speed is calculated in pixels per frame + float speed = totalLineLength / (float)framesTarget; + + // Draw three lines: platforms for tanks and the connecting line. + // Eventually, render a more complex ground from the array. + length = renderLine(0, tank1Y, screenWidth * 0.2, tank1Y, + speed, buffer, bufferSize); + length += renderLine(screenWidth * 0.2, tank1Y, screenWidth * 0.8, tank2Y, + speed, &buffer[length], bufferSize - length); + length += renderLine(screenWidth * 0.8, tank2Y, screenWidth, tank2Y, + speed, &buffer[length], bufferSize - length); + + return length; +} + +int drawTanks(float *buffer, int bufferSize, int framesTarget) +{ + int length = 0; + + // Calculate total length of tank lines, to arrive at a speed calculation + float totalLineLength = 2.0*M_PI*tankRadius + 2.0*(cannonLength - tankRadius); + + // Speed is calculated in pixels per frame + float speed = totalLineLength / (float)framesTarget; + + if(playerHasWon != 2) { + // Tank 1 body = semicircle + line + length += renderArc(tank1X, tank1Y, tankRadius, M_PI, 2.0 * M_PI, + speed, buffer, bufferSize); + length += renderLine(tank1X + tankRadius, tank1Y, + tank1X - tankRadius, tank1Y, + speed, &buffer[length], bufferSize - length); + // Tank 1 cannon (line depending on angle) + length += renderLine(tank1X + tankRadius * cosf(tank1CannonAngle), + tank1Y - tankRadius * sinf(tank1CannonAngle), + tank1X + cannonLength * cosf(tank1CannonAngle), + tank1Y - cannonLength * sinf(tank1CannonAngle), + speed, &buffer[length], bufferSize - length); + } + + if(playerHasWon != 1) { + // Same idea for tank 2 + length += renderArc(tank2X, tank2Y, tankRadius, M_PI, 2.0 * M_PI, + speed, &buffer[length], bufferSize - length); + length += renderLine(tank2X + tankRadius, tank2Y, + tank2X - tankRadius, tank2Y, + speed, &buffer[length], bufferSize - length); + length += renderLine(tank2X + tankRadius * cosf(tank2CannonAngle), + tank2Y - tankRadius * sinf(tank2CannonAngle), + tank2X + cannonLength * cosf(tank2CannonAngle), + tank2Y - cannonLength * sinf(tank2CannonAngle), + speed, &buffer[length], bufferSize - length); + } + + return length; +} + +int drawProjectile(float *buffer, int bufferSize, int framesTarget) +{ + if(!projectileInMotion) + return 0; + + // Draw a point for a specified number of frames (each containing X and Y) + // Return the number of items used in the buffer, which will be twice + // the number of frames unless the buffer is full + + if(bufferSize/2 < framesTarget) { + renderPoint(projectilePositionX, projectilePositionY, buffer, bufferSize/2); + return bufferSize; + } + else { + renderPoint(projectilePositionX, projectilePositionY, buffer, framesTarget); + return framesTarget*2; + } +} + +// Main drawing routine entry point +int drawGame(float *buffer, int bufferSize) +{ + int length; + + // Based on buffer size, come up with speeds for each of the elements + // 50% of time to ground; 30% to the tanks and 20% to the projectile + // Give a margin of 25% beyond so we don't run out of buffer space + // if things take longer to draw than we guess they will + const float amountToUse = 0.375; // 0.75/2 because two samples per frame + const float groundFraction = 0.5 * amountToUse; + const float tankFraction = 0.3 * amountToUse; + const float projectileFraction = 0.2 * amountToUse; + + length = drawGround(buffer, bufferSize, bufferSize * groundFraction); + length += drawTanks(&buffer[length], bufferSize - length, + bufferSize * tankFraction); + length += drawProjectile(&buffer[length], bufferSize - length, + bufferSize * projectileFraction); + + return length; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/tank_wars/game.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,39 @@ +/* + * game.h + * + * Created on: Nov 10, 2014 + * Author: parallels + */ + +#ifndef GAME_H_ +#define GAME_H_ + +// Initialisation +void setupGame(int width, int height); +void restartGame(); + +// Update physics +void nextGameFrame(); + +// State updaters +void setTank1CannonAngle(float angle); +void setTank2CannonAngle(float angle); +void setTank1CannonStrength(float strength); +void setTank2CannonStrength(float strength); +void fireProjectile(); + +// State queries +bool gameStatusPlayer1Turn(); +bool gameStatusProjectileInMotion(); +int gameStatusWinner(); +bool gameStatusCollisionOccurred(); +bool gameStatusTankHitOccurred(); +float gameStatusProjectileHeight(); + +// Render screen; returns length of buffer used +int drawGame(float *buffer, int bufferSize); + +// Cleanup and memory release +void cleanupGame(); + +#endif /* GAME_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/tank_wars/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,169 @@ +/* + * main.cpp + * + * Created on: Oct 24, 2014 + * Author: parallels + */ + +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <sndfile.h> +#include <Bela.h> + +extern int gScreenFramesPerSecond; + +float *gMusicBuffer = 0; +int gMusicBufferLength = 0; +float *gSoundBoomBuffer = 0; +int gSoundBoomBufferLength = 0; +float *gSoundHitBuffer = 0; +int gSoundHitBufferLength = 0; + + +using namespace std; + +// Load a sound sample from file +int loadSoundFile(const string& path, float **buffer, int *bufferLength) +{ + SNDFILE *sndfile ; + SF_INFO sfinfo ; + + if (!(sndfile = sf_open (path.c_str(), SFM_READ, &sfinfo))) { + cout << "Couldn't open file " << path << endl; + return 1; + } + + int numChan = sfinfo.channels; + if(numChan != 1) + { + cout << "Error: " << path << " is not a mono file" << endl; + return 1; + } + + *bufferLength = sfinfo.frames * numChan; + *buffer = new float[*bufferLength]; + if(*buffer == 0){ + cout << "Could not allocate buffer" << endl; + return 1; + } + + int subformat = sfinfo.format & SF_FORMAT_SUBMASK; + int readcount = sf_read_float(sndfile, *buffer, *bufferLength); + + // Pad with zeros in case we couldn't read whole file + for(int k = readcount; k < *bufferLength; k++) + (*buffer)[k] = 0; + + sf_close(sndfile); + return 0; +} + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --fps [-f] value: Set target frames per second\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + string musicFileName = "music.wav"; + string soundBoomFileName = "boom.wav"; + string soundHitFileName = "hit.wav"; + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"fps", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'f': + gScreenFramesPerSecond = atoi(optarg); + if(gScreenFramesPerSecond < 1) + gScreenFramesPerSecond = 1; + if(gScreenFramesPerSecond > 100) + gScreenFramesPerSecond = 100; + break; + case 'h': + usage(basename(argv[0])); + exit(0); + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Load the sound files + if(loadSoundFile(musicFileName, &gMusicBuffer, &gMusicBufferLength) != 0) { + cout << "Warning: unable to load sound file " << musicFileName << endl; + } + if(loadSoundFile(soundBoomFileName, &gSoundBoomBuffer, &gSoundBoomBufferLength) != 0) { + cout << "Warning: unable to load sound file " << soundBoomFileName << endl; + } + if(loadSoundFile(soundHitFileName, &gSoundHitBuffer, &gSoundHitBufferLength) != 0) { + cout << "Warning: unable to load sound file " << soundHitFileName << endl; + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, 0) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // Release sound files + if(gMusicBuffer != 0) + free(gMusicBuffer); + if(gSoundBoomBuffer != 0) + free(gSoundBoomBuffer); + if(gSoundHitBuffer != 0) + free(gSoundHitBuffer); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/tank_wars/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,337 @@ +/* + * render.cpp + * + * Created on: Oct 24, 2014 + * Author: parallels + */ + + +#include <Bela.h> +#include "game.h" +#include <rtdk.h> +#include <cmath> +#include <cstdlib> +#include <time.h> + +int gAudioFramesPerMatrixFrame = 2; // Ratio in audio to matrix sample rate + +int gInputTank1Angle = 0; // Inputs for the cannon angles +int gInputTank2Angle = 1; +int gInputLauncher = 2; // Input for launcher FSR + +int gOutputX = 0; // Outputs for the scope +int gOutputY = 1; +int gOutputPlayer1LED = 2; +int gOutputPlayer2LED = 3; + +int gGameFramesPerSecond = 60; // How often the physics are updated +int gGameFrameInterval; // ...and in frames +int gSamplesUntilNextFrame; // Counter until next update +int gSamplesSinceFinish = 0; // How long since somebody won? +bool gGameShouldRestart = false;// Whether we need to reinitiliase the game + +// Counter for overall number of samples that have elapsed +unsigned int gSampleCounter = 0; + +// 1st-order filter and peak detector for launcher input +float gLauncherLastSample = 0; +float gLauncherFilterPole = 0.8; +float gLauncherPeakValue = 0; +float gLauncherPeakFilterPole = 0.999; +float gLauncherNoiseThreshold = 0.01; +float gLauncherMinimumPeak = 0.1; +bool gLauncherTriggered = false; + +// Screen update rate; affects buffer size. Actual contents of buffer +// may be smaller than this +int gScreenWidth = 512; +int gScreenHeight = 512; +int gScreenFramesPerSecond = 25; + +// Double buffer for rendering screen. Each is an interleaved buffer +// of XY data. +float *gScreenBuffer1, *gScreenBuffer2; +float *gScreenBufferWrite, *gScreenBufferRead; +int gScreenBufferMaxLength; // What is the total buffer allocated? +int gScreenBufferReadLength; // How long is the read buffer? +int gScreenBufferWriteLength; // How long is the write (next) buffer? +int gScreenBufferReadPointer; // Where are we in the read buffer now? +int gScreenBufferNextUpdateLocation; // When should we render the next buffer? +bool gScreenNextBufferReady; // Is the next buffer ready to go? + +// Auxiliary (low-priority) task for updating the screen +AuxiliaryTask gScreenUpdateTask; + +// Buffers for music and sound effects +extern float *gMusicBuffer; +extern int gMusicBufferLength; +extern float *gSoundBoomBuffer; +extern int gSoundBoomBufferLength; +extern float *gSoundHitBuffer; +extern int gSoundHitBufferLength; + +// Current state for sound and music +int gMusicBufferPointer = 0; // 0 means start of buffer... +int gSoundBoomBufferPointer = -1; // -1 means don't play... +int gSoundHitBufferPointer = -1; +float gSoundProjectileOscillatorPhase = 0; +float gSoundProjectileOscillatorGain = 0.2; +float gOscillatorPhaseScaler = 0; + +void screen_update(); + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + +bool setup(BelaContext *context, void *userData) +{ + srandom(time(NULL)); + + // Verify we are running with matrix enabled + if(context->analogFrames == 0 || context->analogChannels < 4) { + rt_printf("Error: this example needs the matrix enabled with at least 4 channels\n"); + return false; + } + + // Initialise audio variables + gAudioFramesPerMatrixFrame = context->audioFrames / context->analogFrames; + gOscillatorPhaseScaler = 2.0 * M_PI / context->audioSampleRate; + + // Initialise the screen buffers + gScreenBufferMaxLength = 2 * context->analogSampleRate / gScreenFramesPerSecond; + gScreenBuffer1 = new float[gScreenBufferMaxLength]; + gScreenBuffer2 = new float[gScreenBufferMaxLength]; + if(gScreenBuffer1 == 0 || gScreenBuffer2 == 0) { + rt_printf("Error initialising screen buffers\n"); + return false; + } + + gScreenBufferRead = gScreenBuffer1; + gScreenBufferWrite = gScreenBuffer2; + gScreenBufferReadLength = gScreenBufferWriteLength = 0; + gScreenBufferReadPointer = 0; + gScreenBufferNextUpdateLocation = 0; + gScreenNextBufferReady = false; + + // Initialise the game + setupGame(gScreenWidth, gScreenHeight); + gGameFrameInterval = context->analogSampleRate / gGameFramesPerSecond; + gSamplesUntilNextFrame = gGameFrameInterval; + + // Initialise auxiliary tasks + if((gScreenUpdateTask = Bela_createAuxiliaryTask(&screen_update, 90, + "bela-screen-update")) == 0) + return false; + + return true; +} + +// Swap buffers on the screen +void swap_buffers() +{ + if(gScreenBufferRead == gScreenBuffer1) { + gScreenBufferRead = gScreenBuffer2; + gScreenBufferWrite = gScreenBuffer1; + } + else { + gScreenBufferRead = gScreenBuffer1; + gScreenBufferWrite = gScreenBuffer2; + } + + gScreenBufferReadLength = gScreenBufferWriteLength; + gScreenBufferReadPointer = 0; + + // Schedule next update for 3/4 of the way through the buffer + gScreenBufferNextUpdateLocation = gScreenBufferReadLength * 0.75; + gScreenNextBufferReady = false; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + int audioIndex = 0; + + for(unsigned int n = 0; n < context->analogFrames; n++) { + for(int k = 0; k < gAudioFramesPerMatrixFrame; k++) { + // Render music and sound + float audioSample = 0; + + // Music plays in a loop + if(gMusicBuffer != 0 && gMusicBufferPointer >= 0) { + audioSample += gMusicBuffer[gMusicBufferPointer++]; + if(gMusicBufferPointer >= gMusicBufferLength) + gMusicBufferPointer = 0; + } + + // Sound effect plays until finished, then stops + if(gSoundBoomBuffer != 0 && gSoundBoomBufferPointer >= 0) { + audioSample += gSoundBoomBuffer[gSoundBoomBufferPointer++]; + if(gSoundBoomBufferPointer >= gSoundBoomBufferLength) + gSoundBoomBufferPointer = -1; + } + + if(gSoundHitBuffer != 0 && gSoundHitBufferPointer >= 0) { + audioSample += gSoundHitBuffer[gSoundHitBufferPointer++]; + if(gSoundHitBufferPointer >= gSoundHitBufferLength) + gSoundHitBufferPointer = -1; + } + + // Oscillator plays to indicate projectile height + if(gameStatusProjectileInMotion()) { + audioSample += gSoundProjectileOscillatorGain * sinf(gSoundProjectileOscillatorPhase); + + gSoundProjectileOscillatorPhase += gOscillatorPhaseScaler * constrain(map(gameStatusProjectileHeight(), + 1.0, 0, 300, 2000), 200, 6000); + if(gSoundProjectileOscillatorPhase > 2.0 * M_PI) + gSoundProjectileOscillatorPhase -= 2.0 * M_PI; + } + + context->audioOut[2*audioIndex] = context->audioOut[2*audioIndex + 1] = audioSample; + audioIndex++; + } + + // First-order lowpass filter to remove noise on launch FSR + float rawSample = analogRead(context, n, gInputLauncher); + float launchSample = gLauncherFilterPole * gLauncherLastSample + + (1.0f - gLauncherFilterPole) * rawSample; + gLauncherLastSample = launchSample; + + // Peak-detect on launch signal + if(launchSample >= gLauncherPeakValue) { + gLauncherPeakValue = launchSample; + gLauncherTriggered = false; + } + else { + if(gLauncherPeakValue - launchSample > gLauncherNoiseThreshold && !gLauncherTriggered) { + // Detected a peak; is it big enough overall? + if(gLauncherPeakValue >= gLauncherMinimumPeak) { + gLauncherTriggered = true; + // Peak detected-- fire!! + // Set both cannon strengths but only one will + // fire depending on whose turn it is + float strength = map(gLauncherPeakValue, + gLauncherMinimumPeak, 1.0, + 0.5f, 10.0f); + setTank1CannonStrength(strength); + setTank2CannonStrength(strength); + fireProjectile(); + } + } + + gLauncherPeakValue *= gLauncherPeakFilterPole; + } + + if(--gSamplesUntilNextFrame <= 0) { + // Update game physics and cannon angles + gSamplesUntilNextFrame = gGameFrameInterval; + + setTank1CannonAngle(map(analogRead(context, n, gInputTank1Angle), + 0, 1.0, M_PI, 0)); + setTank2CannonAngle(map(analogRead(context, n, gInputTank2Angle), + 0, 1.0, M_PI, 0)); + nextGameFrame(); + + // Check for collision and start sound accordingly + if(gameStatusCollisionOccurred()) { + gSoundBoomBufferPointer = 0; + } + + if(gameStatusTankHitOccurred()) { + gSoundHitBufferPointer = 0; + } + } + + if(gScreenBufferReadPointer >= gScreenBufferReadLength - 1 + && gScreenNextBufferReady) { + // Got to the end; swap buffers + swap_buffers(); + } + + // Push current screen buffer to the matrix output + if(gScreenBufferReadPointer < gScreenBufferReadLength - 1) { + float x = gScreenBufferRead[gScreenBufferReadPointer++]; + float y = gScreenBufferRead[gScreenBufferReadPointer++]; + + // Rescale screen coordinates to matrix ranges; invert the Y + // coordinate to go from normal screen coordinates to scope coordinates + analogWriteOnce(context, n, gOutputX, constrain(map(x, 0, gScreenWidth, 0, 1.0), 0, 1.0)); + analogWriteOnce(context, n, gOutputY, constrain(map(y, 0, gScreenHeight, 1.0, 0), 0, 1.0)); + } + else { + // Still not ready! Write 0 until something happens + analogWriteOnce(context, n, gOutputX, 0); + analogWriteOnce(context, n, gOutputY, 0); + } + + if(gameStatusWinner() != 0) { + // Blink one LED to show who won + // Blink both LEDs when projectile is in motion + float val = (gSampleCounter % 4000 > 2000) ? 1.0 : 0; + analogWriteOnce(context, n, gOutputPlayer1LED, gameStatusWinner() == 1 ? val : 0); + analogWriteOnce(context, n, gOutputPlayer2LED, gameStatusWinner() == 2 ? val : 0); + + // After 5 seconds, restart the game + gSamplesSinceFinish++; + if(gSamplesSinceFinish > 22050*5) + gGameShouldRestart = true; + } + else if(gameStatusProjectileInMotion()) { + // Blink both LEDs when projectile is in motion + float val = (gSampleCounter % 2000 > 1000) ? 1.0 : 0; + analogWriteOnce(context, n, gOutputPlayer1LED, val); + analogWriteOnce(context, n, gOutputPlayer2LED, val); + } + else if(gameStatusPlayer1Turn()) { + analogWriteOnce(context, n, gOutputPlayer1LED, 1.0); + analogWriteOnce(context, n, gOutputPlayer2LED, 0); + } + else { + analogWriteOnce(context, n, gOutputPlayer2LED, 1.0); + analogWriteOnce(context, n, gOutputPlayer1LED, 0); + } + + // Check if we have reached the point where we should next update + if(gScreenBufferReadPointer >= gScreenBufferNextUpdateLocation && + !gScreenNextBufferReady) { + // Update the screen at lower priority than the audio thread + Bela_scheduleAuxiliaryTask(gScreenUpdateTask); + } + + gSampleCounter++; + } +} + +void screen_update() +{ + // If we should restart, reinitialise the game + if(gGameShouldRestart) { + restartGame(); + gGameShouldRestart = false; + gSamplesSinceFinish = 0; + } + + // Render the game based on the current state + gScreenBufferWriteLength = drawGame(gScreenBufferWrite, gScreenBufferMaxLength); + + // Flag it as ready to go + gScreenNextBufferReady = true; +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + // Clean up the game state + cleanupGame(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/tank_wars/vector_graphics.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,72 @@ +/* + * vector_graphics.cpp + * + * Created on: Nov 10, 2014 + * Author: parallels + */ + +#include <cmath> + +// Draw a line between two points at a specified rate in +// pixels per buffer sample. Indicate maximum available space. +// Returns space used +int renderLine(float x1, float y1, float x2, float y2, float speed, + float *buffer, int maxLength) { + // Figure out length of line and therefore how many samples + // are needed to represent it based on the speed (rounded to nearest int) + float totalLineLength = sqrtf((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); + int samplesNeeded = floorf(totalLineLength / speed + 0.5); + + // Now render into the buffer + int length = 0; + float scaleFactor = 1.0f / samplesNeeded; + for(int n = 0; n < samplesNeeded; n++) { + if(length >= maxLength - 1) + return length; + // X coordinate + *buffer++ = x1 + (float)n * scaleFactor * (x2 - x1); + // Y coordinate + *buffer++ = y1 + (float)n * scaleFactor * (y2 - y1); + length += 2; + } + + return length; +} + +// Draw an arc around a centre point at a specified rate of pixels +// per buffer sample. Indicate maximum available space. +// Returns space used +int renderArc(float x, float y, float radius, float thetaMin, float thetaMax, + float speed, float *buffer, int maxLength) { + // Figure out circumference of arc and therefore how many samples + // are needed to represent it based on the speed (rounded to nearest int) + float circumference = (thetaMax - thetaMin) * radius; + int samplesNeeded = floorf(circumference / speed + 0.5); + + // Now render into the buffer + int length = 0; + float scaleFactor = 1.0f / samplesNeeded; + for(int n = 0; n < samplesNeeded; n++) { + if(length >= maxLength - 1) + return length; + // Get current angle + float theta = thetaMin + (float)n * scaleFactor * (thetaMax - thetaMin); + + // Convert polar to cartesian coordinates + *buffer++ = x + radius * cosf(theta); + *buffer++ = y + radius * sinf(theta); + + length += 2; + } + + return length; +} + +// Draw a single point for a specified number of frames +void renderPoint(float x, float y, float *buffer, float length) { + while(length > 0) { + *buffer++ = x; + *buffer++ = y; + length--; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/10-Instruments/tank_wars/vector_graphics.h Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,18 @@ +/* + * vector_graphics.h + * + * Created on: Nov 10, 2014 + * Author: parallels + */ + +#ifndef VECTOR_GRAPHICS_H_ +#define VECTOR_GRAPHICS_H_ + +int renderLine(float x1, float y1, float x2, float y2, float speed, + float *buffer, int maxLength); +int renderArc(float x, float y, float radius, float thetaMin, float thetaMax, + float speed, float *buffer, int maxLength); +void renderPoint(float x, float y, float *buffer, float length); + + +#endif /* VECTOR_GRAPHICS_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/11-Extras/7segment/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,142 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> + +#define NUM_PINS 12 + +// Breadboard wiring layout: +// 11 10 12 9 8 7 +// [ LED DISP ] +// 1 2 3 6 4 5 + +// Organised by display segments: +// e d . X c g b X X X f a +const int kPins[NUM_PINS] = {P8_07, P8_08, P8_09, P8_10, P8_11, P8_12, + P8_15, P8_16, P8_27, P8_28, P8_29, P8_30}; + +// Indices into the above array: pins 12, 9, 8, 6 +const int kDigits[4] = {9, 8, 7, 3}; + +int gCurrentlyDisplayingDigit = 0; +int gDigitDisplayTime = 0; +const int kDigitMaxDisplayTime = 44; + +int gState = 0; +int gStateCounter = 0; +const int kMaxState = 25; + +// . g f e d c b a +//const unsigned char kBELA[4] = {0x7C, 0x79, 0x38, 0x77}; +const unsigned char kBELA[4] = {0x7C, 0x7B, 0x38, 0x5F}; +const unsigned char kPerimeter[6] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20}; + +int gCharacterToDisplay[4] = {0, 0, 0, 0}; + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + +bool setup(BelaContext *context, void *userData) +{ + // This project makes the assumption that the audio and digital + // sample rates are the same. But check it to be sure! + if(context->audioFrames != context->digitalFrames) { + rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n"); + return false; + } + + for(int i = 0; i < NUM_PINS; i++) { + pinMode(context, 0, kPins[i], OUTPUT); + } + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + // Check for rotation between digits + if(--gDigitDisplayTime <= 0) { + gCurrentlyDisplayingDigit = (gCurrentlyDisplayingDigit + 1) % 4; + gDigitDisplayTime = kDigitMaxDisplayTime; + } + + // Write the currently displaying digit low and the rest high + for(int i = 0; i < 4; i++) + digitalWriteOnce(context, n, kPins[kDigits[i]], HIGH); + digitalWriteOnce(context, n, kPins[kDigits[gCurrentlyDisplayingDigit]], LOW); + + // Write the digit to the other outputs + digitalWriteOnce(context, n, kPins[11], + gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x01); // a + digitalWriteOnce(context, n, kPins[6], + gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x02); // b + digitalWriteOnce(context, n, kPins[4], + gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x04); // c + digitalWriteOnce(context, n, kPins[1], + gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x08); // d + digitalWriteOnce(context, n, kPins[0], + gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x10); // e + digitalWriteOnce(context, n, kPins[10], + gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x20); // f + digitalWriteOnce(context, n, kPins[5], + gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x40); // g + digitalWriteOnce(context, n, kPins[2], + gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x80); // . + + // Check for changing state + if(--gStateCounter <= 0) { + gState = (gState + 1) % kMaxState; + if(gState != (kMaxState - 1)) { + for(int i = 0; i < 4; i++) + gCharacterToDisplay[i] = 1 << (gState % 6); + gStateCounter = 2000; + } + else { + for(int i = 0; i < 4; i++) + gCharacterToDisplay[i] = kBELA[i]; + gStateCounter = 50000; + } + } + } +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/11-Extras/cape-test/main.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,97 @@ +/* + * main.cpp + * + * Created on: Oct 24, 2014 + * Author: parallels + */ +#include <unistd.h> +#include <iostream> +#include <cstdlib> +#include <libgen.h> +#include <signal.h> +#include <getopt.h> +#include <Bela.h> + +using namespace std; + +// Handle Ctrl-C by requesting that the audio rendering stop +void interrupt_handler(int var) +{ + gShouldStop = true; +} + +// Print usage information +void usage(const char * processName) +{ + cerr << "Usage: " << processName << " [options]" << endl; + + Bela_usage(); + + cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; + cerr << " --help [-h]: Print this menu\n"; +} + +int main(int argc, char *argv[]) +{ + BelaInitSettings settings; // Standard audio settings + float frequency = 440.0; // Frequency of oscillator + + struct option customOptions[] = + { + {"help", 0, NULL, 'h'}, + {"frequency", 1, NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + // Set default settings + Bela_defaultSettings(&settings); + + // Parse command-line arguments + while (1) { + int c; + if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) + break; + switch (c) { + case 'h': + usage(basename(argv[0])); + exit(0); + case 'f': + frequency = atof(optarg); + break; + case '?': + default: + usage(basename(argv[0])); + exit(1); + } + } + + // Initialise the PRU audio device + if(Bela_initAudio(&settings, &frequency) != 0) { + cout << "Error: unable to initialise audio" << endl; + return -1; + } + + // Start the audio device running + if(Bela_startAudio()) { + cout << "Error: unable to start real-time audio" << endl; + return -1; + } + + // Set up interrupt handler to catch Control-C and SIGTERM + signal(SIGINT, interrupt_handler); + signal(SIGTERM, interrupt_handler); + + // Run until told to stop + while(!gShouldStop) { + usleep(100000); + } + + // Stop the audio device + Bela_stopAudio(); + + // Clean up any resources allocated for audio + Bela_cleanupAudio(); + + // All done! + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/11-Extras/cape-test/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,279 @@ +/* + * render.cpp + * + * Created on: Oct 24, 2014 + * Author: parallels + */ + + +#include <Bela.h> +#include <cmath> + +#define ANALOG_LOW (2048.0 / 65536.0) +#define ANALOG_HIGH (50000.0 / 65536.0) + +const int gDACPinOrder[] = {6, 4, 2, 0, 1, 3, 5, 7}; + +enum { + kStateTestingAudioLeft = 0, + kStateTestingAudioRight, + kStateTestingAudioDone +}; + +uint64_t gLastErrorFrame = 0; +uint32_t gEnvelopeSampleCount = 0; +float gEnvelopeValueL = 0.5, gEnvelopeValueR = 0.5; +float gEnvelopeDecayRate = 0.9995; +int gEnvelopeLastChannel = 0; + +float gPositivePeakLevels[2] = {0, 0}; +float gNegativePeakLevels[2] = {0, 0}; +float gPeakLevelDecayRate = 0.999; +const float gPeakLevelLowThreshold = 0.02; +const float gPeakLevelHighThreshold = 0.2; +const float gDCOffsetThreshold = 0.1; +int gAudioTestState = kStateTestingAudioLeft; +int gAudioTestStateSampleCount = 0; +int gAudioTestSuccessCounter = 0; +const int gAudioTestSuccessCounterThreshold = 64; +const int gAudioTestStateSampleThreshold = 16384; + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + +bool setup(BelaContext *context, void *userData) +{ + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + static float phase = 0.0; + static int sampleCounter = 0; + static int invertChannel = 0; + float frequency = 0; + + // Play a sine wave on the audio output + for(unsigned int n = 0; n < context->audioFrames; n++) { + + // Peak detection on the audio inputs, with offset to catch + // DC errors + for(int ch = 0; ch < 2; ch++) { + if(context->audioIn[2*n + ch] > gPositivePeakLevels[ch]) + gPositivePeakLevels[ch] = context->audioIn[2*n + ch]; + gPositivePeakLevels[ch] += 0.1; + gPositivePeakLevels[ch] *= gPeakLevelDecayRate; + gPositivePeakLevels[ch] -= 0.1; + if(context->audioIn[2*n + ch] < gNegativePeakLevels[ch]) + gNegativePeakLevels[ch] = context->audioIn[2*n + ch]; + gNegativePeakLevels[ch] -= 0.1; + gNegativePeakLevels[ch] *= gPeakLevelDecayRate; + gNegativePeakLevels[ch] += 0.1; + } + + if(gAudioTestState == kStateTestingAudioLeft) { + context->audioOut[2*n] = 0.2 * sinf(phase); + context->audioOut[2*n + 1] = 0; + + frequency = 3000.0; + phase += 2.0 * M_PI * frequency / 44100.0; + if(phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + + gAudioTestStateSampleCount++; + if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) { + // Check if we have the expected input: signal on the left but not + // on the right. Also check that there is not too much DC offset on the + // inactive signal + if((gPositivePeakLevels[0] - gNegativePeakLevels[0]) >= gPeakLevelHighThreshold + && (gPositivePeakLevels[1] - gNegativePeakLevels[1]) <= gPeakLevelLowThreshold && + fabsf(gPositivePeakLevels[1]) < gDCOffsetThreshold && + fabsf(gNegativePeakLevels[1]) < gDCOffsetThreshold) { + // Successful test: increment counter + gAudioTestSuccessCounter++; + if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) { + gAudioTestState = kStateTestingAudioRight; + gAudioTestStateSampleCount = 0; + gAudioTestSuccessCounter = 0; + } + + } + else { + if(!((context->audioFramesElapsed + n) % 22050)) { + // Debugging print messages + if((gPositivePeakLevels[0] - gNegativePeakLevels[0]) < gPeakLevelHighThreshold) + rt_printf("Left Audio In FAIL: insufficient signal: %f\n", + gPositivePeakLevels[0] - gNegativePeakLevels[0]); + else if(gPositivePeakLevels[1] - gNegativePeakLevels[1] > gPeakLevelLowThreshold) + rt_printf("Right Audio In FAIL: signal present when it should not be: %f\n", + gPositivePeakLevels[1] - gNegativePeakLevels[1]); + else if(fabsf(gPositivePeakLevels[1]) >= gDCOffsetThreshold || + fabsf(gNegativePeakLevels[1]) >= gDCOffsetThreshold) + rt_printf("Right Audio In FAIL: DC offset: (%f, %f)\n", + gPositivePeakLevels[1], gNegativePeakLevels[1]); + } + gAudioTestSuccessCounter--; + if(gAudioTestSuccessCounter <= 0) + gAudioTestSuccessCounter = 0; + } + } + } + else if(gAudioTestState == kStateTestingAudioRight) { + context->audioOut[2*n] = 0; + context->audioOut[2*n + 1] = 0.2 * sinf(phase); + + frequency = 3000.0; + phase += 2.0 * M_PI * frequency / 44100.0; + if(phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + + gAudioTestStateSampleCount++; + if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) { + // Check if we have the expected input: signal on the left but not + // on the right + if((gPositivePeakLevels[1] - gNegativePeakLevels[1]) >= gPeakLevelHighThreshold + && (gPositivePeakLevels[0] - gNegativePeakLevels[0]) <= gPeakLevelLowThreshold && + fabsf(gPositivePeakLevels[0]) < gDCOffsetThreshold && + fabsf(gNegativePeakLevels[0]) < gDCOffsetThreshold) { + // Successful test: increment counter + gAudioTestSuccessCounter++; + if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) { + gAudioTestSuccessCounter = 0; + gAudioTestStateSampleCount = 0; + gAudioTestState = kStateTestingAudioDone; + } + } + else { + if(!((context->audioFramesElapsed + n) % 22050)) { + // Debugging print messages + if((gPositivePeakLevels[1] - gNegativePeakLevels[1]) < gPeakLevelHighThreshold) + rt_printf("Right Audio In FAIL: insufficient signal: %f\n", + gPositivePeakLevels[1] - gNegativePeakLevels[1]); + else if(gPositivePeakLevels[0] - gNegativePeakLevels[0] > gPeakLevelLowThreshold) + rt_printf("Left Audio In FAIL: signal present when it should not be: %f\n", + gPositivePeakLevels[0] - gNegativePeakLevels[0]); + else if(fabsf(gPositivePeakLevels[0]) >= gDCOffsetThreshold || + fabsf(gNegativePeakLevels[0]) >= gDCOffsetThreshold) + rt_printf("Left Audio In FAIL: DC offset: (%f, %f)\n", + gPositivePeakLevels[0], gNegativePeakLevels[0]); + } + gAudioTestSuccessCounter--; + if(gAudioTestSuccessCounter <= 0) + gAudioTestSuccessCounter = 0; + } + } + } + else { + // Audio input testing finished. Play tones depending on status of + // analog testing + context->audioOut[2*n] = gEnvelopeValueL * sinf(phase); + context->audioOut[2*n + 1] = gEnvelopeValueR * sinf(phase); + + // If one second has gone by with no error, play one sound, else + // play another + if(context->audioFramesElapsed + n - gLastErrorFrame > 44100) { + gEnvelopeValueL *= gEnvelopeDecayRate; + gEnvelopeValueR *= gEnvelopeDecayRate; + gEnvelopeSampleCount++; + if(gEnvelopeSampleCount > 22050) { + if(gEnvelopeLastChannel == 0) + gEnvelopeValueR = 0.5; + else + gEnvelopeValueL = 0.5; + gEnvelopeLastChannel = !gEnvelopeLastChannel; + gEnvelopeSampleCount = 0; + } + frequency = 880.0; + } + else { + gEnvelopeValueL = gEnvelopeValueR = 0.5; + gEnvelopeLastChannel = 0; + frequency = 220.0; + } + + phase += 2.0 * M_PI * frequency / 44100.0; + if(phase >= 2.0 * M_PI) + phase -= 2.0 * M_PI; + } + } + + for(unsigned int n = 0; n < context->analogFrames; n++) { + // Change outputs every 512 samples + if(sampleCounter < 512) { + for(int k = 0; k < 8; k++) { + if(k == invertChannel) + context->analogOut[n*8 + gDACPinOrder[k]] = ANALOG_HIGH; + else + context->analogOut[n*8 + gDACPinOrder[k]] = 0; + } + } + else { + for(int k = 0; k < 8; k++) { + if(k == invertChannel) + context->analogOut[n*8 + gDACPinOrder[k]] = 0; + else + context->analogOut[n*8 + gDACPinOrder[k]] = ANALOG_HIGH; + } + } + + // Read after 256 samples: input should be low + if(sampleCounter == 256) { + for(int k = 0; k < 8; k++) { + if(k == invertChannel) { + if(context->analogIn[n*8 + k] < ANALOG_HIGH) { + rt_printf("FAIL [output %d, input %d] -- output HIGH input %f (inverted)\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]); + gLastErrorFrame = context->audioFramesElapsed + n; + } + } + else { + if(context->analogIn[n*8 + k] > ANALOG_LOW) { + rt_printf("FAIL [output %d, input %d] -- output LOW --> input %f\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]); + gLastErrorFrame = context->audioFramesElapsed + n; + } + } + } + } + else if(sampleCounter == 768) { + for(int k = 0; k < 8; k++) { + if(k == invertChannel) { + if(context->analogIn[n*8 + k] > ANALOG_LOW) { + rt_printf("FAIL [output %d, input %d] -- output LOW input %f (inverted)\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]); + gLastErrorFrame = context->audioFramesElapsed + n; + } + } + else { + if(context->analogIn[n*8 + k] < ANALOG_HIGH) { + rt_printf("FAIL [output %d, input %d] -- output HIGH input %f\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]); + gLastErrorFrame = context->audioFramesElapsed + n; + } + } + } + } + + if(++sampleCounter >= 1024) { + sampleCounter = 0; + invertChannel++; + if(invertChannel >= 8) + invertChannel = 0; + } + } +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/11-Extras/gpioAnalogLoopbackTest/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,209 @@ +#include <Bela.h> +#include <cmath> +#include <rtdk.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <stats.hpp> +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + + +// digital inputs can be changed at will (as they are all being processed at the same time) +// analog channels must be as per below +int gAnalogOutCh = 1; +int gDigitalOutCh = 2; +int gDigitalInACh = 0; +int gDigitalInDCh = 3; +int gAnalogOutLoopDelay; +int gDigitalOutLoopDelay; +bool setup(BelaContext *context, void *userData) +{ + rt_printf("For this test you need the following connections:\n" + "analog%d out->digital%d in, analog%d out->analog%d in, " + "digital%d out -> digital%d in, digital%d out-> analog%d in\n", + gAnalogOutCh, gDigitalInACh, gAnalogOutCh, 0, gDigitalOutCh, gDigitalInDCh, gDigitalOutCh, 0); + rt_printf("Running test with %d analog channels and a buffer size of %d\n", + context->analogChannels, context->audioFrames); + + for(unsigned int n = 0; n < context->digitalFrames; n++){ + pinMode(context, n, gDigitalInACh, INPUT); + pinMode(context, n, gDigitalInDCh, INPUT); + pinMode(context, n, gDigitalOutCh, OUTPUT); + } + switch (context->analogChannels){ + case 2: + gAnalogOutLoopDelay = context->audioFrames*2 + 3; + gDigitalOutLoopDelay = context->audioFrames*2 + 2; + break; + case 4: + gAnalogOutLoopDelay = context->audioFrames*2 + 3; + gDigitalOutLoopDelay = context->audioFrames*2 + 2; + break; + case 8: + gAnalogOutLoopDelay = context->audioFrames + 3; + gDigitalOutLoopDelay = context->audioFrames + 1; + break; + default: + exit(2); + } + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numAnalogFrames +// will be 0. + +const int patternLength = 31; +static int anaErrorCount = 0; +static int digErrorCount = 0; +void render(BelaContext *context, void *userData) +{ + static bool writePattern[patternLength] = { + 0,1,0,1,0,0,1,1, + 0,0,0,1,1,1,0,0, + 1,1,1,1,0,0,0,0, + 1,1,1,1,1,0,0}; +// for(int n = 0; n < patternLength; n++){ +// writePattern[n]=1; +// } + static int inPointer = 0; + static int outPointer = 0; + static int digitalOutPointer = 0; + static int digitalInPointer = 0; + static int analogOut = 1; + /** Checking offset between analog and digital + * how it should be : + * The PRU loop does the following (the loop runs at 88.2kHz): + * - Read/write audio sample (once for the left channel, once for the right channel) + * - Write DAC 0 or 0/2 or 0/2/4/6 + * - Read ADC 0 or 0/2 or 0/2/4/6, 2 samples (@176.4) older than NOW + * - /During/ the line above, every two loops we also Read/Write GPIO, + * therefore reading on ADC 0/2/4/6 a value that is being output from GPIO will lead to undefined results + * - Write DAC 1 or 1/3 or 1/3/5/7 + * - Read ADC 1 or 1/3 or 1/3/5/7, 2 samples (@176.4) older than NOW + */ + if(1) + for(unsigned int n = 0; n < context->audioFrames; n++){ + static bool analog0In = false; + static bool digitalAIn = false; + static int count = 0; + bool doReadWrite = context->analogChannels<=4 ? true : ((context->analogChannels == 8) && (n&1)==0); + if(doReadWrite){ + digitalAIn = digitalRead(context, n, gDigitalInACh); + switch(context->analogChannels){ + case 8: + analog0In = analogRead(context, n/2, 0) > 0.5; + analogWrite(context, n/2, analogOut, writePattern[outPointer]); + break; + case 4: + analog0In = analogRead(context, n, 0) > 0.5; + analogWrite(context, n, analogOut, writePattern[outPointer]); + break; + case 2: + analog0In = analogRead(context, n * 2 + 1, 0) > 0.5; + analogWrite(context, 2 * n, analogOut, writePattern[outPointer]); + analogWrite(context, 2 * n + 1, analogOut, writePattern[outPointer]); + break; + } + gAnalogOutLoopDelay--; + outPointer++; + if(gAnalogOutLoopDelay <= 0){ + if(++inPointer == patternLength){ + inPointer = 0; + } + } + } + bool expectedIn = writePattern[inPointer]; + if(gAnalogOutLoopDelay <= 0 && doReadWrite == true){ + if(analog0In != expectedIn || digitalAIn != expectedIn){ + rt_printf("expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n", + expectedIn, analog0In, digitalAIn, inPointer, gAnalogOutLoopDelay, count); + anaErrorCount++; + } + } + count++; + if(analog0In != digitalAIn){ // at any time the analog and digital in should be the same + rt_printf("ana %d_%d %d,\n", analog0In, digitalAIn, n); + } + if(outPointer == patternLength){ + outPointer = 0; + } + } + if(1) + for(unsigned int n = 0; n < context->audioFrames; n++){ + static int count = 0; + static bool analog1In = false; + static bool digitalDIn = false; +/* we need to remember the pastAnalog1In because + * reading GPIO takes place before writing to it, therefore + * when reading a GPIOout, the GPIOin samples will always be one sample late + */ + bool doReadWrite = false; + static bool pastAnalog1In = false; + digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); + if(context->analogChannels == 8){ + if((n&1) == 0){ //do it every other sample + pastAnalog1In = analogRead(context, n/2, 1) > 0.5; + digitalDIn = digitalRead(context, n, gDigitalInDCh); + doReadWrite = true; + } + } + if(context->analogChannels == 4){ + pastAnalog1In = analogRead(context, n, 1) > 0.5; + digitalDIn = digitalRead(context, n, gDigitalInDCh); + digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); + doReadWrite = true; + } + if(context->analogChannels == 2){ + pastAnalog1In = analogRead(context, n * 2, 1) > 0.5; + digitalDIn = digitalRead(context, n, gDigitalInDCh); + digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); + doReadWrite = true; + } + bool expectedDigitalIn = writePattern[digitalInPointer]; + if(doReadWrite == true){ + gDigitalOutLoopDelay--; + if(gDigitalOutLoopDelay <= 0){ + if(expectedDigitalIn != pastAnalog1In || expectedDigitalIn != digitalDIn){ + rt_printf("D expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n", + expectedDigitalIn, pastAnalog1In, digitalDIn, inPointer, gDigitalOutLoopDelay, count); + digErrorCount++; + } + if(++digitalInPointer == patternLength){ + digitalInPointer = 0; + } + } + pastAnalog1In = analog1In; + if(++digitalOutPointer == patternLength){ + digitalOutPointer = 0; + } + } + count++; + } + if(context->audioFramesElapsed > 30000){ + gShouldStop = true; + } +} + + +void cleanup(BelaContext *context, void *userData) +{ + if(anaErrorCount == 0 && digErrorCount == 0){ + rt_printf("Test was succesful with %d analog channels and a buffer size of %d\n", context->analogChannels, context->audioFrames); + } else { + rt_printf("------------------------\n%danalog %ddigital errors over %dsamples while running test with ", + anaErrorCount, digErrorCount, context->audioFramesElapsed); + rt_printf("%d analog channels and a buffer size of %d \n\n\n", + context->analogChannels, context->audioFrames); + exit(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/11-Extras/stepper/render.cpp Mon Jun 20 16:20:38 2016 +0100 @@ -0,0 +1,166 @@ +/* + ____ _____ _ _ +| __ )| ____| | / \ +| _ \| _| | | / _ \ +| |_) | |___| |___ / ___ \ +|____/|_____|_____/_/ \_\ + +The platform for ultra-low latency audio and sensor processing + +http://bela.io + +A project of the Augmented Instruments Laboratory within the +Centre for Digital Music at Queen Mary University of London. +http://www.eecs.qmul.ac.uk/~andrewm + +(c) 2016 Augmented Instruments Laboratory: Andrew McPherson, + Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack, + Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved. + +The Bela software is distributed under the GNU Lesser General Public License +(LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt +*/ + + +#include <Bela.h> + +const int kStepLengthSlow = 1000; +const int kStepLengthFast = 500; + +int gStepLengthSamples = kStepLengthSlow; + +const int gPinA1 = P8_27; +const int gPinA2 = P8_28; +const int gPinB1 = P8_29; +const int gPinB2 = P8_30; +const int gPinServo = P9_16; + +int gStepCounter = 0; +int gPhase = 0; + +int gServoCounter = 0; + + +enum { + kStateMoveRight1 = 0, + kStateMoveLeft1, + kStateMoveRight2, + kStateMoveLeft2, + kStateMoveRight3, + kStateMoveLeft3, + kStateSpin, + kStateMax +}; + +int gState = 0; +int gStateCounter = 0; + +// setup() is called once before the audio rendering starts. +// Use it to perform any initialisation and allocation which is dependent +// on the period size or sample rate. +// +// userData holds an opaque pointer to a data structure that was passed +// in from the call to initAudio(). +// +// Return true on success; returning false halts the program. + +bool setup(BelaContext *context, void *userData) +{ + // This project makes the assumption that the audio and digital + // sample rates are the same. But check it to be sure! + if(context->audioFrames != context->digitalFrames) { + rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n"); + return false; + } + + pinMode(context, 0, gPinA1, OUTPUT); + pinMode(context, 0, gPinA2, OUTPUT); + pinMode(context, 0, gPinB1, OUTPUT); + pinMode(context, 0, gPinB2, OUTPUT); + pinMode(context, 0, gPinServo, OUTPUT); + + return true; +} + +// render() is called regularly at the highest priority by the audio engine. +// Input and output are given from the audio hardware and the other +// ADCs and DACs (if available). If only audio is available, numMatrixFrames +// will be 0. + +void render(BelaContext *context, void *userData) +{ + for(unsigned int n = 0; n < context->audioFrames; n++) { + if(gPhase == 0 || gPhase == 1) { + digitalWriteOnce(context, n, gPinB1, HIGH); + digitalWriteOnce(context, n, gPinB2, LOW); + } + else { + digitalWriteOnce(context, n, gPinB1, LOW); + digitalWriteOnce(context, n, gPinB2, HIGH); + } + + if(gPhase == 1 || gPhase == 2) { + digitalWriteOnce(context, n, gPinA1, HIGH); + digitalWriteOnce(context, n, gPinA2, LOW); + } + else { + digitalWriteOnce(context, n, gPinA1, LOW); + digitalWriteOnce(context, n, gPinA2, HIGH); + } + + if(--gServoCounter > 0) + digitalWriteOnce(context, n, gPinServo, HIGH); + else + digitalWriteOnce(context, n, gPinServo, LOW); + + if(++gStepCounter >= gStepLengthSamples) { + gStateCounter++; + + switch(gState) { + case kStateMoveRight1: + case kStateMoveRight2: + case kStateMoveRight3: + gPhase = (gPhase + 1) & 3; + break; + case kStateMoveLeft1: + case kStateMoveLeft2: + case kStateMoveLeft3: + gPhase = (gPhase + 3) & 3; + break; + case kStateSpin: + gPhase = (gPhase + 1) & 3; + break; + } + + if(gState == kStateSpin) { + if(gStateCounter >= 48) { + gStateCounter = 0; + gState = 0; + gStepLengthSamples = kStepLengthSlow; + } + } + else { + if(gStateCounter >= 16) { + gStateCounter = 0; + gState++; + if(gState & 1) + gServoCounter = 120; + else + gServoCounter = 80; + if(gState == kStateSpin) + gStepLengthSamples = kStepLengthFast; + } + } + + gStepCounter = 0; + } + } +} + +// cleanup() is called once at the end, after the audio has stopped. +// Release any resources that were allocated in setup(). + +void cleanup(BelaContext *context, void *userData) +{ + +}
--- a/examples/7segment/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - - -#include <Bela.h> - -#define NUM_PINS 12 - -// Breadboard wiring layout: -// 11 10 12 9 8 7 -// [ LED DISP ] -// 1 2 3 6 4 5 - -// Organised by display segments: -// e d . X c g b X X X f a -const int kPins[NUM_PINS] = {P8_07, P8_08, P8_09, P8_10, P8_11, P8_12, - P8_15, P8_16, P8_27, P8_28, P8_29, P8_30}; - -// Indices into the above array: pins 12, 9, 8, 6 -const int kDigits[4] = {9, 8, 7, 3}; - -int gCurrentlyDisplayingDigit = 0; -int gDigitDisplayTime = 0; -const int kDigitMaxDisplayTime = 44; - -int gState = 0; -int gStateCounter = 0; -const int kMaxState = 25; - -// . g f e d c b a -//const unsigned char kBELA[4] = {0x7C, 0x79, 0x38, 0x77}; -const unsigned char kBELA[4] = {0x7C, 0x7B, 0x38, 0x5F}; -const unsigned char kPerimeter[6] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20}; - -int gCharacterToDisplay[4] = {0, 0, 0, 0}; - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - // This project makes the assumption that the audio and digital - // sample rates are the same. But check it to be sure! - if(context->audioFrames != context->digitalFrames) { - rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n"); - return false; - } - - for(int i = 0; i < NUM_PINS; i++) { - pinMode(context, 0, kPins[i], OUTPUT); - } - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - // Check for rotation between digits - if(--gDigitDisplayTime <= 0) { - gCurrentlyDisplayingDigit = (gCurrentlyDisplayingDigit + 1) % 4; - gDigitDisplayTime = kDigitMaxDisplayTime; - } - - // Write the currently displaying digit low and the rest high - for(int i = 0; i < 4; i++) - digitalWriteOnce(context, n, kPins[kDigits[i]], HIGH); - digitalWriteOnce(context, n, kPins[kDigits[gCurrentlyDisplayingDigit]], LOW); - - // Write the digit to the other outputs - digitalWriteOnce(context, n, kPins[11], - gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x01); // a - digitalWriteOnce(context, n, kPins[6], - gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x02); // b - digitalWriteOnce(context, n, kPins[4], - gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x04); // c - digitalWriteOnce(context, n, kPins[1], - gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x08); // d - digitalWriteOnce(context, n, kPins[0], - gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x10); // e - digitalWriteOnce(context, n, kPins[10], - gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x20); // f - digitalWriteOnce(context, n, kPins[5], - gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x40); // g - digitalWriteOnce(context, n, kPins[2], - gCharacterToDisplay[gCurrentlyDisplayingDigit] & 0x80); // . - - // Check for changing state - if(--gStateCounter <= 0) { - gState = (gState + 1) % kMaxState; - if(gState != (kMaxState - 1)) { - for(int i = 0; i < 4; i++) - gCharacterToDisplay[i] = 1 << (gState % 6); - gStateCounter = 2000; - } - else { - for(int i = 0; i < 4; i++) - gCharacterToDisplay[i] = kBELA[i]; - gStateCounter = 50000; - } - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/airharp/Junction.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * - * Excitation Junction for two waveguides - * - * Christian Heinrichs 04/2015 - * - */ - -#include "Junction.h" -#include "../include/Utilities.h" - -Junction::Junction() { - - setFrequency(440); - _dt = 1.0/44100.0; - - // initialize variables - for(int i=0;i<WG_BUFFER_SIZE;i++) { - _buffer_l[i] = 0; - _buffer_r[i] = 0; - } - _excitation = 0; - _lastPlectrumDisplacement = 0; - _readPtr = 0; - -} - -void Junction::update(float excitation, float left, float right) { - - // 1. advance delay buffer read pointer - - if(++_readPtr>=WG_BUFFER_SIZE) - _readPtr=0; - - // 2. add excitation sample into buffer - - _buffer_l[(_readPtr+_delay_l+WG_BUFFER_SIZE)%WG_BUFFER_SIZE] = excitation; - _buffer_r[(_readPtr+_delay_r+WG_BUFFER_SIZE)%WG_BUFFER_SIZE] = excitation; - - // 3. feed right input to left output and vice versa - - _buffer_l[_readPtr] += right; - _buffer_r[_readPtr] += left; - - // 4. store excitation value for later use - _excitation = excitation; - -} - -float Junction::getOutput(int direction) { - - if(direction = 0) - return _buffer_l[_readPtr]; - else - return _buffer_r[_readPtr]; - -} - -float Junction::getExcitationDisplacement() { - - // string displacement and excitation force - // use delayed value to account for excitation position - float in = _buffer_l[(_readPtr+_delay_l+WG_BUFFER_SIZE)%WG_BUFFER_SIZE] + _excitation; - - // integrate total force - float out = 0.00001 * in + 0.99999 * _lastPlectrumDisplacement; - - // store variable for next iteration - _lastPlectrumDisplacement = out; - - // multiply by delta time - return out * _dt; - -} - -void Junction::setPluckPosition(float pluckPos){ - - pluckPos = constrain(pluckPos,0,1); - _delay_l = pluckPos * _periodInSamples; - _delay_r = (1-pluckPos) * _periodInSamples; - -} - -void Junction::setPeriod(float period) { - - _periodInMilliseconds = period; - -} - -void Junction::setFrequency(float frequency) { - - _periodInMilliseconds = 1000.0/frequency; - _periodInSamples = (int)(_periodInMilliseconds * 44.1); - -}
--- a/examples/airharp/Junction.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * - * Excitation Junction for two waveguides - * - * Christian Heinrichs 04/2015 - * - */ - -#ifndef JUNCTION_H_ -#define JUNCTION_H_ - -#include <cmath> - -#ifndef WG_BUFFER_SIZE -#define WG_BUFFER_SIZE 4096 -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846264338 -#endif - -class Junction -{ - -public: - - Junction(); - void setup(); - void update(float excitation, float left, float right); - float getOutput(int direction); - float getExcitationDisplacement(); - void setFrequency(float frequency); - void setPeriod(float periodInMs); - void setPluckPosition(float pluckPos); - -private: - - double _dt; - float _periodInMilliseconds; - int _periodInSamples; - - int _delay_l; - int _delay_r; - - float _buffer_l[WG_BUFFER_SIZE]; - float _buffer_r[WG_BUFFER_SIZE]; - int _readPtr; - - float _excitation; - float _lastPlectrumDisplacement; - -}; - -#endif
--- a/examples/airharp/MassSpringDamper.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * - * Simple 1-Dimensional Mass Spring Damper - * - * Christian Heinrichs 04/2015 - * - */ - -#include "MassSpringDamper.h" - -MassSpringDamper::MassSpringDamper(float mass, float spring, float damp) { - - _dt = 1.0/44100.0; - _mass = mass; - _spring = spring; - _damp = damp; - _position = 0; - _velocity = 0; - -} - -void MassSpringDamper::setup() { - -} - -double MassSpringDamper::update(float inForce) { - - // 1. calculate spring/damper forces using current position and velocity - - double out = (_position * (double)_spring * -1) + (_velocity * (double)_damp * -1); - - // 2. apply external force - - out += inForce; - - // 3. derive acceleration (a = f/m) - - out /= (double)_mass; - - // 4. derive velocity (v = a*dt) - - out *= _dt; - - // 5. apply previous velocity - - out += _velocity; - - // 6. save current velocity state for next iteration - - _velocity = out; - - // 7. derive new position (x[n] = x[n-1] + v[n]) and save for next iteration - - out += _position; - _position = out; - - return out; - -}
--- a/examples/airharp/MassSpringDamper.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * - * Simple 1-Dimensional Mass Spring Damper - * - * Christian Heinrichs 04/2015 - * - */ - -#ifndef MASSSPRINGDAMPER_H_ -#define MASSSPRINGDAMPER_H_ - -class MassSpringDamper -{ - -public: - - MassSpringDamper(float mass, float spring, float damp); - void setup(); - double update(float inForce); - -private: - - double _dt; - float _mass; - float _spring; - float _damp; - double _position; - double _velocity; - -}; - -#endif
--- a/examples/airharp/Plectrum.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * - * Plectrum model for touching and plucking strings - * - * Christian Heinrichs 04/2015 - * - * [inspired by E. Berdahl's pluck~ abstraction for the FireFader] - * - */ - -#include "Plectrum.h" - -#include "../include/Utilities.h" -#include <cmath> -#include <stdio.h> -#include <cstdlib> - -Plectrum::Plectrum() { - - _contact = 0; - _lastDistance = 0; - -} - -void Plectrum::setup(float spring, float damp, float hyst) { - - _spring = spring; - _damp = damp; - _hyst = hyst; - -} - -float Plectrum::update(float position, float stringPosition) { - - float distance = position - stringPosition; - - // Calculate spring/damp forces based on distance to string - - float springOut = distance * _spring; - - float dampOut = (distance - _lastDistance) * 44100; - - float out = springOut+dampOut; - - // If distance crosses zero, enable contact - - if((distance>0 && _lastDistance<=0)||(distance<0 && _lastDistance>=0)) - _contact = 1; - - // If distance exceeds hysteresis threshold, jump to zero (i.e. 'pluck') - - if(fabs(distance)>_hyst) - _contact = 0; - - // FIXME: contact doesn't switch back to zero if distance goes back in original direction - - _lastDistance = distance; - - return out * _contact; - -}
--- a/examples/airharp/Plectrum.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * - * Plectrum model for touching and plucking strings - * - * [inspired by E. Berdahl's pluck~ abstraction for the FireFader] - * - */ - -#ifndef PLECTRUM_H_ -#define PLECTRUM_H_ - -class Plectrum -{ - -public: - - Plectrum(); - void setup(float spring, float damp, float hyst); - float update(float position, float stringPosition); - -private: - - double _dt; - float _spring; - float _damp; - double _position; - double _velocity; - float _hyst; - float _lastDistance; - int _contact; - -}; - -#endif -
--- a/examples/airharp/String.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * - * 1-D string consisting of two waveguides and junction - * - * Christian Heinrichs 04/2015 - * - */ - -#include "String.h" -#include "Junction.h" -#include "Waveguide.h" - -#include "../include/Utilities.h" -#include <rtdk.h> -#include <cmath> -#include <stdio.h> -#include <cstdlib> - -String::String(){ - - wg_l = Waveguide(); - wg_r = Waveguide(); - junction = Junction(); - - junction.setPluckPosition(0.5); - - _previous_l = 0; - _previous_r = 0; - -} - -float String::update(float in) { - - // 1. send excitation signal and previous waveguide outputs into junction - - junction.update(in,_previous_l,_previous_r); - - // 2. save new waveguide outputs for next iteration - - _previous_l = wg_l.update(junction.getOutput(0)); - _previous_r = wg_r.update(junction.getOutput(1)); - - // 3. use right waveguide as output - - //rt_printf("BANANA %f ",_readPtr); - //rt_printf("%f\n",_previous_r); - - return _previous_r; -} - -float String::getPlectrumDisplacement() { - - return junction.getExcitationDisplacement(); - -} - -void String::setPluckPosition(float pluckPos){ - - junction.setPluckPosition(pluckPos); - -} - -void String::setGlobalPosition(float pos) { - - _globalPosition = pos; - -} - -float String::getGlobalPosition() { - - return _globalPosition; - -} - -void String::setMidinote(float midinote) { - - float frequency = 440.0f*(float)powf(2,(midinote-57)/12.0f); - - junction.setFrequency(frequency); - wg_l.setFrequency(frequency); - wg_r.setFrequency(frequency); - -} - -void String::setFrequency(float frequency) { - - junction.setFrequency(frequency); - wg_l.setFrequency(frequency); - wg_r.setFrequency(frequency); - -}
--- a/examples/airharp/String.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * - * 1-D string consisting of two waveguides and junction - * - * Christian Heinrichs 04/2015 - * - */ - -#ifndef STRING_H_ -#define STRING_H_ - -#include <cmath> -#include "Junction.h" -#include "Waveguide.h" - -class String -{ - -public: - - String(); - float update(float in); - - float getPlectrumDisplacement(); - void setMidinote(float midinote); - void setFrequency(float frequency); - void setPeriod(float periodInMs); - void setPluckPosition(float pluckPos); - void setGlobalPosition(float pos); - float getGlobalPosition(); - -private: - - float _previous_l; - float _previous_r; - - float _globalPosition; - - Waveguide wg_l; - Waveguide wg_r; - Junction junction; - -}; - -#endif
--- a/examples/airharp/Waveguide.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * - * Simple 1-Dimensional Waveguide - * - */ - -#include "Waveguide.h" -#include "../include/Utilities.h" -#include <rtdk.h> -#include <cmath> -#include <stdio.h> -#include <cstdlib> - -#define DECAY 0.995//0.999 -#define DAMPING 0.01//0.05 - -// TODO: make damping and decay parametrisable - -Waveguide::Waveguide() { - - // initialize variables - a1_lp = 0; - a2_lp = 0; - b0_lp = 0; - b1_lp = 0; - b2_lp = 0; - _dt = 1.0/44100.0; - setFrequency(440); - updateFilterCoeffs(8000); - _filterReadPtr=0; - for(int i=0;i<FILTER_BUFFER_SIZE;i++) { - _filterBuffer_x[i] = 0; - _filterBuffer_y[i] = 0; - } - for(int i=0;i<WG_BUFFER_SIZE;i++) { - _buffer[i] = 0; - } - _lastX = 0; - _lastY = 0; - _readPtr = 0; - -} - -void Waveguide::setup() { - -} - -float Waveguide::update(float in) { - - // 1. advance delay buffer read pointer - - if(++_readPtr>=WG_BUFFER_SIZE) - _readPtr=0; - - // 2. write input into buffer - - _buffer[_readPtr] = in; - - // 3. read delayed sample from buffer - - float out = _buffer[(_readPtr-_periodInSamples+WG_BUFFER_SIZE)%WG_BUFFER_SIZE]; - - // 4. apply damping (low-pass) filter to output - - if(++_filterReadPtr>=FILTER_BUFFER_SIZE) - _filterReadPtr=0; - - out = b0_lp*out + - b1_lp*_filterBuffer_x[(_filterReadPtr-1+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] + - b2_lp*_filterBuffer_x[(_filterReadPtr-2+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] - - a1_lp*_filterBuffer_y[(_filterReadPtr-1+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE] - - a2_lp*_filterBuffer_y[(_filterReadPtr-2+FILTER_BUFFER_SIZE)%FILTER_BUFFER_SIZE]; - - // 5. Simple high-pass filter to block DC-offset - // y[n] = x[n] - x[n-1] + a * y[n-1] - float gain = 0.9999; - float temp = out; - out = out - _lastX + gain * _lastY; - _lastY = out; - _lastX = temp; - - // 6. Apply intensity damping - out *= DECAY; - - _filterBuffer_x[_filterReadPtr] = in; - _filterBuffer_y[_filterReadPtr] = out; - - return out; - -} - -void Waveguide::setFrequency(float frequency) { - - // NB: currently no interpolation, so may not be ideal for dynamically changing waveguide frequency - _periodInMilliseconds = 1000.0/frequency; - _periodInSamples = (int)(_periodInMilliseconds * 44.1); - -} - -void Waveguide::updateFilterCoeffs(float frequency) { - - // FIXME: Butterworth filter doesn't work very well, - // using simple FIR in the meantime - - a1_lp = 0; - a2_lp = 0; - b0_lp = 1.0 - DAMPING; - b1_lp = DAMPING; - b2_lp = 0; - - /* - // 'w' for sake of resembling lower-case 'omega' - float w = 2.0 * M_PI * frequency; - float t = _dt; - // The Q for a 2nd-order Butterworth is sqrt(2)/2 - float q = 0.707;//sqrt(2.0)/2.0; - - // low-pass filter coefficients - float a0_lp = w*w*t*t + 2*(w/q)*t + 4.0; - float k = 1.0/a0_lp; - a1_lp = (2.0*w*w*t*t - 8.0) * k; - a2_lp = (4.0 - (w/q)*2.0*t + w*w*t*t) * k; - b0_lp = (w*w*t*t) * k; - b1_lp = (2.0*w*w*t*t) * k; - b2_lp = (w*w*t*t) * k; - */ - -}
--- a/examples/airharp/Waveguide.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * - * Simple 1-Dimensional Waveguide - * - * Christian Heinrichs 04/2015 - * - */ - -#ifndef WAVEGUIDE_H_ -#define WAVEGUIDE_H_ - -#include <cmath> - -#ifndef WG_BUFFER_SIZE -#define WG_BUFFER_SIZE 4096 -#endif - -#ifndef FILTER_BUFFER_SIZE -#define FILTER_BUFFER_SIZE 4 -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846264338 -#endif - -class Waveguide -{ - -public: - - Waveguide(); - void setup(); - float update(float in); - void updateFilterCoeffs(float frequency); - void setFrequency(float frequency); - -private: - - double _dt; - float _periodInMilliseconds; - int _periodInSamples; - - float _buffer[WG_BUFFER_SIZE]; - int _readPtr; - - float _filterBuffer_x[FILTER_BUFFER_SIZE]; - float _filterBuffer_y[FILTER_BUFFER_SIZE]; - float _hipBuffer_x[FILTER_BUFFER_SIZE]; - float _hipBuffer_y[FILTER_BUFFER_SIZE]; - int _filterReadPtr; - - float b0_lp,b1_lp,b2_lp,a1_lp, a2_lp; - float _lastY,_lastX; - -}; - -#endif
--- a/examples/airharp/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,211 +0,0 @@ -/* - * AIR-HARP - * Physically modelled strings using waveguide junctions and mass-spring-dampers - * - * render.cpp - * - * Christian Heinrichs 04/2015 - * - */ - - -#include "MassSpringDamper.h" -#include "String.h" -#include "Plectrum.h" - -#include <Bela.h> -#include <cmath> -#include <stdio.h> -#include <cstdlib> -#include <rtdk.h> - -#define ACCEL_BUF_SIZE 8 -#define NUMBER_OF_STRINGS 9 - -// PENTATONIC SCALE -float gMidinotes[NUMBER_OF_STRINGS] = {40,45,50,55,57,60,62,64,67}; - -float gInverseSampleRate; - -float out_gain = 5.0; - -int accelPin_x = 0; -int accelPin_y = 1; -int accelPin_z = 2; - -MassSpringDamper msd = MassSpringDamper(1,0.1,10);// (10,0.001,10); -String strings[NUMBER_OF_STRINGS]; -Plectrum plectrums[NUMBER_OF_STRINGS]; - -float gPlectrumDisplacement = 0; - -float gAccel_x[ACCEL_BUF_SIZE] = {0}; -int gAccelReadPtr = 0; - -// DC BLOCK BUTTERWORTH - -// Coefficients for 100hz cut-off -float a0_l = 0.9899759179893742; -float a1_l = -1.9799518359787485; -float a2_l = 0.9899759179893742; -float a3_l = -1.979851353142371; -float a4_l = 0.9800523188151258; - -float a0_r = a0_l; -float a1_r = a1_l; -float a2_r = a2_l; -float a3_r = a3_l; -float a4_r = a4_l; - -float x1_l = 0; -float x2_l = 0; -float y1_l = 0; -float y2_l = 0; - -float x1_r = 0; -float x2_r = 0; -float y1_r = 0; -float y2_r = 0; - - -bool setup(BelaContext *context, void *userData) -{ - - gInverseSampleRate = 1.0 / context->audioSampleRate; - - // initialise strings & plectrums - for(int i=0;i<NUMBER_OF_STRINGS;i++) { - - plectrums[i] = Plectrum(); - plectrums[i].setup(250,0.25,0.05); - - strings[i] = String(); - strings[i].setMidinote(gMidinotes[i]); - - float spacing = 2.0 / (NUMBER_OF_STRINGS+1); - - strings[i].setGlobalPosition( -1 + spacing*(i+1) ); - - rt_printf("STRING %d // midinote: %f position: %f\n",i,gMidinotes[i],( -1 + spacing*(i+1) )); - - } - - return true; -} - -void render(BelaContext *context, void *userData) -{ - - float lastAccel = 0; - - for(int n = 0; n < context->audioFrames; n++) { - - /* - * - * ACCELEROMETER DATA - * - */ - - // Read accelerometer data from analog input - float accel_x = 0; - if(n%2) { - accel_x = (float)context->analogIn[(n/2)*8+accelPin_x] * 2 - 1; // 15800 - 28300 - 41500 - lastAccel = accel_x; - } else { - // grab previous value if !n%2 - accel_x = lastAccel; - } - - // Dead-zone avoids noise when box is lying horizontally on a surface - - float accelDeadZone = 0.1; - - if(accel_x <= accelDeadZone && accel_x >= -accelDeadZone) - accel_x = 0; - - // Perform smoothing (moving average) on acceleration value - if(++gAccelReadPtr >= ACCEL_BUF_SIZE) - gAccelReadPtr = 0; - gAccel_x[gAccelReadPtr] = accel_x; - float gravity = 0; - for(int i=0;i<ACCEL_BUF_SIZE;i++) { - gravity = gAccel_x[(gAccelReadPtr-i+ACCEL_BUF_SIZE)%ACCEL_BUF_SIZE]; - } - gravity /= ACCEL_BUF_SIZE; - - /* - * - * PHYSICS SIMULATION - * - */ - - // The horizontal force (which can be gravity if box is tipped on its side) - // is used as the input to a Mass-Spring-Damper model - // Plectrum displacement (i.e. when interacting with string) is included - float massPosition = (float)msd.update(gravity - gPlectrumDisplacement); - - float out_l = 0; - float out_r = 0; - // Use this parameter to quickly adjust output gain - float gain = 0.0015; // 0.0015 is a good value or 12 strings - gPlectrumDisplacement = 0; - - for(int s=0;s<NUMBER_OF_STRINGS;s++) { - - float stringPosition = strings[s].getGlobalPosition(); - - float plectrumForce = plectrums[s].update(massPosition, stringPosition); - gPlectrumDisplacement += strings[s].getPlectrumDisplacement(); - - // calculate panning based on string position (-1->left / 1->right) - float panRight = map(stringPosition,1,-1,0.1,1); - float panLeft = map(stringPosition,-1,1,0.1,1); - panRight *= panRight; - panLeft *= panLeft; - - float out = strings[s].update(plectrumForce)*gain; - - out_l += out*panLeft; - out_r += out*panRight; - - } - - // APPLY DC-BLOCK FILTER TO OUTPUTS - - // LEFT CHANNEL - float temp_in = out_l; - /* compute result */ - out_l = a0_l * out_l + a1_l * x1_l + a2_l * x2_l - a3_l * y1_l - a4_l * y2_l; - /* shift x1 to x2, sample to x1 */ - x2_l = x1_l; - x1_l = temp_in; - /* shift y1 to y2, result to y1 */ - y2_l = y1_l; - y1_l = out_l; - - // RIGHT CHANNEL - temp_in = out_r; - /* compute result */ - out_r = a0_r * out_r + a1_r * x1_r + a2_r * x2_r - a3_r * y1_r - a4_r * y2_r; - /* shift x1 to x2, sample to x1 */ - x2_r = x1_r; - x1_r = temp_in; - /* shift y1 to y2, result to y1 */ - y2_r = y1_r; - y1_r = out_r; - - context->audioOut[n * context->audioChannels + 1] = out_l * out_gain; - context->audioOut[n * context->audioChannels + 0] = out_r * out_gain; - - } - -} - - -// cleanup_render() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in initialise_render(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/analogDigitalDemo/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * assignment1_crossover - * RTDSP 2015 - * - * First assignment for ECS732 RTDSP, to implement a 2-way audio crossover - * using the BeagleBone Black. - * - * Andrew McPherson and Victor Zappi - * Queen Mary, University of London - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <unistd.h> -#include <stdlib.h> -#include <fcntl.h> - -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - float frequency = 1000.0; // Frequency of crossover - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"frequency", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - frequency = atof(optarg); - if(frequency < 20.0) - frequency = 20.0; - if(frequency > 5000.0) - frequency = 5000.0; - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &frequency) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/analogDigitalDemo/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * - * Andrew McPherson and Victor Zappi - * Queen Mary, University of London - */ - -/** -\example 3_analogDigitalDemo - -Analog digital workout ----------------------- - -This sketch showcases many different ways to write and read digital pins, -including generating clocks and creating binary counters. - -The code as it is will not work properly, as the direction of the pins is not -set. As an exercise, you will need to set the pin mode before writing or reading -the digital pins. - -This is for advanced users only. -*/ - -#include <Bela.h> -#include <cmath> -#include <rtdk.h> - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numAnalogFrames -// will be 0. - -void render(BelaContext *context, void *userData) -/* -we assume that gNumAnalogChannels=8, numAnalogFrames==8 and numDigitalFrames==numAudioFrames - * */ -{ - /* - * TODO: as an exercise, you will need to set the pin mode before writing or reading the digital pins. - */ - if((context->audioFramesElapsed&31)==0){ //every 32 frames... - //ANALOG channels - analogWrite(context, 0, 0, analogRead(context, 0,0)); - // read the input0 at frame0 and write it to output0 frame0. Using analogWrite will fill the rest of the buffer with the same value - // The value at the last frame will persist through the successive buffers until is set again. - // This effectively is a pass-through with downsampling by 32 times - analogWrite(context, 0, 3, 1.0); // write 1.0 to channel3 from frame0 to the end of the buffer - analogWrite(context, 4, 3, 0.1); // write 0.1 to channel3 from frame4 to the end of the buffer - analogWriteOnce(context, 6, 3, 0.2); //write 0.2 to channel3 only on frame 6 - //this buffer for channel 3 will look like this: 1 1 1 1 0.1 0.1 0.2 0.1 - //the next buffers for channel 3 will be filled up with 0.1 .... - //DIGITAL channels - digitalWrite(context, 0, P8_07, GPIO_HIGH); //sets all the frames to HIGH for channel 0 - digitalWriteOnce(context, 4, P8_07, GPIO_LOW); //only frame 4 will be LOW for channel 0 - // in this buffer the frames of channel 0 will look like this: 1 1 1 1 0 1 1 1 ...... 1 - // in the next buffer each frame of channel 0 will be initialized to 1 (the last value of this buffer) - digitalWrite(context, 0, P8_08, GPIO_HIGH); - digitalWrite(context, 2, P8_08, GPIO_LOW); - digitalWrite(context, 4, P8_08, GPIO_HIGH); - digitalWrite(context, 5, P8_08, GPIO_LOW); - pinMode(context, 0, P9_16, GPIO_INPUT); // set channel 10 to input - // in this buffer the frames of channel 1 will look like this: 1 1 0 0 1 0 0 0 .... 0 - // in the next buffer each frame of channel 1 will be initialized to 0 (the last value of this buffer) - } - for(unsigned int n=0; n<context->audioFrames; n++){ - for(unsigned int c=0; c<context->audioChannels; c++){ - context->audioOut[n*context->audioChannels + c]=context->audioIn[n*context->audioChannels + c]; - } - //use digital channels 2-8 to create a 7 bit binary counter - context->digital[n]=context->digital[n] & (~0b111111100); // set to zero (GPIO_OUTPUT) the bits in the lower word - context->digital[n]=context->digital[n] & ((~0b111111100<<16) | 0xffff ); //initialize to zero the bits in the higher word (output value) - context->digital[n]=context->digital[n] | ( ((context->audioFramesElapsed&0b1111111)<<(16+2)) ) ; // set the bits in the higher word to the desired output value, keeping the lower word unchanged - digitalWrite(context, n, P8_29, digitalRead(context, n, P8_30)); // echo the input from from channel 15 to channel 14 - digitalWrite(context, n, P8_28, digitalRead(context, n, P9_16)); // echo the input from from channel 10 to channel 13 - pinMode(context, 0, P8_30, 0); //set channel 15 to input - } - - for(unsigned int n=0; n<context->analogFrames; n++){ - analogWrite(context, n, 1, (context->audioFramesElapsed&8191)/8192.0); // writes a single frame. channel 1 is a ramp that follows gCountFrames - analogWrite(context, n, 2, analogRead(context, n, 2)); // writes a single frame. channel2 is just a passthrough -// rt_printf("Analog out frame %d :",n); -// for(int c=0; c<gNumAnalogChannels; c++) -// rt_printf("%.1f ",analogOut[n*gNumAnalogChannels + c]); -// rt_printf("\n"); - } - return; - -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - // Nothing to do here -}
--- a/examples/audio_in_FFT/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --fftsize [-s] size: Set the fSize of the FFT, in samples\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - int fftSize = 64; // Size of the FFT, in samples - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"fftsize", 1, NULL, 's'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - -// settings.useAnalog = 0; // No matrix usage by default - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hs:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 's': - fftSize = atof(optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &fftSize) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -} -
--- a/examples/audio_in_FFT/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: Andrew McPherson, C4DM, QMUL - */ - -/** -\example 4_audio_FFT - -Fast Fourier Transform ----------------------- - -This sketch performs an FFT (Fast Fourier Transform) on incoming audio. It uses -the NE10 library, included at the top of the file (line 11). - -Read the documentation on the NE10 library [here](http://projectne10.github.io/Ne10/doc/annotated.html). - -The variables `timeDomainIn`, `timeDomainOut` and `frequencyDomain` are -variables of the struct `ne10_fft_cpx_float32_t` [http://projectne10.github.io/Ne10/doc/structne10__fft__cpx__float32__t.html](http://projectne10.github.io/Ne10/doc/structne10__fft__cpx__float32__t.html). -These are declared at the top of the file (line 21), and memory is allocated -for them in `setup()` (line 41). - -In `render()` a `for` loop performs the FFT which is performed on each sample, -and the resulting output is placed on each channel. -*/ - -#include <Bela.h> -#include <rtdk.h> -#include <ne10/NE10.h> // neon library -#include <cmath> - -int gFFTSize; - -int gReadPointer = 0; -int gWritePointer = 0; - -// FFT vars -static ne10_fft_cpx_float32_t* timeDomainIn; -static ne10_fft_cpx_float32_t* timeDomainOut; -static ne10_fft_cpx_float32_t* frequencyDomain; -static ne10_fft_cfg_float32_t cfg; - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - // Retrieve a parameter passed in from the initAudio() call - gFFTSize = *(int *)userData; - - timeDomainIn = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); - timeDomainOut = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); - frequencyDomain = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); - cfg = ne10_fft_alloc_c2c_float32_neon (gFFTSize); - - memset(timeDomainOut, 0, gFFTSize * sizeof (ne10_fft_cpx_float32_t)); - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - timeDomainIn[gReadPointer].r = (ne10_float32_t) ((context->audioIn[n*context->audioChannels] + - context->audioIn[n*context->audioChannels+1]) * 0.5); - timeDomainIn[gReadPointer].i = 0; - - if(++gReadPointer >= gFFTSize) - { - //FFT - ne10_fft_c2c_1d_float32_neon (frequencyDomain, timeDomainIn, cfg, 0); - - //Do frequency domain stuff - - //IFFT - ne10_fft_c2c_1d_float32_neon (timeDomainOut, frequencyDomain, cfg, 1); - - gReadPointer = 0; - gWritePointer = 0; - } - - for(unsigned int channel = 0; channel < context->audioChannels; channel++) - context->audioOut[n * context->audioChannels + channel] = (float) timeDomainOut[gWritePointer].r; - gWritePointer++; - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - NE10_FREE(timeDomainIn); - NE10_FREE(timeDomainOut); - NE10_FREE(frequencyDomain); - NE10_FREE(cfg); -}
--- a/examples/basic/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ -#include <unistd.h> -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - float frequency = 440.0; // Frequency of oscillator - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"frequency", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - frequency = atof(optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &frequency) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/basic/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -/** -\example 1_basic_helloworld - -Producing your first bleep! ---------------------------- - -This sketch is the hello world of embedded interactive audio. Better known as bleep, it -produces a sine tone. - -The frequency of the sine tone is determined by a global variable, `gFrequency` -(line 12). The sine tone is produced by incrementing the phase of a sin function -on every audio frame. - -In render() you'll see a nested for loop structure. You'll see this in all Bela projects. -The first for loop cycles through 'audioFrames', the second through 'audioChannels' (in this case left 0 and right 1). -It is good to familiarise yourself with this structure as it's fundamental to producing sound with the system. -*/ - -#include <Bela.h> -#include <cmath> - -float gFrequency = 440.0; -float gPhase; -float gInverseSampleRate; - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - // Retrieve a parameter passed in from the initAudio() call - if(userData != 0) - gFrequency = *(float *)userData; - - gInverseSampleRate = 1.0 / context->audioSampleRate; - gPhase = 0.0; - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - float out = 0.8f * sinf(gPhase); - gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; - if(gPhase > 2.0 * M_PI) - gPhase -= 2.0 * M_PI; - - for(unsigned int channel = 0; channel < context->audioChannels; channel++) { - // Two equivalent ways to write this code - - // The long way, using the buffers directly: - // context->audioOut[n * context->audioChannels + channel] = out; - - // Or using the macros: - audioWrite(context, n, channel, out); - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/basic_FFT_phase_vocoder/SampleData.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* - * SampleData.h - * - * Created on: Nov 5, 2014 - * Author: Victor Zappi - */ - -#ifndef SAMPLEDATA_H_ -#define SAMPLEDATA_H_ - -// User defined structure to pass between main and rendere complex data retrieved from file -struct SampleData { - float *samples; // Samples in file - int sampleLen; // Total nume of samples -}; - - - -#endif /* SAMPLEDATA_H_ */
--- a/examples/basic_FFT_phase_vocoder/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <cstdio> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <unistd.h> -#include <sys/time.h> -#include <sndfile.h> // to load audio files -#include "SampleData.h" -#include <Bela.h> - -using namespace std; - -// Global variables used by getCurrentTime() -unsigned long long gFirstSeconds, gFirstMicroseconds; - -// Load samples from file -int initFile(string file, SampleData *smp)//float *& smp) -{ - SNDFILE *sndfile ; - SF_INFO sfinfo ; - - if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { - cout << "Couldn't open file " << file << endl; - return 1; - } - - int numChan = sfinfo.channels; - if(numChan != 1) - { - cout << "Error: " << file << " is not a mono file" << endl; - return 1; - } - - smp->sampleLen = sfinfo.frames * numChan; - smp->samples = new float[smp->sampleLen]; - if(smp == NULL){ - cout << "Could not allocate buffer" << endl; - return 1; - } - - int subformat = sfinfo.format & SF_FORMAT_SUBMASK; - int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); - - // Pad with zeros in case we couldn't read whole file - for(int k = readcount; k <smp->sampleLen; k++) - smp->samples[k] = 0; - - if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { - double scale ; - int m ; - - sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; - if (scale < 1e-10) - scale = 1.0 ; - else - scale = 32700.0 / scale ; - cout << "File samples scale = " << scale << endl; - - for (m = 0; m < smp->sampleLen; m++) - smp->samples[m] *= scale; - } - - sf_close(sndfile); - - return 0; -} - - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --help [-h]: Print this menu\n"; -} - -/* Function which returns the time since start of the program - * in (fractional) seconds. - */ -double getCurrentTime(void) { - unsigned long long result; - struct timeval tv; - - gettimeofday(&tv, NULL); - result = (tv.tv_sec - gFirstSeconds) * 1000000ULL + (tv.tv_usec - gFirstMicroseconds); - return (double)result / 1000000.0; -} -extern SampleData gSampleData; -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - struct timeval tv; - string fileName; // Name of the sample to load - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"file", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - gSampleData.samples = 0; - gSampleData.sampleLen = -1; - - // Set default settings - Bela_defaultSettings(&settings); - - settings.periodSize = 32; // Larger period size by default, for testing - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - fileName = string((char *)optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - if(fileName.empty()){ - fileName = "sample.wav"; - } - - - // Load file - if(initFile(fileName, &gSampleData) != 0) - { - cout << "Error: unable to load samples " << endl; - return -1; - } - - if(settings.verbose) - cout << "File contains " << gSampleData.sampleLen << " samples" << endl; - - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &gSampleData) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Initialise time - gettimeofday(&tv, NULL); - gFirstSeconds = tv.tv_sec; - gFirstMicroseconds = tv.tv_usec; - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/basic_FFT_phase_vocoder/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,299 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -/** -\example 4_audio_FFT_phase_vocoder - -Phase Vocoder ----------------------- - -This sketch shows an implementation of a phase vocoder and builds on the previous FFT example. -Again it uses the NE10 library, included at the top of the file (line 11). - -Read the documentation on the NE10 library [here](http://projectne10.github.io/Ne10/doc/annotated.html). -*/ - -#include <Bela.h> -#include <rtdk.h> -#include <ne10/NE10.h> // NEON FFT library -#include <cmath> -#include "SampleData.h" -#include <Midi.h> - -#define BUFFER_SIZE 16384 - -// TODO: your buffer and counter go here! -float gInputBuffer[BUFFER_SIZE]; -int gInputBufferPointer = 0; -float gOutputBuffer[BUFFER_SIZE]; -int gOutputBufferWritePointer = 0; -int gOutputBufferReadPointer = 0; -int gSampleCount = 0; - -float *gWindowBuffer; - -// ----------------------------------------------- -// These variables used internally in the example: -int gFFTSize = 2048; -int gHopSize = 512; -int gPeriod = 512; -float gFFTScaleFactor = 0; - -// FFT vars -ne10_fft_cpx_float32_t* timeDomainIn; -ne10_fft_cpx_float32_t* timeDomainOut; -ne10_fft_cpx_float32_t* frequencyDomain; -ne10_fft_cfg_float32_t cfg; - -// Sample info -SampleData gSampleData; // User defined structure to get complex data from main -int gReadPtr = 0; // Position of last read sample from file - -// Auxiliary task for calculating FFT -AuxiliaryTask gFFTTask; -int gFFTInputBufferPointer = 0; -int gFFTOutputBufferPointer = 0; - -void process_fft_background(); - - -int gEffect = 0; // change this here or with midi CC -enum{ - kBypass, - kRobot, - kWhisper, -}; - -float gDryWet = 1; // mix between the unprocessed and processed sound -float gPlaybackLive = 0.5f; // mix between the file playback and the live audio input -float gGain = 1; // overall gain -float *gInputAudio = NULL; -Midi midi; - - -void midiCallback(MidiChannelMessage message, void* arg){ - if(message.getType() == kmmNoteOn){ - if(message.getDataByte(1) > 0){ - int note = message.getDataByte(0); - float frequency = powf(2, (note-69)/12.f)*440; - gPeriod = (int)(44100 / frequency + 0.5); - printf("\nnote: %d, frequency: %f, hop: %d\n", note, frequency, gPeriod); - } - } - - bool shouldPrint = false; - if(message.getType() == kmmControlChange){ - float data = message.getDataByte(1) / 127.0f; - switch (message.getDataByte(0)){ - case 2 : - gEffect = (int)(data * 2 + 0.5); // CC2 selects an effect between 0,1,2 - break; - case 3 : - gPlaybackLive = data; - break; - case 4 : - gDryWet = data; - break; - case 5: - gGain = data*10; - break; - default: - shouldPrint = true; - } - } - if(shouldPrint){ - message.prettyPrint(); - } -} - -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. -bool setup(BelaContext* context, void* userData) -{ - midi.readFrom(0); - midi.setParserCallback(midiCallback); - // Retrieve a parameter passed in from the initAudio() call - gSampleData = *(SampleData *)userData; - - gFFTScaleFactor = 1.0f / (float)gFFTSize; - gOutputBufferWritePointer += gHopSize; - - timeDomainIn = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); - timeDomainOut = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); - frequencyDomain = (ne10_fft_cpx_float32_t*) NE10_MALLOC (gFFTSize * sizeof (ne10_fft_cpx_float32_t)); - cfg = ne10_fft_alloc_c2c_float32_neon (gFFTSize); - - memset(timeDomainOut, 0, gFFTSize * sizeof (ne10_fft_cpx_float32_t)); - memset(gOutputBuffer, 0, BUFFER_SIZE * sizeof(float)); - - // Allocate buffer to mirror and modify the input - gInputAudio = (float *)malloc(context->audioFrames * context->audioChannels * sizeof(float)); - if(gInputAudio == 0) - return false; - - // Allocate the window buffer based on the FFT size - gWindowBuffer = (float *)malloc(gFFTSize * sizeof(float)); - if(gWindowBuffer == 0) - return false; - - // Calculate a Hann window - for(int n = 0; n < gFFTSize; n++) { - gWindowBuffer[n] = 0.5f * (1.0f - cosf(2.0 * M_PI * n / (float)(gFFTSize - 1))); - } - - // Initialise auxiliary tasks - if((gFFTTask = Bela_createAuxiliaryTask(&process_fft_background, 90, "fft-calculation")) == 0) - return false; - rt_printf("You are listening to an FFT phase-vocoder with overlap-and-add.\n" - "Use Midi Control Change to control:\n" - "CC 2: effect type (bypass/robotization/whisperization)\n" - "CC 3: mix between recorded sample and live audio input\n" - "CC 4: mix between the unprocessed and processed sound\n" - "CC 5: gain\n" - ); - return true; -} - -// This function handles the FFT processing in this example once the buffer has -// been assembled. -void process_fft(float *inBuffer, int inWritePointer, float *outBuffer, int outWritePointer) -{ - // Copy buffer into FFT input - int pointer = (inWritePointer - gFFTSize + BUFFER_SIZE) % BUFFER_SIZE; - for(int n = 0; n < gFFTSize; n++) { - timeDomainIn[n].r = (ne10_float32_t) inBuffer[pointer] * gWindowBuffer[n]; - timeDomainIn[n].i = 0; - - pointer++; - if(pointer >= BUFFER_SIZE) - pointer = 0; - } - - // Run the FFT - ne10_fft_c2c_1d_float32_neon (frequencyDomain, timeDomainIn, cfg, 0); - - switch (gEffect){ - case kRobot : - // Robotise the output - for(int n = 0; n < gFFTSize; n++) { - float amplitude = sqrtf(frequencyDomain[n].r * frequencyDomain[n].r + frequencyDomain[n].i * frequencyDomain[n].i); - frequencyDomain[n].r = amplitude; - frequencyDomain[n].i = 0; - } - break; - case kWhisper : - for(int n = 0; n < gFFTSize; n++) { - float amplitude = sqrtf(frequencyDomain[n].r * frequencyDomain[n].r + frequencyDomain[n].i * frequencyDomain[n].i); - float phase = rand()/(float)RAND_MAX * 2 * M_PI; - frequencyDomain[n].r = cosf(phase) * amplitude; - frequencyDomain[n].i = sinf(phase) * amplitude; - } - break; - case kBypass: - //bypass - break; - } - - // Run the inverse FFT - ne10_fft_c2c_1d_float32_neon (timeDomainOut, frequencyDomain, cfg, 1); - // Overlap-and-add timeDomainOut into the output buffer - pointer = outWritePointer; - for(int n = 0; n < gFFTSize; n++) { - outBuffer[pointer] += (timeDomainOut[n].r) * gFFTScaleFactor; - if(isnan(outBuffer[pointer])) - rt_printf("outBuffer OLA\n"); - pointer++; - if(pointer >= BUFFER_SIZE) - pointer = 0; - } -} - -// Function to process the FFT in a thread at lower priority -void process_fft_background() { - process_fft(gInputBuffer, gFFTInputBufferPointer, gOutputBuffer, gFFTOutputBufferPointer); -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. -void render(BelaContext* context, void* userData) -{ - float* audioOut = context->audioOut; - int numAudioFrames = context->audioFrames; - int numAudioChannels = context->audioChannels; - // ------ this code internal to the demo; leave as is ---------------- - - // Prep the "input" to be the sound file played in a loop - for(int n = 0; n < numAudioFrames; n++) { - if(gReadPtr < gSampleData.sampleLen) - gInputAudio[2*n] = gInputAudio[2*n+1] = gSampleData.samples[gReadPtr]*(1-gPlaybackLive) + - gPlaybackLive*0.5f*(audioRead(context,n,0)+audioRead(context,n,1)); - else - gInputAudio[2*n] = gInputAudio[2*n+1] = 0; - if(++gReadPtr >= gSampleData.sampleLen) - gReadPtr = 0; - } - // ------------------------------------------------------------------- - - for(int n = 0; n < numAudioFrames; n++) { - gInputBuffer[gInputBufferPointer] = ((gInputAudio[n*numAudioChannels] + gInputAudio[n*numAudioChannels+1]) * 0.5); - - // Copy output buffer to output - for(int channel = 0; channel < numAudioChannels; channel++){ - audioOut[n * numAudioChannels + channel] = gOutputBuffer[gOutputBufferReadPointer] * gGain * gDryWet + (1 - gDryWet) * gInputAudio[n * numAudioChannels + channel]; - } - - // Clear the output sample in the buffer so it is ready for the next overlap-add - gOutputBuffer[gOutputBufferReadPointer] = 0; - gOutputBufferReadPointer++; - if(gOutputBufferReadPointer >= BUFFER_SIZE) - gOutputBufferReadPointer = 0; - gOutputBufferWritePointer++; - if(gOutputBufferWritePointer >= BUFFER_SIZE) - gOutputBufferWritePointer = 0; - - gInputBufferPointer++; - if(gInputBufferPointer >= BUFFER_SIZE) - gInputBufferPointer = 0; - - gSampleCount++; - if(gSampleCount >= gHopSize) { - //process_fft(gInputBuffer, gInputBufferPointer, gOutputBuffer, gOutputBufferPointer); - gFFTInputBufferPointer = gInputBufferPointer; - gFFTOutputBufferPointer = gOutputBufferWritePointer; - Bela_scheduleAuxiliaryTask(gFFTTask); - - gSampleCount = 0; - } - } - gHopSize = gPeriod; -} - -// cleanup_render() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in initialise_render(). - -void cleanup(BelaContext* context, void* userData) -{ - NE10_FREE(timeDomainIn); - NE10_FREE(timeDomainOut); - NE10_FREE(frequencyDomain); - NE10_FREE(cfg); - free(gInputAudio); - free(gWindowBuffer); -}
--- a/examples/basic_analog_input/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -int gSensorInputFrequency = 0; -int gSensorInputAmplitude = 1; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --frequency [-f] input: Choose the analog input controlling frequency (0-7; default 0)\n"; - cerr << " --amplitude [-a] input: Choose the analog input controlling amplitude (0-7; default 1)\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"frequency", 1, NULL, 'f'}, - {"amplitude", 1, NULL, 'a'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:a:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - gSensorInputFrequency = atoi(optarg); - if(gSensorInputFrequency < 0 || gSensorInputFrequency > 7) { - usage(basename(argv[0])); - exit(0); - } - break; - case 'a': - gSensorInputAmplitude = atoi(optarg); - if(gSensorInputAmplitude < 0 || gSensorInputAmplitude > 7) { - usage(basename(argv[0])); - exit(0); - } - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, 0) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - if(settings.verbose) { - cout << "--> Frequency on input " << gSensorInputFrequency << endl; - cout << "--> Amplitude on input " << gSensorInputAmplitude << endl; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/basic_analog_input/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -/** -\example 3_analog_input - -Connecting potentiometers -------------------------- - -This sketch produces a sine tone, the frequency and amplitude of which are -affected by data received on the analog pins. Before looping through each audio -frame, we declare a value for the frequency and amplitude of our sine tone -(line 55); we adjust these values by taking in data from analog sensors -(for example potentiometers) with `analogRead()`. - -- connect a 10K pot to 3.3V and GND on its 1st and 3rd pins. -- connect the 2nd middle pin of the pot to analogIn 0. -- connect another 10K pot in the same way but with the middle pin connected to analogIn 1. - -The important thing to notice is that audio is sampled twice as often as analog -data. The audio sampling rate is 44.1kHz (44100 frames per second) and the -analog sampling rate is 22.05kHz (22050 frames per second). On line 62 you might -notice that we are processing the analog data and updating frequency and -amplitude only on every second audio sample, since the analog sampling rate is -half that of the audio. - -Note that the pin numbers are stored in the variables `gAnalogInputFrequency` and -`gAnalogInputAmplitude`. These are declared in the main.cpp file; if you look in -that file you will see that they have the values of 0 and 1. Bear in mind that -these are analog input pins which is a specific header! -*/ - -#include <Bela.h> -#include <rtdk.h> -#include <cmath> - -float gPhase; -float gInverseSampleRate; -int gAudioFramesPerAnalogFrame; - -// These settings are carried over from main.cpp -// Setting global variables is an alternative approach -// to passing a structure to userData in setup() - -extern int gSensorInputFrequency; -extern int gSensorInputAmplitude; - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - if(context->analogFrames == 0 || context->analogFrames > context->audioFrames) { - rt_printf("Error: this example needs analog enabled, with 4 or 8 channels\n"); - return false; - } - - gAudioFramesPerAnalogFrame = context->audioFrames / context->analogFrames; - gInverseSampleRate = 1.0 / context->audioSampleRate; - gPhase = 0.0; - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - float frequency = 440.0; - float amplitude = 0.8; - - // There are twice as many audio frames as matrix frames since audio sample rate - // is twice as high - - for(unsigned int n = 0; n < context->audioFrames; n++) { - if(!(n % gAudioFramesPerAnalogFrame)) { - // Even audio samples: update frequency and amplitude from the matrix - frequency = map(analogRead(context, n/gAudioFramesPerAnalogFrame, gSensorInputFrequency), 0, 1, 100, 1000); - amplitude = analogRead(context, n/gAudioFramesPerAnalogFrame, gSensorInputAmplitude); - } - - float out = amplitude * sinf(gPhase); - - for(unsigned int channel = 0; channel < context->audioChannels; channel++) - context->audioOut[n * context->audioChannels + channel] = out; - - gPhase += 2.0 * M_PI * frequency * gInverseSampleRate; - if(gPhase > 2.0 * M_PI) - gPhase -= 2.0 * M_PI; - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/basic_analog_output/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --frequency [-f] frequency: Set the frequency of the LED fade (default: 1.0)\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - float frequency = 1.0; // Frequency of LED fades - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"frequency", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // In this example, audio isn't used so might as well leave speaker muted - settings.beginMuted = 1; - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - frequency = atof(optarg); - if(frequency < 0) - frequency = 0; - if(frequency > 11025.0) - frequency = 11025.0; - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &frequency) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/basic_analog_output/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * - * Andrew McPherson and Victor Zappi - * Queen Mary, University of London - */ - -/** -\example 3_analog_output - -Fading LEDs ------------ - -This sketch uses a sine wave to drive the brightness of a series of LEDs -connected to the eight analog out pins. Again you can see the nested `for` loop -structure but this time for the analog output channels rather than the audio. - -- connect an LED in series with a 470ohm resistor between each of the analogOut pins and ground. - -Within the first for loop in render we cycle through each frame in the analog -output matrix. At each frame we then cycle through the analog output channels -with another for loop and set the output voltage according to the phase of a -sine tone that acts as an LFO. The analog output pins can provide a voltage of -~4.092V. - -The output on each pin is set with `analogWrite()` within the for loop that -cycles through the analog output channels. This needs to be provided with -arguments as follows `analogWrite(context, n, channel, out)`. Channel is -where the you give the address of the analog output pin (in this case we cycle -through each pin address in the for loop), out is the variable that holds the -desired output (in this case set by the sine wave). - -Notice that the phase of the brightness cycle for each led is different. This -is achieved by updating a variable that stores a relative phase value. This -variable is advanced by pi/4 (1/8 of a full rotation) for each channel giving -each of the eight LEDs a different phase. -*/ - -#include <Bela.h> -#include <rtdk.h> -#include <cmath> - -// Set range for analog outputs designed for driving LEDs -const float kMinimumAmplitude = (1.5 / 5.0); -const float kAmplitudeRange = 1.0 - kMinimumAmplitude; - -float gFrequency; -float gPhase; -float gInverseSampleRate; - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - // Retrieve a parameter passed in from the initAudio() call - gFrequency = *(float *)userData; - - if(context->analogFrames == 0) { - rt_printf("Error: this example needs the matrix enabled\n"); - return false; - } - - gInverseSampleRate = 1.0 / context->analogSampleRate; - gPhase = 0.0; - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->analogFrames; n++) { - // Set LED to different phase for each matrix channel - float relativePhase = 0.0; - for(unsigned int channel = 0; channel < context->analogChannels; channel++) { - float out = kMinimumAmplitude + kAmplitudeRange * 0.5f * (1.0f + sinf(gPhase + relativePhase)); - - analogWrite(context, n, channel, out); - - // Advance by pi/4 (1/8 of a full rotation) for each channel - relativePhase += M_PI * 0.25; - } - - gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; - if(gPhase > 2.0 * M_PI) - gPhase -= 2.0 * M_PI; - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/basic_blink/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * - * Andrew McPherson and Victor Zappi - * Queen Mary, University of London - */ - -/** -\example 2_digital_blink - -Blinking an LED ---------------- - -This sketch shows the simplest case of digital out. - -- Connect an LED in series with a 470ohm resistor between P8_07 and ground. - -The led is blinked on and off by setting the digital pin `HIGH` and `LOW` every interval seconds which is set in -`render()`. - -In `setup()` the pin mode must be set to output mode via `pinMode()`. For example: -`pinMode(context, 0, P8_07, OUTPUT)`. -In `render()` the output of the digital pins is set by `digitalWrite()`. For example: -`digitalWrite(context, n, P8_07, status)` where `status` can be equal to -either `HIGH` or `LOW`. When set `HIGH` the pin will give 3.3V, when set to -`LOW` 0V. - -To keep track of elapsed time we have a sample counter count. When the count reaches -a certain limit it switches state to either `HIGH` or `LOW` depending on its current -value. In this case the limit is `context->digitalSampleRate*interval` which -allows us to write the desired interval in seconds, stored in `interval`. -*/ - -#include <Bela.h> -#include <cmath> -#include <rtdk.h> - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - pinMode(context, 0, P8_07, OUTPUT); - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numAnalogFrames -// will be 0. - -/* basic_blink -* Connect an LED in series with a 470ohm resistor between P8_07 and ground. -* The LED will blink every @interval seconds. -*/ - -void render(BelaContext *context, void *userData) -{ - static int count=0; //counts elapsed samples - float interval=0.5; //how often to toggle the LED (in seconds) - static int status=GPIO_LOW; - for(unsigned int n=0; n<context->digitalFrames; n++){ - if(count==context->digitalSampleRate*interval){ //if enough samples have elapsed - count=0; //reset the counter - // status=digitalRead(context, 0, P8_07); - if(status==GPIO_LOW) { //toggle the status - digitalWrite(context, n, P8_07, status); //write the status to the LED - status=GPIO_HIGH; - } - else { - digitalWrite(context, n, P8_07, status); //write the status to the LED - status=GPIO_LOW; - } - } - count++; - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - // Nothing to do here -}
--- a/examples/basic_button/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * - * Andrew McPherson and Victor Zappi - * Queen Mary, University of London - */ - -/** -\example 2_digital_button - -Switching an LED on and off ---------------------------- - -This example brings together digital input and digital output. The program will read -a button and turn the LED on and off according to the state of the button. - -- connect an LED in series with a 470ohm resistor between P8_07 and ground. -- connect a 1k resistor to P9_03 (+3.3V), -- connect the other end of the resistor to both a button and P8_08 -- connect the other end of the button to ground. - -You will notice that the LED will normally stay on and will turn off as long as -the button is pressed. This is due to the fact that the LED is set to the same -value read at input P8_08. When the button is not pressed, P8_08 is `HIGH` and so -P8_07 is set to `HIGH` as well, so that the LED conducts and emits light. When -the button is pressed, P8_08 goes `LOW` and P8_07 is set to `LOW`, turning off the LED. - -As an exercise try and change the code so that the LED only turns on when -the button is pressed. -*/ - -#include <Bela.h> -#include <cmath> -#include <rtdk.h> -#include <stdlib.h> - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - pinMode(context, 0, P8_08, INPUT); - pinMode(context, 0, P8_07, OUTPUT); - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numAnalogFrames -// will be 0. - -/* basic_button -* - connect an LED in series with a 470ohm resistor between P8_07 and ground. -* - connect a 1k resistor to P9_03 (+3.3V), -* - connect the other end of the resistor to both a button and P8_08 -* - connect the other end of the button to ground. -* The program will read the button and make the LED blink when the button is pressed. -*/ - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n=0; n<context->digitalFrames; n++){ - int status=digitalRead(context, 0, P8_08); //read the value of the button - digitalWriteOnce(context, n, P8_07, status); //write the status to the LED - float out = 0.1 * status * rand() / (float)RAND_MAX * 2 - 1; //generate some noise, gated by the button - for(unsigned int j = 0; j < context->audioChannels; j++){ - audioWrite(context, n, j, out); //write the audio output - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - // Nothing to do here -} -
--- a/examples/basic_libpd/m_pd.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,770 +0,0 @@ -/* Copyright (c) 1997-1999 Miller Puckette. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -#ifndef __m_pd_h_ - -#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) -extern "C" { -#endif - -#define PD_MAJOR_VERSION 0 -#define PD_MINOR_VERSION 46 -#define PD_BUGFIX_VERSION 6 -#define PD_TEST_VERSION "" -extern int pd_compatibilitylevel; /* e.g., 43 for pd 0.43 compatibility */ - -/* old name for "MSW" flag -- we have to take it for the sake of many old -"nmakefiles" for externs, which will define NT and not MSW */ -#if defined(NT) && !defined(MSW) -#define MSW -#endif - -/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans@at.or.at> */ -#ifdef _MSC_VER -/* #pragma warning( disable : 4091 ) */ -#pragma warning( disable : 4305 ) /* uncast const double to float */ -#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */ -#pragma warning( disable : 4101 ) /* unused automatic variables */ -#endif /* _MSC_VER */ - - /* the external storage class is "extern" in UNIX; in MSW it's ugly. */ -#ifdef _WIN32 -#ifdef PD_INTERNAL -#define EXTERN __declspec(dllexport) extern -#else -#define EXTERN __declspec(dllimport) extern -#endif /* PD_INTERNAL */ -#else -#define EXTERN extern -#endif /* _WIN32 */ - - /* and depending on the compiler, hidden data structures are - declared differently: */ -#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ ) -#define EXTERN_STRUCT struct -#else -#define EXTERN_STRUCT extern struct -#endif - -/* Define some attributes, specific to the compiler */ -#if defined(__GNUC__) -#define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__ ((format (printf, a, b))) -#else -#define ATTRIBUTE_FORMAT_PRINTF(a, b) -#endif - -#if !defined(_SIZE_T) && !defined(_SIZE_T_) -#include <stddef.h> /* just for size_t -- how lame! */ -#endif - -/* Microsoft Visual Studio is not C99, it does not provide stdint.h */ -#ifdef _MSC_VER -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef signed __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -#else -# include <stdint.h> -#endif - -/* for FILE, needed by sys_fopen() and sys_fclose() only */ -#include <stdio.h> - -#define MAXPDSTRING 1000 /* use this for anything you want */ -#define MAXPDARG 5 /* max number of args we can typecheck today */ - -/* signed and unsigned integer types the size of a pointer: */ -#if !defined(PD_LONGINTTYPE) -#define PD_LONGINTTYPE long -#endif - -#if !defined(PD_FLOATSIZE) - /* normally, our floats (t_float, t_sample,...) are 32bit */ -# define PD_FLOATSIZE 32 -#endif - -#if PD_FLOATSIZE == 32 -# define PD_FLOATTYPE float -/* an unsigned int of the same size as FLOATTYPE: */ -# define PD_FLOATUINTTYPE unsigned int - -#elif PD_FLOATSIZE == 64 -# define PD_FLOATTYPE double -# define PD_FLOATUINTTYPE unsigned long -#else -# error invalid FLOATSIZE: must be 32 or 64 -#endif - -typedef PD_LONGINTTYPE t_int; /* pointer-size integer */ -typedef PD_FLOATTYPE t_float; /* a float type at most the same size */ -typedef PD_FLOATTYPE t_floatarg; /* float type for function calls */ - -typedef struct _symbol -{ - char *s_name; - struct _class **s_thing; - struct _symbol *s_next; -} t_symbol; - -EXTERN_STRUCT _array; -#define t_array struct _array /* g_canvas.h */ - -/* pointers to glist and array elements go through a "stub" which sticks -around after the glist or array is freed. The stub itself is deleted when -both the glist/array is gone and the refcount is zero, ensuring that no -gpointers are pointing here. */ - -#define GP_NONE 0 /* the stub points nowhere (has been cut off) */ -#define GP_GLIST 1 /* the stub points to a glist element */ -#define GP_ARRAY 2 /* ... or array */ - -typedef struct _gstub -{ - union - { - struct _glist *gs_glist; /* glist we're in */ - struct _array *gs_array; /* array we're in */ - } gs_un; - int gs_which; /* GP_GLIST/GP_ARRAY */ - int gs_refcount; /* number of gpointers pointing here */ -} t_gstub; - -typedef struct _gpointer /* pointer to a gobj in a glist */ -{ - union - { - struct _scalar *gp_scalar; /* scalar we're in (if glist) */ - union word *gp_w; /* raw data (if array) */ - } gp_un; - int gp_valid; /* number which must match gpointee */ - t_gstub *gp_stub; /* stub which points to glist/array */ -} t_gpointer; - -typedef union word -{ - t_float w_float; - t_symbol *w_symbol; - t_gpointer *w_gpointer; - t_array *w_array; - struct _binbuf *w_binbuf; - int w_index; -} t_word; - -typedef enum -{ - A_NULL, - A_FLOAT, - A_SYMBOL, - A_POINTER, - A_SEMI, - A_COMMA, - A_DEFFLOAT, - A_DEFSYM, - A_DOLLAR, - A_DOLLSYM, - A_GIMME, - A_CANT -} t_atomtype; - -#define A_DEFSYMBOL A_DEFSYM /* better name for this */ - -typedef struct _atom -{ - t_atomtype a_type; - union word a_w; -} t_atom; - -EXTERN_STRUCT _class; -#define t_class struct _class - -EXTERN_STRUCT _outlet; -#define t_outlet struct _outlet - -EXTERN_STRUCT _inlet; -#define t_inlet struct _inlet - -EXTERN_STRUCT _binbuf; -#define t_binbuf struct _binbuf - -EXTERN_STRUCT _clock; -#define t_clock struct _clock - -EXTERN_STRUCT _outconnect; -#define t_outconnect struct _outconnect - -EXTERN_STRUCT _glist; -#define t_glist struct _glist -#define t_canvas struct _glist /* LATER lose this */ - -typedef t_class *t_pd; /* pure datum: nothing but a class pointer */ - -typedef struct _gobj /* a graphical object */ -{ - t_pd g_pd; /* pure datum header (class) */ - struct _gobj *g_next; /* next in list */ -} t_gobj; - -typedef struct _scalar /* a graphical object holding data */ -{ - t_gobj sc_gobj; /* header for graphical object */ - t_symbol *sc_template; /* template name (LATER replace with pointer) */ - t_word sc_vec[1]; /* indeterminate-length array of words */ -} t_scalar; - -typedef struct _text /* patchable object - graphical, with text */ -{ - t_gobj te_g; /* header for graphical object */ - t_binbuf *te_binbuf; /* holder for the text */ - t_outlet *te_outlet; /* linked list of outlets */ - t_inlet *te_inlet; /* linked list of inlets */ - short te_xpix; /* x&y location (within the toplevel) */ - short te_ypix; - short te_width; /* requested width in chars, 0 if auto */ - unsigned int te_type:2; /* from defs below */ -} t_text; - -#define T_TEXT 0 /* just a textual comment */ -#define T_OBJECT 1 /* a MAX style patchable object */ -#define T_MESSAGE 2 /* a MAX stype message */ -#define T_ATOM 3 /* a cell to display a number or symbol */ - -#define te_pd te_g.g_pd - - /* t_object is synonym for t_text (LATER unify them) */ - -typedef struct _text t_object; - -#define ob_outlet te_outlet -#define ob_inlet te_inlet -#define ob_binbuf te_binbuf -#define ob_pd te_g.g_pd -#define ob_g te_g - -typedef void (*t_method)(void); -typedef void *(*t_newmethod)( void); - -/* in ARM 64 a varargs prototype generates a different function call sequence -from a fixed one, so in that special case we make a more restrictive -definition for t_gotfn. This will break some code in the "chaos" package -in Pd extended. (that code will run incorrectly anyhow so why not catch it -at compile time anyhow.) */ -#if defined(__APPLE__) && defined(__aarch64__) -typedef void (*t_gotfn)(void *x); -#else -typedef void (*t_gotfn)(void *x, ...); -#endif - -/* ---------------- pre-defined objects and symbols --------------*/ -EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */ -EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */ -EXTERN t_symbol s_pointer; -EXTERN t_symbol s_float; -EXTERN t_symbol s_symbol; -EXTERN t_symbol s_bang; -EXTERN t_symbol s_list; -EXTERN t_symbol s_anything; -EXTERN t_symbol s_signal; -EXTERN t_symbol s__N; -EXTERN t_symbol s__X; -EXTERN t_symbol s_x; -EXTERN t_symbol s_y; -EXTERN t_symbol s_; - -/* --------- prototypes from the central message system ----------- */ -EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv); -EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv); -EXTERN t_symbol *gensym(const char *s); -EXTERN t_gotfn getfn(t_pd *x, t_symbol *s); -EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s); -EXTERN void nullfn(void); -EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...); - -/* the following macrose are for sending non-type-checkable mesages, i.e., -using function lookup but circumventing type checking on arguments. Only -use for internal messaging protected by A_CANT so that the message can't -be generated at patch level. */ -#define mess0(x, s) ((*getfn((x), (s)))((x))) -typedef void (*t_gotfn1)(void *x, void *arg1); -#define mess1(x, s, a) ((*(t_gotfn1)getfn((x), (s)))((x), (a))) -typedef void (*t_gotfn2)(void *x, void *arg1, void *arg2); -#define mess2(x, s, a,b) ((*(t_gotfn2)getfn((x), (s)))((x), (a),(b))) -typedef void (*t_gotfn3)(void *x, void *arg1, void *arg2, void *arg3); -#define mess3(x, s, a,b,c) ((*(t_gotfn3)getfn((x), (s)))((x), (a),(b),(c))) -typedef void (*t_gotfn4)(void *x, - void *arg1, void *arg2, void *arg3, void *arg4); -#define mess4(x, s, a,b,c,d) \ - ((*(t_gotfn4)getfn((x), (s)))((x), (a),(b),(c),(d))) -typedef void (*t_gotfn5)(void *x, - void *arg1, void *arg2, void *arg3, void *arg4, void *arg5); -#define mess5(x, s, a,b,c,d,e) \ - ((*(t_gotfn5)getfn((x), (s)))((x), (a),(b),(c),(d),(e))) - -EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv); -EXTERN t_pd *pd_newest(void); - -/* --------------- memory management -------------------- */ -EXTERN void *getbytes(size_t nbytes); -EXTERN void *getzbytes(size_t nbytes); -EXTERN void *copybytes(void *src, size_t nbytes); -EXTERN void freebytes(void *x, size_t nbytes); -EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize); - -/* -------------------- atoms ----------------------------- */ - -#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0) -#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0) -#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \ - (atom)->a_w.w_gpointer = (gp)) -#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f)) -#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \ - (atom)->a_w.w_symbol = (s)) -#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \ - (atom)->a_w.w_index = (n)) -#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \ - (atom)->a_w.w_symbol= (s)) - -EXTERN t_float atom_getfloat(t_atom *a); -EXTERN t_int atom_getint(t_atom *a); -EXTERN t_symbol *atom_getsymbol(t_atom *a); -EXTERN t_symbol *atom_gensym(t_atom *a); -EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv); -EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv); -EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv); - -EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize); - -/* ------------------ binbufs --------------- */ - -EXTERN t_binbuf *binbuf_new(void); -EXTERN void binbuf_free(t_binbuf *x); -EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y); - -EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size); -EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp); -EXTERN void binbuf_clear(t_binbuf *x); -EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv); -EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...); -EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y); -EXTERN void binbuf_addsemi(t_binbuf *x); -EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv); -EXTERN void binbuf_print(t_binbuf *x); -EXTERN int binbuf_getnatom(t_binbuf *x); -EXTERN t_atom *binbuf_getvec(t_binbuf *x); -EXTERN int binbuf_resize(t_binbuf *x, int newsize); -EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv); -EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname, - int crflag); -EXTERN int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas, - int crflag); -EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname, - int crflag); -EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir, - int crflag); -EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir); -EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, - int tonew); - -/* ------------------ clocks --------------- */ - -EXTERN t_clock *clock_new(void *owner, t_method fn); -EXTERN void clock_set(t_clock *x, double systime); -EXTERN void clock_delay(t_clock *x, double delaytime); -EXTERN void clock_unset(t_clock *x); -EXTERN void clock_setunit(t_clock *x, double timeunit, int sampflag); -EXTERN double clock_getlogicaltime(void); -EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */ -EXTERN double clock_gettimesince(double prevsystime); -EXTERN double clock_gettimesincewithunits(double prevsystime, - double units, int sampflag); -EXTERN double clock_getsystimeafter(double delaytime); -EXTERN void clock_free(t_clock *x); - -/* ----------------- pure data ---------------- */ -EXTERN t_pd *pd_new(t_class *cls); -EXTERN void pd_free(t_pd *x); -EXTERN void pd_bind(t_pd *x, t_symbol *s); -EXTERN void pd_unbind(t_pd *x, t_symbol *s); -EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c); -EXTERN void pd_pushsym(t_pd *x); -EXTERN void pd_popsym(t_pd *x); -EXTERN t_symbol *pd_getfilename(void); -EXTERN t_symbol *pd_getdirname(void); -EXTERN void pd_bang(t_pd *x); -EXTERN void pd_pointer(t_pd *x, t_gpointer *gp); -EXTERN void pd_float(t_pd *x, t_float f); -EXTERN void pd_symbol(t_pd *x, t_symbol *s); -EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv); -EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv); -#define pd_class(x) (*(x)) - -/* ----------------- pointers ---------------- */ -EXTERN void gpointer_init(t_gpointer *gp); -EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto); -EXTERN void gpointer_unset(t_gpointer *gp); -EXTERN int gpointer_check(const t_gpointer *gp, int headok); - -/* ----------------- patchable "objects" -------------- */ -EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, - t_symbol *s2); -EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp); -EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp); -EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp); -EXTERN t_inlet *signalinlet_new(t_object *owner, t_float f); -EXTERN void inlet_free(t_inlet *x); - -EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s); -EXTERN void outlet_bang(t_outlet *x); -EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp); -EXTERN void outlet_float(t_outlet *x, t_float f); -EXTERN void outlet_symbol(t_outlet *x, t_symbol *s); -EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv); -EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv); -EXTERN t_symbol *outlet_getsymbol(t_outlet *x); -EXTERN void outlet_free(t_outlet *x); -EXTERN t_object *pd_checkobject(t_pd *x); - - -/* -------------------- canvases -------------- */ - -EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir); - -EXTERN void canvas_setargs(int argc, t_atom *argv); -EXTERN void canvas_getargs(int *argcp, t_atom **argvp); -EXTERN t_symbol *canvas_getcurrentdir(void); -EXTERN t_glist *canvas_getcurrent(void); -EXTERN void canvas_makefilename(t_glist *c, char *file, - char *result,int resultsize); -EXTERN t_symbol *canvas_getdir(t_glist *x); -EXTERN char sys_font[]; /* default typeface set in s_main.c */ -EXTERN char sys_fontweight[]; /* default font weight set in s_main.c */ -EXTERN int sys_fontwidth(int fontsize); -EXTERN int sys_fontheight(int fontsize); -EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b); -EXTERN int canvas_open(t_canvas *x, const char *name, const char *ext, - char *dirresult, char **nameresult, unsigned int size, int bin); - -/* ---------------- widget behaviors ---------------------- */ - -EXTERN_STRUCT _widgetbehavior; -#define t_widgetbehavior struct _widgetbehavior - -EXTERN_STRUCT _parentwidgetbehavior; -#define t_parentwidgetbehavior struct _parentwidgetbehavior -EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x); - -/* -------------------- classes -------------- */ - -#define CLASS_DEFAULT 0 /* flags for new classes below */ -#define CLASS_PD 1 -#define CLASS_GOBJ 2 -#define CLASS_PATCHABLE 3 -#define CLASS_NOINLET 8 - -#define CLASS_TYPEMASK 3 - - -EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod, - t_method freemethod, size_t size, int flags, t_atomtype arg1, ...); -EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s, - t_atomtype type1, ...); -EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel, - t_atomtype arg1, ...); -EXTERN void class_addbang(t_class *c, t_method fn); -EXTERN void class_addpointer(t_class *c, t_method fn); -EXTERN void class_doaddfloat(t_class *c, t_method fn); -EXTERN void class_addsymbol(t_class *c, t_method fn); -EXTERN void class_addlist(t_class *c, t_method fn); -EXTERN void class_addanything(t_class *c, t_method fn); -EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s); -EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w); -EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w); -EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c); -EXTERN char *class_getname(t_class *c); -EXTERN char *class_gethelpname(t_class *c); -EXTERN char *class_gethelpdir(t_class *c); -EXTERN void class_setdrawcommand(t_class *c); -EXTERN int class_isdrawcommand(t_class *c); -EXTERN void class_domainsignalin(t_class *c, int onset); -EXTERN void class_set_extern_dir(t_symbol *s); -#define CLASS_MAINSIGNALIN(c, type, field) \ - class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0) - - /* prototype for functions to save Pd's to a binbuf */ -typedef void (*t_savefn)(t_gobj *x, t_binbuf *b); -EXTERN void class_setsavefn(t_class *c, t_savefn f); -EXTERN t_savefn class_getsavefn(t_class *c); -EXTERN void obj_saveformat(t_object *x, t_binbuf *bb); /* add format to bb */ - - /* prototype for functions to open properties dialogs */ -typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist); -EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f); -EXTERN t_propertiesfn class_getpropertiesfn(t_class *c); - -#ifndef PD_CLASS_DEF -#define class_addbang(x, y) class_addbang((x), (t_method)(y)) -#define class_addpointer(x, y) class_addpointer((x), (t_method)(y)) -#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y)) -#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y)) -#define class_addlist(x, y) class_addlist((x), (t_method)(y)) -#define class_addanything(x, y) class_addanything((x), (t_method)(y)) -#endif - -/* ------------ printing --------------------------------- */ -EXTERN void post(const char *fmt, ...); -EXTERN void startpost(const char *fmt, ...); -EXTERN void poststring(const char *s); -EXTERN void postfloat(t_floatarg f); -EXTERN void postatom(int argc, t_atom *argv); -EXTERN void endpost(void); -EXTERN void error(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); -EXTERN void verbose(int level, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); -EXTERN void bug(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); -EXTERN void pd_error(void *object, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); -EXTERN void logpost(const void *object, const int level, const char *fmt, ...) - ATTRIBUTE_FORMAT_PRINTF(3, 4); -EXTERN void sys_logerror(const char *object, const char *s); -EXTERN void sys_unixerror(const char *object); -EXTERN void sys_ouch(void); - - -/* ------------ system interface routines ------------------- */ -EXTERN int sys_isreadablefile(const char *name); -EXTERN int sys_isabsolutepath(const char *dir); -EXTERN void sys_bashfilename(const char *from, char *to); -EXTERN void sys_unbashfilename(const char *from, char *to); -EXTERN int open_via_path(const char *dir, const char *name, const char *ext, - char *dirresult, char **nameresult, unsigned int size, int bin); -EXTERN int sched_geteventno(void); -EXTERN double sys_getrealtime(void); -EXTERN int (*sys_idlehook)(void); /* hook to add idle time computation */ - -/* Win32's open()/fopen() do not handle UTF-8 filenames so we need - * these internal versions that handle UTF-8 filenames the same across - * all platforms. They are recommended for use in external - * objectclasses as well so they work with Unicode filenames on Windows */ -EXTERN int sys_open(const char *path, int oflag, ...); -EXTERN int sys_close(int fd); -EXTERN FILE *sys_fopen(const char *filename, const char *mode); -EXTERN int sys_fclose(FILE *stream); - -/* ------------ threading ------------------- */ -EXTERN void sys_lock(void); -EXTERN void sys_unlock(void); -EXTERN int sys_trylock(void); - - -/* --------------- signals ----------------------------------- */ - -typedef PD_FLOATTYPE t_sample; -typedef union _sampleint_union { - t_sample f; - PD_FLOATUINTTYPE i; -} t_sampleint_union; -#define MAXLOGSIG 32 -#define MAXSIGSIZE (1 << MAXLOGSIG) - -typedef struct _signal -{ - int s_n; /* number of points in the array */ - t_sample *s_vec; /* the array */ - t_float s_sr; /* sample rate */ - int s_refcount; /* number of times used */ - int s_isborrowed; /* whether we're going to borrow our array */ - struct _signal *s_borrowedfrom; /* signal to borrow it from */ - struct _signal *s_nextfree; /* next in freelist */ - struct _signal *s_nextused; /* next in used list */ - int s_vecsize; /* allocated size of array in points */ -} t_signal; - -typedef t_int *(*t_perfroutine)(t_int *args); - -EXTERN t_int *plus_perform(t_int *args); -EXTERN t_int *zero_perform(t_int *args); -EXTERN t_int *copy_perform(t_int *args); - -EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n); -EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n); -EXTERN void dsp_add_scalarcopy(t_float *in, t_sample *out, int n); -EXTERN void dsp_add_zero(t_sample *out, int n); - -EXTERN int sys_getblksize(void); -EXTERN t_float sys_getsr(void); -EXTERN int sys_get_inchannels(void); -EXTERN int sys_get_outchannels(void); - -EXTERN void dsp_add(t_perfroutine f, int n, ...); -EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec); -EXTERN void pd_fft(t_float *buf, int npoints, int inverse); -EXTERN int ilog2(int n); - -EXTERN void mayer_fht(t_sample *fz, int n); -EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag); -EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag); -EXTERN void mayer_realfft(int n, t_sample *real); -EXTERN void mayer_realifft(int n, t_sample *real); - -EXTERN float *cos_table; -#define LOGCOSTABSIZE 9 -#define COSTABSIZE (1<<LOGCOSTABSIZE) - -EXTERN int canvas_suspend_dsp(void); -EXTERN void canvas_resume_dsp(int oldstate); -EXTERN void canvas_update_dsp(void); -EXTERN int canvas_dspstate; - -/* up/downsampling */ -typedef struct _resample -{ - int method; /* up/downsampling method ID */ - - int downsample; /* downsampling factor */ - int upsample; /* upsampling factor */ - - t_sample *s_vec; /* here we hold the resampled data */ - int s_n; - - t_sample *coeffs; /* coefficients for filtering... */ - int coefsize; - - t_sample *buffer; /* buffer for filtering */ - int bufsize; -} t_resample; - -EXTERN void resample_init(t_resample *x); -EXTERN void resample_free(t_resample *x); - -EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method); -EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method); -EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method); - -/* ----------------------- utility functions for signals -------------- */ -EXTERN t_float mtof(t_float); -EXTERN t_float ftom(t_float); -EXTERN t_float rmstodb(t_float); -EXTERN t_float powtodb(t_float); -EXTERN t_float dbtorms(t_float); -EXTERN t_float dbtopow(t_float); - -EXTERN t_float q8_sqrt(t_float); -EXTERN t_float q8_rsqrt(t_float); -#ifndef N32 -EXTERN t_float qsqrt(t_float); /* old names kept for extern compatibility */ -EXTERN t_float qrsqrt(t_float); -#endif -/* --------------------- data --------------------------------- */ - - /* graphical arrays */ -EXTERN_STRUCT _garray; -#define t_garray struct _garray - -EXTERN t_class *garray_class; -EXTERN int garray_getfloatarray(t_garray *x, int *size, t_float **vec); -EXTERN int garray_getfloatwords(t_garray *x, int *size, t_word **vec); -EXTERN void garray_redraw(t_garray *x); -EXTERN int garray_npoints(t_garray *x); -EXTERN char *garray_vec(t_garray *x); -EXTERN void garray_resize(t_garray *x, t_floatarg f); /* avoid; use this: */ -EXTERN void garray_resize_long(t_garray *x, long n); /* better version */ -EXTERN void garray_usedindsp(t_garray *x); -EXTERN void garray_setsaveit(t_garray *x, int saveit); -EXTERN t_glist *garray_getglist(t_garray *x); -EXTERN t_array *garray_getarray(t_garray *x); -EXTERN t_class *scalar_class; - -EXTERN t_float *value_get(t_symbol *s); -EXTERN void value_release(t_symbol *s); -EXTERN int value_getfloat(t_symbol *s, t_float *f); -EXTERN int value_setfloat(t_symbol *s, t_float f); - -/* ------- GUI interface - functions to send strings to TK --------- */ -typedef void (*t_guicallbackfn)(t_gobj *client, t_glist *glist); - -EXTERN void sys_vgui(char *fmt, ...); -EXTERN void sys_gui(char *s); -EXTERN void sys_pretendguibytes(int n); -EXTERN void sys_queuegui(void *client, t_glist *glist, t_guicallbackfn f); -EXTERN void sys_unqueuegui(void *client); - /* dialog window creation and destruction */ -EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd); -EXTERN void gfxstub_deleteforkey(void *key); - -extern t_class *glob_pdobject; /* object to send "pd" messages */ - -/*------------- Max 0.26 compatibility --------------------*/ - -/* the following reflects the new way classes are laid out, with the class - pointing to the messlist and not vice versa. Externs shouldn't feel it. */ -typedef t_class *t_externclass; - -EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine, - t_method freeroutine, t_symbol *name, size_t size, int tiny, \ - t_atomtype arg1, ...); -EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...); - -#define t_getbytes getbytes -#define t_freebytes freebytes -#define t_resizebytes resizebytes -#define typedmess pd_typedmess -#define vmess pd_vmess - -/* A definition to help gui objects straddle 0.34-0.35 changes. If this is -defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */ - -#define PD_USE_TE_XPIX - -#ifndef _MSC_VER /* Microoft compiler can't handle "inline" function/macros */ -#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) -/* a test for NANs and denormals. Should only be necessary on i386. */ -# if PD_FLOATSIZE == 32 -static inline int PD_BADFLOAT(t_sample f) { - t_sampleint_union u; - u.f=f; - return ((u.i & 0x7f800000)==0) || ((u.i&0x7f800000)==0x7f800000); -} -/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */ -static inline int PD_BIGORSMALL(t_sample f) { - t_sampleint_union u; - u.f=f; - return ((u.i & 0x60000000)==0) || ((u.i & 0x60000000)==0x60000000); -} -# else -# warning 64bit mode: BIGORSMALL not implemented yet -# define PD_BADFLOAT(f) 0 -# define PD_BIGORSMALL(f) 0 -# endif -#else -# define PD_BADFLOAT(f) 0 -# define PD_BIGORSMALL(f) 0 -#endif -#else /* _MSC_VER */ -#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \ - (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000)) -/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */ -#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \ - (((*(unsigned int*)&(f))&0x60000000)==0x60000000)) -#endif /* _MSC_VER */ - /* get version number at run time */ -EXTERN void sys_getversion(int *major, int *minor, int *bugfix); - -EXTERN_STRUCT _pdinstance; -#define t_pdinstance struct _pdinstance /* m_imp.h */ - -/* m_pd.c */ - -EXTERN t_pdinstance *pdinstance_new( void); -EXTERN void pd_setinstance(t_pdinstance *x); -EXTERN void pdinstance_free(t_pdinstance *x); -EXTERN t_canvas *pd_getcanvaslist(void); -EXTERN int pd_getdspstate(void); - -#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) -} -#endif - -#define __m_pd_h_ -#endif /* __m_pd_h_ */
--- a/examples/basic_libpd/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * default_main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ -#include <unistd.h> -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include "../include/Bela.h" - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "h", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, 0) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/basic_libpd/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,403 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <Bela.h> -#include <DigitalChannelManager.h> -#include <cmath> -#include <I2c_Codec.h> -#include <PRU.h> -#include <stdio.h> -#include "z_libpd.h" -#include "s_stuff.h" -#include <UdpServer.h> -#include <Midi.h> -//extern t_sample* sys_soundin; -//extern t_sample* sys_soundout; -// if you are 100% sure of what value was used to compile libpd/puredata, then -// you could #define this instead of getting it at runtime. It has proved to give some 0.3% -// performance boost when it is 8 (thanks to vectorize optimizations I guess). -int gBufLength; - -float* gInBuf; -float* gOutBuf; - -void pdnoteon(int ch, int pitch, int vel) { - printf("noteon: %d %d %d\n", ch, pitch, vel); -} - -void Bela_printHook(const char *recv){ - rt_printf("%s", recv); -} - -void libpdReadFilesLoop(){ - while(!gShouldStop){ - // check for modified sockets/file descriptors - // (libpd would normally do this every block WITHIN the audio thread) - // not sure if this is thread-safe at the moment - libpd_sys_microsleep(0); - usleep(1000); - } -} - -#define PARSE_MIDI -static AuxiliaryTask libpdReadFilesTask; -static Midi midi; -static DigitalChannelManager dcm; -//UdpServer udpServer; - -void sendDigitalMessage(bool state, unsigned int delay, void* receiverName){ - libpd_float((char*)receiverName, (float)state); -// rt_printf("%s: %d\n", (char*)receiverName, state); -} - -#define LIBPD_DIGITAL_OFFSET 11 // digitals are preceded by 2 audio and 8 analogs (even if using a different number of analogs) - -void Bela_messageHook(const char *source, const char *symbol, int argc, t_atom *argv){ - if(strcmp(source, "bela_setDigital") == 0){ - // symbol is the direction, argv[0] is the channel, argv[1] (optional) - // is signal("sig" or "~") or message("message", default) rate - bool isMessageRate = true; // defaults to message rate - bool direction = 0; // initialize it just to avoid the compiler's warning - bool disable = false; - if(strcmp(symbol, "in") == 0){ - direction = INPUT; - } else if(strcmp(symbol, "out") == 0){ - direction = OUTPUT; - } else if(strcmp(symbol, "disable") == 0){ - disable = true; - } else { - return; - } - if(argc == 0){ - return; - } else if (libpd_is_float(&argv[0]) == false){ - return; - } - int channel = libpd_get_float(&argv[0]) - LIBPD_DIGITAL_OFFSET; - if(disable == true){ - dcm.unmanage(channel); - return; - } - if(argc >= 2){ - t_atom* a = &argv[1]; - if(libpd_is_symbol(a)){ - char *s = libpd_get_symbol(a); - if(strcmp(s, "~") == 0 || strncmp(s, "sig", 3) == 0){ - isMessageRate = false; - } - } - } - dcm.manage(channel, direction, isMessageRate); - } -} - -void Bela_floatHook(const char *source, float value){ - // let's make this as optimized as possible for built-in digital Out parsing - // the built-in digital receivers are of the form "bela_digitalOutXX" where XX is between 11 and 26 - static int prefixLength = 15; // strlen("bela_digitalOut") - if(strncmp(source, "bela_digitalOut", prefixLength)==0){ - if(source[prefixLength] != 0){ //the two ifs are used instead of if(strlen(source) >= prefixLength+2) - if(source[prefixLength + 1] != 0){ - // quickly convert the suffix to integer, assuming they are numbers, avoiding to call atoi - int receiver = ((source[prefixLength] - 48) * 10); - receiver += (source[prefixLength+1] - 48); - unsigned int channel = receiver - 11; // go back to the actual Bela digital channel number - if(channel >= 0 && channel < 16){ //16 is the hardcoded value for the number of digital channels - dcm.setValue(channel, value); - } - } - } - } -} - -char receiverNames[16][21]={ - {"bela_digitalIn11"},{"bela_digitalIn12"},{"bela_digitalIn13"},{"bela_digitalIn14"},{"bela_digitalIn15"}, - {"bela_digitalIn16"},{"bela_digitalIn17"},{"bela_digitalIn18"},{"bela_digitalIn19"},{"bela_digitalIn20"}, - {"bela_digitalIn21"},{"bela_digitalIn22"},{"bela_digitalIn23"},{"bela_digitalIn24"},{"bela_digitalIn25"}, - {"bela_digitalIn26"} -}; - -static unsigned int analogChannelsInUse; -static unsigned int gLibpdBlockSize; -static unsigned int gChannelsInUse = 26; - -bool setup(BelaContext *context, void *userData) -{ - dcm.setCallback(sendDigitalMessage); - analogChannelsInUse = min(context->analogChannels, gChannelsInUse - context->audioChannels - context->digitalChannels); - if(context->digitalChannels > 0){ - for(unsigned int ch = 0; ch < context->digitalChannels; ++ch){ - dcm.setCallbackArgument(ch, receiverNames[ch]); - } - } - midi.readFrom(0); - midi.writeTo(0); -#ifdef PARSE_MIDI - midi.enableParser(true); -#else - midi.enableParser(false); -#endif /* PARSE_MIDI */ -// gChannelsInUse = min((int)(context->analogChannels+context->audioChannels), (int)gChannelsInUse); -// udpServer.bindToPort(1234); - - gLibpdBlockSize = libpd_blocksize(); - // check that we are not running with a blocksize smaller than gLibPdBlockSize - // it would still work, but the load would be executed unevenly between calls to render - if(context->audioFrames < gLibpdBlockSize){ - fprintf(stderr, "Error: minimum block size must be %d\n", gLibpdBlockSize); - return false; - } - // set hooks before calling libpd_init - libpd_set_printhook(Bela_printHook); - libpd_set_floathook(Bela_floatHook); - libpd_set_messagehook(Bela_messageHook); - libpd_set_noteonhook(pdnoteon); - //TODO: add hooks for other midi events and generate MIDI output appropriately - libpd_init(); - //TODO: ideally, we would analyse the ASCII of the patch file and find out which in/outs to use - libpd_init_audio(gChannelsInUse, gChannelsInUse, context->audioSampleRate); - gInBuf = libpd_get_sys_soundin(); - gOutBuf = libpd_get_sys_soundout(); - - libpd_start_message(1); // one entry in list - libpd_add_float(1.0f); - libpd_finish_message("pd", "dsp"); - - gBufLength = max(gLibpdBlockSize, context->audioFrames); - - - // bind your receivers here - libpd_bind("bela_digitalOut11"); - libpd_bind("bela_digitalOut12"); - libpd_bind("bela_digitalOut13"); - libpd_bind("bela_digitalOut14"); - libpd_bind("bela_digitalOut15"); - libpd_bind("bela_digitalOut16"); - libpd_bind("bela_digitalOut17"); - libpd_bind("bela_digitalOut18"); - libpd_bind("bela_digitalOut19"); - libpd_bind("bela_digitalOut20"); - libpd_bind("bela_digitalOut21"); - libpd_bind("bela_digitalOut22"); - libpd_bind("bela_digitalOut23"); - libpd_bind("bela_digitalOut24"); - libpd_bind("bela_digitalOut25"); - libpd_bind("bela_digitalOut26"); - libpd_bind("bela_setDigital"); - - char file[] = "_main.pd"; - char folder[] = "./"; - // open patch [; pd open file folder( - libpd_openfile(file, folder); - libpdReadFilesTask = Bela_createAuxiliaryTask(libpdReadFilesLoop, 60, "libpdReadFiles"); - Bela_scheduleAuxiliaryTask(libpdReadFilesTask); - - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - int num; - // the safest thread-safe option to handle MIDI input is to process the MIDI buffer - // from the audio thread. -#ifdef PARSE_MIDI - while((num = midi.getParser()->numAvailableMessages()) > 0){ - static MidiChannelMessage message; - message = midi.getParser()->getNextChannelMessage(); - //message.prettyPrint(); // use this to print beautified message (channel, data bytes) - switch(message.getType()){ - case kmmNoteOn: - { - int noteNumber = message.getDataByte(0); - int velocity = message.getDataByte(1); - int channel = message.getChannel(); - libpd_noteon(channel, noteNumber, velocity); - break; - } - case kmmNoteOff: - { - /* PureData does not seem to handle noteoff messages as per the MIDI specs, - * so that the noteoff velocity is ignored. Here we convert them to noteon - * with a velocity of 0. - */ - int noteNumber = message.getDataByte(0); -// int velocity = message.getDataByte(1); // would be ignored by Pd - int channel = message.getChannel(); - libpd_noteon(channel, noteNumber, 0); - break; - } - case kmmControlChange: - { - int channel = message.getChannel(); - int controller = message.getDataByte(0); - int value = message.getDataByte(1); - libpd_controlchange(channel, controller, value); - break; - } - case kmmProgramChange: - { - int channel = message.getChannel(); - int program = message.getDataByte(0); - libpd_programchange(channel, program); - break; - } - case kmmPolyphonicKeyPressure: - { - int channel = message.getChannel(); - int pitch = message.getDataByte(0); - int value = message.getDataByte(1); - libpd_polyaftertouch(channel, pitch, value); - break; - } - case kmmChannelPressure: - { - int channel = message.getChannel(); - int value = message.getDataByte(0); - libpd_aftertouch(channel, value); - break; - } - case kmmPitchBend: - { - int channel = message.getChannel(); - int value = (message.getDataByte(1) << 7)| message.getDataByte(0); - libpd_pitchbend(channel, value); - break; - } - case kmmNone: - case kmmAny: - break; - } - } -#else - int input; - while((input = midi.getInput()) >= 0){ - libpd_midibyte(0, input); - } -#endif /* PARSE_MIDI */ - - static unsigned int numberOfPdBlocksToProcess = gBufLength / gLibpdBlockSize; - - // these are reset at every audio callback. Persistence across audio callbacks - // is handled by the core code. -// setDataOut = 0; -// clearDataOut = 0; - - for(unsigned int tick = 0; tick < numberOfPdBlocksToProcess; ++tick){ - unsigned int audioFrameBase = gLibpdBlockSize * tick; - unsigned int j; - unsigned int k; - float* p0; - float* p1; - for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { - for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { - *p1 = audioRead(context, audioFrameBase + j, k); - } - } - // then analogs - // this loop resamples by ZOH, as needed, using m - if(context->analogChannels == 8 ){ //hold the value for two frames - for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { - for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { - unsigned int analogFrame = (audioFrameBase + j) / 2; - *p1 = analogRead(context, analogFrame, k); - } - } - } else if(context->analogChannels == 4){ //write every frame - for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { - for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { - unsigned int analogFrame = audioFrameBase + j; - *p1 = analogRead(context, analogFrame, k); - } - } - } else if(context->analogChannels == 2){ //drop every other frame - for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { - for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { - unsigned int analogFrame = (audioFrameBase + j) * 2; - *p1 = analogRead(context, analogFrame, k); - } - } - } - - //then digital - // note: in multiple places below we assume that the number of digitals is same as number of audio - // digital in at message-rate - dcm.processInput(&context->digital[audioFrameBase], gLibpdBlockSize); - - // digital in at signal-rate - for (j = 0, p0 = gInBuf; j < gLibpdBlockSize; j++, p0++) { - unsigned int digitalFrame = audioFrameBase + j; - for (k = 0, p1 = p0 + gLibpdBlockSize * (context->audioChannels + 8); - k < 16; ++k, p1 += gLibpdBlockSize) { - if(dcm.isSignalRate(k) && dcm.isInput(k)){ // only process input channels that are handled at signal rate - *p1 = digitalRead(context, digitalFrame, k); - } - } - } - - libpd_process_sys(); // process the block - - //digital out - // digital out at signal-rate - for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) { - unsigned int digitalFrame = (audioFrameBase + j); - for (k = 0, p1 = p0 + gLibpdBlockSize * (context->audioChannels + 8); - k < context->digitalChannels; k++, p1 += gLibpdBlockSize) { - if(dcm.isSignalRate(k) && dcm.isOutput(k)){ // only process output channels that are handled at signal rate - digitalWriteOnce(context, digitalFrame, k, *p1 > 0.5); - } - } - } - - // digital out at message-rate - dcm.processOutput(&context->digital[audioFrameBase], gLibpdBlockSize); - - //audio - for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { - for (k = 0, p1 = p0; k < context->audioChannels; k++, p1 += gLibpdBlockSize) { - audioWrite(context, audioFrameBase + j, k, *p1); - } - } - - //analog - if(context->analogChannels == 8){ - for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j += 2, p0 += 2) { //write every two frames - unsigned int analogFrame = (audioFrameBase + j) / 2; - for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { - analogWriteOnce(context, analogFrame, k, *p1); - } - } - } else if(context->analogChannels == 4){ //write every frame - for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; ++j, ++p0) { - unsigned int analogFrame = (audioFrameBase + j); - for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { - analogWriteOnce(context, analogFrame, k, *p1); - } - } - } else if(context->analogChannels == 2){ //write every frame twice - for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j++, p0++) { - for (k = 0, p1 = p0 + gLibpdBlockSize * context->audioChannels; k < analogChannelsInUse; k++, p1 += gLibpdBlockSize) { - int analogFrame = audioFrameBase * 2 + j * 2; - analogWriteOnce(context, analogFrame, k, *p1); - analogWriteOnce(context, analogFrame + 1, k, *p1); - } - } - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ -}
--- a/examples/basic_libpd/s_stuff.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,411 +0,0 @@ -/* Copyright (c) 1997-1999 Miller Puckette. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* Audio and MIDI I/O, and other scheduling and system stuff. */ - -/* NOTE: this file describes Pd implementation details which may change -in future releases. The public (stable) API is in m_pd.h. */ - -/* in s_path.c */ - -typedef struct _namelist /* element in a linked list of stored strings */ -{ - struct _namelist *nl_next; /* next in list */ - char *nl_string; /* the string */ -} t_namelist; - -t_namelist *namelist_append(t_namelist *listwas, const char *s, int allowdup); -t_namelist *namelist_append_files(t_namelist *listwas, const char *s); -void namelist_free(t_namelist *listwas); -char *namelist_get(t_namelist *namelist, int n); -void sys_setextrapath(const char *p); -extern int sys_usestdpath; -extern t_namelist *sys_externlist; -extern t_namelist *sys_searchpath; -extern t_namelist *sys_helppath; -int sys_open_absolute(const char *name, const char* ext, - char *dirresult, char **nameresult, unsigned int size, int bin, int *fdp); -int sys_trytoopenone(const char *dir, const char *name, const char* ext, - char *dirresult, char **nameresult, unsigned int size, int bin); -t_symbol *sys_decodedialog(t_symbol *s); - -/* s_file.c */ - -void sys_loadpreferences( void); -void sys_savepreferences( void); -extern int sys_defeatrt; -extern t_symbol *sys_flags; - -/* s_main.c */ -extern int sys_debuglevel; -extern int sys_verbose; -extern int sys_noloadbang; -extern int sys_nogui; -extern char *sys_guicmd; - -EXTERN int sys_nearestfontsize(int fontsize); -EXTERN int sys_hostfontsize(int fontsize); - -extern int sys_defaultfont; -EXTERN t_symbol *sys_libdir; /* library directory for auxilliary files */ -extern t_symbol *sys_guidir; /* directory holding pd_gui, u_pdsend, etc */ - -/* s_loader.c */ - -typedef int (*loader_t)(t_canvas *canvas, char *classname); /* callback type */ -EXTERN int sys_load_lib(t_canvas *canvas, char *filename); -EXTERN void sys_register_loader(loader_t loader); - -/* s_audio.c */ - -#define SENDDACS_NO 0 /* return values for sys_send_dacs() */ -#define SENDDACS_YES 1 -#define SENDDACS_SLEPT 2 - -#define DEFDACBLKSIZE 8 -extern int sys_schedblocksize; /* audio block size for scheduler */ -extern int sys_hipriority; /* real-time flag, true if priority boosted */ -EXTERN t_sample *sys_soundout; -EXTERN t_sample *sys_soundin; -extern int sys_inchannels; -extern int sys_outchannels; -extern int sys_advance_samples; /* scheduler advance in samples */ -extern int sys_blocksize; /* audio I/O block size in sample frames */ -extern t_float sys_dacsr; -extern int sys_schedadvance; -extern int sys_sleepgrain; -EXTERN void sys_set_audio_settings(int naudioindev, int *audioindev, - int nchindev, int *chindev, - int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, - int srate, int advance, int callback, int blocksize); -/* the same as above, but reopens the audio subsystem if needed */ -EXTERN void sys_set_audio_settings_reopen(int naudioindev, int *audioindev, - int nchindev, int *chindev, - int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, - int srate, int advance, int callback, int blocksize); -EXTERN void sys_reopen_audio( void); -EXTERN void sys_close_audio(void); - /* return true if the interface prefers always being open (ala jack) : */ -EXTERN int audio_shouldkeepopen( void); -EXTERN int audio_isopen( void); /* true if audio interface is open */ -EXTERN int sys_audiodevnametonumber(int output, const char *name); -EXTERN void sys_audiodevnumbertoname(int output, int devno, char *name, - int namesize); - -int sys_send_dacs(void); -void sys_reportidle(void); -void sys_set_priority(int higher); -void sys_audiobuf(int nbufs); -void sys_getmeters(t_sample *inmax, t_sample *outmax); -void sys_listdevs(void); -void sys_setblocksize(int n); - -EXTERN void sys_get_audio_devs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int *canmulti, int *cancallback, - int maxndev, int devdescsize); -EXTERN void sys_get_audio_apis(char *buf); - -/* s_midi.c */ -#define MAXMIDIINDEV 16 /* max. number of input ports */ -#define MAXMIDIOUTDEV 16 /* max. number of output ports */ -extern int sys_midiapi; -extern int sys_nmidiin; -extern int sys_nmidiout; -extern int sys_midiindevlist[]; -extern int sys_midioutdevlist[]; - -EXTERN void sys_open_midi(int nmidiin, int *midiinvec, - int nmidiout, int *midioutvec, int enable); - -EXTERN void sys_get_midi_apis(char *buf); -EXTERN void sys_get_midi_devs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, - int maxndev, int devdescsize); -EXTERN void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, - int *pnmidioutdev, int *pmidioutdev); -EXTERN int sys_mididevnametonumber(int output, const char *name); -EXTERN void sys_mididevnumbertoname(int output, int devno, char *name, - int namesize); - -EXTERN void sys_reopen_midi( void); -EXTERN void sys_close_midi( void); -EXTERN void sys_putmidimess(int portno, int a, int b, int c); -EXTERN void sys_putmidibyte(int portno, int a); -EXTERN void sys_poll_midi(void); -EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime); -EXTERN void sys_midibytein(int portno, int byte); - - /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */ -void midi_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int maxndev, int devdescsize); -void sys_do_open_midi(int nmidiindev, int *midiindev, - int nmidioutdev, int *midioutdev); - -#ifdef USEAPI_ALSA -EXTERN void sys_alsa_putmidimess(int portno, int a, int b, int c); -EXTERN void sys_alsa_putmidibyte(int portno, int a); -EXTERN void sys_alsa_poll_midi(void); -EXTERN void sys_alsa_setmiditimediff(double inbuftime, double outbuftime); -EXTERN void sys_alsa_midibytein(int portno, int byte); -EXTERN void sys_alsa_close_midi( void); - - - /* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */ -void midi_alsa_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int maxndev, int devdescsize); -void sys_alsa_do_open_midi(int nmidiindev, int *midiindev, - int nmidioutdev, int *midioutdev); -#endif - -/* m_sched.c */ -EXTERN void sys_log_error(int type); -#define ERR_NOTHING 0 -#define ERR_ADCSLEPT 1 -#define ERR_DACSLEPT 2 -#define ERR_RESYNC 3 -#define ERR_DATALATE 4 - -#define SCHED_AUDIO_NONE 0 -#define SCHED_AUDIO_POLL 1 -#define SCHED_AUDIO_CALLBACK 2 -void sched_set_using_audio(int flag); - -/* s_inter.c */ - -EXTERN void sys_microsleep(int microsec); -EXTERN void sys_init_fdpoll(void); - -EXTERN void sys_bail(int exitcode); -EXTERN int sys_pollgui(void); - -EXTERN_STRUCT _socketreceiver; -#define t_socketreceiver struct _socketreceiver - -typedef void (*t_socketnotifier)(void *x, int n); -typedef void (*t_socketreceivefn)(void *x, t_binbuf *b); - -EXTERN t_socketreceiver *socketreceiver_new(void *owner, - t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp); -EXTERN void socketreceiver_read(t_socketreceiver *x, int fd); -EXTERN void sys_sockerror(char *s); -EXTERN void sys_closesocket(int fd); - -typedef void (*t_fdpollfn)(void *ptr, int fd); -EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr); -EXTERN void sys_rmpollfn(int fd); -#if defined(USEAPI_OSS) || defined(USEAPI_ALSA) -void sys_setalarm(int microsec); -#endif - -#define API_NONE 0 -#define API_ALSA 1 -#define API_OSS 2 -#define API_MMIO 3 -#define API_PORTAUDIO 4 -#define API_JACK 5 -#define API_SGI 6 /* gone */ -#define API_AUDIOUNIT 7 -#define API_ESD 8 /* no idea what this was, probably gone now */ -#define API_DUMMY 9 - - /* figure out which API should be the default. The one we judge most - likely to offer a working device takes precedence so that if you - start up Pd for the first time there's a reasonable chance you'll have - sound. (You'd think portaudio would be best but it seems to default - to jack on linux, and and on Windows we only use it for ASIO). - If nobody shows up, define DUMMY and make it the default.*/ -#if defined(USEAPI_MMIO) -# define API_DEFAULT API_MMIO -# define API_DEFSTRING "MMIO" -#elif defined(USEAPI_ALSA) -# define API_DEFAULT API_ALSA -# define API_DEFSTRING "ALSA" -#elif defined(USEAPI_OSS) -# define API_DEFAULT API_OSS -# define API_DEFSTRING "OSS" -#elif defined(USEAPI_AUDIOUNIT) -# define API_DEFAULT API_AUDIOUNIT -# define API_DEFSTRING "AudioUnit" -#elif defined(USEAPI_ESD) -# define API_DEFAULT API_ESD -# define API_DEFSTRING "ESD (?)" -#elif defined(USEAPI_PORTAUDIO) -# define API_DEFAULT API_PORTAUDIO -# define API_DEFSTRING "portaudio" -#elif defined(USEAPI_JACK) -# define API_DEFAULT API_JACK -# define API_DEFSTRING "Jack audio connection kit" -#else -# ifndef USEAPI_DUMMY /* we need at least one so bring in the dummy */ -# define USEAPI_DUMMY -# endif /* USEAPI_DUMMY */ -# define API_DEFAULT API_DUMMY -# define API_DEFSTRING "dummy audio" -#endif - -#define DEFAULTAUDIODEV 0 - -#define MAXAUDIOINDEV 4 -#define MAXAUDIOOUTDEV 4 - -#define DEFMIDIDEV 0 - -#define DEFAULTSRATE 44100 -#ifdef _WIN32 -#define DEFAULTADVANCE 80 -#else -#ifdef __APPLE__ -#define DEFAULTADVANCE 5 /* this is in addition to their own delay */ -#else -#define DEFAULTADVANCE 25 -#endif -#endif - -typedef void (*t_audiocallback)(void); - -int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, - t_sample *soundout, int framesperbuf, int nbuffers, - int indeviceno, int outdeviceno, t_audiocallback callback); -void pa_close_audio(void); -int pa_send_dacs(void); -void sys_reportidle(void); -void pa_listdevs(void); -void pa_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int *canmulti, - int maxndev, int devdescsize); - -int oss_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate, int blocksize); -void oss_close_audio(void); -int oss_send_dacs(void); -void oss_reportidle(void); -void oss_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int *canmulti, - int maxndev, int devdescsize); - -int alsa_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate, int blocksize); -void alsa_close_audio(void); -int alsa_send_dacs(void); -void alsa_reportidle(void); -void alsa_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int *canmulti, - int maxndev, int devdescsize); - -int jack_open_audio(int wantinchans, int wantoutchans, int srate, - t_audiocallback callback); -void jack_close_audio(void); -int jack_send_dacs(void); -void jack_reportidle(void); -void jack_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int *canmulti, - int maxndev, int devdescsize); -void jack_listdevs(void); - -int mmio_open_audio(int naudioindev, int *audioindev, - int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, - int nchoutdev, int *choutdev, int rate, int blocksize); -void mmio_close_audio( void); -void mmio_reportidle(void); -int mmio_send_dacs(void); -void mmio_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int *canmulti, - int maxndev, int devdescsize); - -int audiounit_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate); -void audiounit_close_audio(void); -int audiounit_send_dacs(void); -void audiounit_listdevs(void); -void audiounit_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int *canmulti, - int maxndev, int devdescsize); - -int esd_open_audio(int naudioindev, int *audioindev, int nchindev, - int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate); -void esd_close_audio(void); -int esd_send_dacs(void); -void esd_listdevs(void); -void esd_getdevs(char *indevlist, int *nindevs, - char *outdevlist, int *noutdevs, int *canmulti, - int maxndev, int devdescsize); - -int dummy_open_audio(int nin, int nout, int sr); -int dummy_close_audio( void); -int dummy_send_dacs( void); -void dummy_getdevs(char *indevlist, int *nindevs, char *outdevlist, - int *noutdevs, int *canmulti, int maxndev, int devdescsize); -void dummy_listdevs( void); - -void sys_listmididevs(void); -EXTERN void sys_set_midi_api(int whichapi); -EXTERN void sys_set_audio_api(int whichapi); -EXTERN int sys_audioapi; -EXTERN void sys_set_audio_state(int onoff); - -/* API dependent audio flags and settings */ -void oss_set32bit( void); -void linux_alsa_devname(char *devname); - -EXTERN void sys_get_audio_params( - int *pnaudioindev, int *paudioindev, int *chindev, - int *pnaudiooutdev, int *paudiooutdev, int *choutdev, - int *prate, int *padvance, int *callback, int *blocksize); -void sys_save_audio_params( - int naudioindev, int *audioindev, int *chindev, - int naudiooutdev, int *audiooutdev, int *choutdev, - int rate, int advance, int callback, int blocksize); - -/* s_file.c */ - -typedef void (*t_printhook)(const char *s); -extern t_printhook sys_printhook; /* set this to override printing */ -extern int sys_printtostderr; - -/* jsarlo { */ - -EXTERN double sys_time; -EXTERN double sys_time_per_dsp_tick; -EXTERN int sys_externalschedlib; - -EXTERN t_sample* get_sys_soundout(void ) ; -EXTERN t_sample* get_sys_soundin(void ) ; -EXTERN int* get_sys_main_advance(void ) ; -EXTERN double* get_sys_time_per_dsp_tick(void ) ; -EXTERN int* get_sys_schedblocksize(void ) ; -EXTERN double* get_sys_time(void ) ; -EXTERN t_float* get_sys_dacsr(void ) ; -EXTERN int* get_sys_sleepgrain(void ) ; -EXTERN int* get_sys_schedadvance(void ) ; - -EXTERN void sys_clearhist(void ); -EXTERN void sys_initmidiqueue(void ); -EXTERN int sys_addhist(int phase); -EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime); -EXTERN void sched_tick( void); -EXTERN void sys_pollmidiqueue(void ); -EXTERN int sys_pollgui(void ); -EXTERN void sys_setchsr(int chin, int chout, int sr); - -EXTERN void inmidi_realtimein(int portno, int cmd); -EXTERN void inmidi_byte(int portno, int byte); -EXTERN void inmidi_sysex(int portno, int byte); -EXTERN void inmidi_noteon(int portno, int channel, int pitch, int velo); -EXTERN void inmidi_controlchange(int portno, - int channel, - int ctlnumber, - int value); -EXTERN void inmidi_programchange(int portno, int channel, int value); -EXTERN void inmidi_pitchbend(int portno, int channel, int value); -EXTERN void inmidi_aftertouch(int portno, int channel, int value); -EXTERN void inmidi_polyaftertouch(int portno, - int channel, - int pitch, - int value); -/* } jsarlo */ -extern t_widgetbehavior text_widgetbehavior;
--- a/examples/basic_libpd/z_libpd.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2010 Peter Brinkmann (peter.brinkmann@gmail.com) - * - * For information on usage and redistribution, and for a DISCLAIMER OF ALL - * WARRANTIES, see the file, "LICENSE.txt," in this distribution. - * - * See https://github.com/libpd/libpd/wiki for documentation - * - */ - -#ifndef __Z_LIBPD_H__ -#define __Z_LIBPD_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "m_pd.h" - -EXTERN int libpd_init(void); -EXTERN void libpd_clear_search_path(void); -EXTERN void libpd_add_to_search_path(const char *sym); - -EXTERN void *libpd_openfile(const char *basename, const char *dirname); -EXTERN void libpd_closefile(void *p); -EXTERN int libpd_getdollarzero(void *p); - -EXTERN int libpd_blocksize(void); -EXTERN int libpd_init_audio(int inChans, int outChans, int sampleRate); -EXTERN int libpd_process_raw(const float *inBuffer, float *outBuffer); -EXTERN t_sample* libpd_get_sys_soundin(); -EXTERN t_sample* libpd_get_sys_soundout(); -EXTERN int libpd_process_sys(); -EXTERN int libpd_process_short(const int ticks, - const short *inBuffer, short *outBuffer); -EXTERN int libpd_process_float(int ticks, - const float *inBuffer, float *outBuffer); -EXTERN int libpd_process_double(int ticks, - const double *inBuffer, double *outBuffer); - -EXTERN int libpd_arraysize(const char *name); -// The parameters of the next two functions are inspired by memcpy. -EXTERN int libpd_read_array(float *dest, const char *src, int offset, int n); -EXTERN int libpd_write_array(const char *dest, int offset, float *src, int n); - -EXTERN int libpd_bang(const char *recv); -EXTERN int libpd_float(const char *recv, float x); -EXTERN int libpd_symbol(const char *recv, const char *sym); - -EXTERN void libpd_set_float(t_atom *v, float x); -EXTERN void libpd_set_symbol(t_atom *v, const char *sym); -EXTERN int libpd_list(const char *recv, int argc, t_atom *argv); -EXTERN int libpd_message(const char *recv, const char *msg, int argc, t_atom *argv); - -EXTERN int libpd_start_message(int max_length); -EXTERN void libpd_add_float(float x); -EXTERN void libpd_add_symbol(const char *sym); -EXTERN int libpd_finish_list(const char *recv); -EXTERN int libpd_finish_message(const char *recv, const char *msg); - -EXTERN int libpd_exists(const char *sym); -EXTERN void *libpd_bind(const char *sym); -EXTERN void libpd_unbind(void *p); - -EXTERN int libpd_is_float(t_atom *a); -EXTERN int libpd_is_symbol(t_atom *a); -EXTERN float libpd_get_float(t_atom *a); -EXTERN char *libpd_get_symbol(t_atom *a); -EXTERN t_atom *libpd_next_atom(t_atom *a); - -typedef void (*t_libpd_printhook)(const char *recv); -typedef void (*t_libpd_banghook)(const char *recv); -typedef void (*t_libpd_floathook)(const char *recv, float x); -typedef void (*t_libpd_symbolhook)(const char *recv, const char *sym); -typedef void (*t_libpd_listhook)(const char *recv, int argc, t_atom *argv); -typedef void (*t_libpd_messagehook)(const char *recv, const char *msg, - int argc, t_atom *argv); - -EXTERN void libpd_set_printhook(const t_libpd_printhook hook); -EXTERN void libpd_set_banghook(const t_libpd_banghook hook); -EXTERN void libpd_set_floathook(const t_libpd_floathook hook); -EXTERN void libpd_set_symbolhook(const t_libpd_symbolhook hook); -EXTERN void libpd_set_listhook(const t_libpd_listhook hook); -EXTERN void libpd_set_messagehook(const t_libpd_messagehook hook); - -EXTERN int libpd_noteon(int channel, int pitch, int velocity); -EXTERN int libpd_controlchange(int channel, int controller, int value); -EXTERN int libpd_programchange(int channel, int value); -EXTERN int libpd_pitchbend(int channel, int value); -EXTERN int libpd_aftertouch(int channel, int value); -EXTERN int libpd_polyaftertouch(int channel, int pitch, int value); -EXTERN int libpd_midibyte(int port, int byte); -EXTERN int libpd_sysex(int port, int byte); -EXTERN int libpd_sysrealtime(int port, int byte); - -typedef void (*t_libpd_noteonhook)(int channel, int pitch, int velocity); -typedef void (*t_libpd_controlchangehook)(int channel, - int controller, int value); -typedef void (*t_libpd_programchangehook)(int channel, int value); -typedef void (*t_libpd_pitchbendhook)(int channel, int value); -typedef void (*t_libpd_aftertouchhook)(int channel, int value); -typedef void (*t_libpd_polyaftertouchhook)(int channel, int pitch, int value); -typedef void (*t_libpd_midibytehook)(int port, int byte); - -EXTERN void libpd_set_noteonhook(const t_libpd_noteonhook hook); -EXTERN void libpd_set_controlchangehook(const t_libpd_controlchangehook hook); -EXTERN void libpd_set_programchangehook(const t_libpd_programchangehook hook); -EXTERN void libpd_set_pitchbendhook(const t_libpd_pitchbendhook hook); -EXTERN void libpd_set_aftertouchhook(const t_libpd_aftertouchhook hook); -EXTERN void libpd_set_polyaftertouchhook(const t_libpd_polyaftertouchhook hook); -EXTERN void libpd_set_midibytehook(const t_libpd_midibytehook hook); -EXTERN void libpd_sys_microsleep(int sleep); - -#ifdef __cplusplus -} -#endif - -#endif
--- a/examples/basic_midi/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <Bela.h> -#include <Midi.h> -#include <stdlib.h> -#include <rtdk.h> -#include <cmath> - -float gFreq; -float gPhaseIncrement = 0; -bool gIsNoteOn = 0; -int gVelocity = 0; -float gSamplingPeriod = 0; - -void midiMessageCallback(MidiChannelMessage message, void* arg){ - if(arg != NULL){ - rt_printf("Message from midi port %d: ", *(int*)arg); - } - message.prettyPrint(); - if(message.getType() == kmmNoteOn){ - gFreq = powf(2, (message.getDataByte(0)-69)/12.0f) * 440; - gVelocity = message.getDataByte(1); - gPhaseIncrement = 2 * M_PI * gFreq * gSamplingPeriod; - gIsNoteOn = gVelocity > 0; - rt_printf("v0:%f, ph: %6.5f, gVelocity: %d\n", gFreq, gPhaseIncrement, gVelocity); - } -} -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. -Midi midi; -int gMidiPort0 = 0; -bool setup(BelaContext *context, void *userData) -{ - midi.readFrom(gMidiPort0); - midi.writeTo(gMidiPort0); - midi.enableParser(true); - midi.setParserCallback(midiMessageCallback, &gMidiPort0); - if(context->analogFrames == 0) { - rt_printf("Error: this example needs the analog I/O to be enabled\n"); - return false; - } - gSamplingPeriod = 1/context->audioSampleRate; - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - - -enum {kVelocity, kNoteOn, kNoteNumber}; -void render(BelaContext *context, void *userData) -{ -// one way of getting the midi data is to parse them yourself -// (you should set midi.enableParser(false) above): -/* - static midi_byte_t noteOnStatus = 0x90; //on channel 1 - static int noteNumber = 0; - static int waitingFor = kNoteOn; - static int playingNote = -1; - int message; - while ((message = midi.getInput()) >= 0){ - rt_printf("%d\n", message); - switch(waitingFor){ - case kNoteOn: - if(message == noteOnStatus){ - waitingFor = kNoteNumber; - } - break; - case kNoteNumber: - if((message & (1<<8)) == 0){ - noteNumber = message; - waitingFor = kVelocity; - } - break; - case kVelocity: - if((message & (1<<8)) == 0){ - int _velocity = message; - waitingFor = kNoteOn; - // "monophonic" behaviour, with priority to the latest note on - // i.e.: a note off from a previous note does not stop the current note - // still you might end up having a key down and no note being played if you pressed and released another - // key in the meantime - if(_velocity == 0 && noteNumber == playingNote){ - noteOn = false; - playingNote = -1; - velocity = _velocity; - } else if (_velocity > 0) { - noteOn = true; - velocity = _velocity; - playingNote = noteNumber; - f0 = powf(2, (playingNote-69)/12.0f) * 440; - phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate; - } - rt_printf("NoteOn: %d, NoteNumber: %d, velocity: %d\n", noteOn, noteNumber, velocity); - } - break; - } - } -*/ - /* - int num; - //alternatively, you can use the built-in parser (only processes channel messages at the moment). - while((num = midi.getParser()->numAvailableMessages()) > 0){ - static MidiChannelMessage message; - message = midi.getParser()->getNextChannelMessage(); - message.prettyPrint(); - if(message.getType() == kmmNoteOn){ - f0 = powf(2, (message.getDataByte(0)-69)/12.0f) * 440; - velocity = message.getDataByte(1); - phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate; - noteOn = velocity > 0; - rt_printf("v0:%f, ph: %6.5f, velocity: %d\n", f0, phaseIncrement, gVelocity); - } - } - */ - // the following block toggles the LED on an Owl pedal - // and asks the pedal to return the status of the LED - // using MIDI control changes - for(unsigned int n = 0; n < context->analogFrames; n++){ - static int count = 0; - static bool state = 0; - analogWriteOnce(context, n, 1, state); - if(count % 40000 == 0){ - state = !state; - midi_byte_t bytes[6] = {176, 30, (char)(state*127), 176, 67, 30}; // toggle the OWL led and ask for the led status - midi.writeOutput(bytes, 6); - } - count++; - } - for(unsigned int n = 0; n < context->audioFrames; n++){ - if(gIsNoteOn == 1){ - static float phase = 0; - phase += gPhaseIncrement; - if(phase > 2 * M_PI) - phase -= 2 * M_PI; - float value = sinf(phase) * gVelocity/128.0f; - audioWrite(context, n, 0, value); - audioWrite(context, n, 1, value); - } else { - audioWrite(context, n, 0, 0); - audioWrite(context, n, 1, 0); - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/basic_network/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <unistd.h> -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - float frequency = 440.0; // Frequency of oscillator - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"frequency", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - frequency = atof(optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &frequency) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/basic_passthru/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "h", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, 0) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/basic_passthru/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - - /* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -/** -\example 1_basic_audio_analog_passthrough - -Audio and analog passthrough: input to output ------------------------------------------ - -This sketch demonstrates how to read from and write to the audio and analog input and output buffers. - -In `render()` you'll see a nested for loop structure. You'll see this in all Bela projects. -The first for loop cycles through `audioFrames`, the second through -`audioChannels` (in this case left 0 and right 1). - -You can access any information about current audio and sensor settings you can do the following: -`context->name_of_item`. For example `context->audioChannels` returns current number of channels, -`context->audioFrames` returns the current number of audio frames, -`context->audioSampleRate` returns the audio sample rate. - -You can look at all the information you can access in ::BeagleRTContext. - -Reading and writing from the audio buffers ------------------------------------------- - -The simplest way to read samples from the audio input buffer is with -`audioRead()` which we pass three arguments: context, current audio -frame and current channel. In this example we have -`audioRead(context, n, ch)` where both `n` and `ch` are provided by -the nested for loop structure. - -We can write samples to the audio output buffer in a similar way using -`audioWrite()`. This has a fourth argument which is the value of the output. -For example `audioWrite(context, n, ch, value_to_output)`. - -Reading and writing from the analog buffers -------------------------------------------- - -The same is true for `analogRead()` and `analogWrite()`. - -Note that for the analog channels we write to and read from the buffers in a separate set -of nested for loops. This is because the they are sampled at half audio rate by default. -The first of these for loops cycles through `analogFrames`, the second through -`analogChannels`. - -By setting `audioWriteFrame(context, n, ch, audioReadFrame(context, n, ch))` and -`analogWrite(context, n, ch, analogReadFrame(context, n, ch))` we have a simple -passthrough of audio input to output and analog input to output. - - -It is also possible to address the buffers directly, for example: -`context->audioOut[n * context->audioChannels + ch]`. -*/ - -#include <Bela.h> -#include <rtdk.h> - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - // Nothing to do here... - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - // Simplest possible case: pass inputs through to outputs - for(unsigned int n = 0; n < context->audioFrames; n++) { - for(unsigned int ch = 0; ch < context->audioChannels; ch++){ - // Two equivalent ways to write this code - - // The long way, using the buffers directly: - // context->audioOut[n * context->audioChannels + ch] = - // context->audioIn[n * context->audioChannels + ch]; - - // Or using the macros: - audioWrite(context, n, ch, audioRead(context, n, ch)); - } - } - - // Same with analog channelss - for(unsigned int n = 0; n < context->analogFrames; n++) { - for(unsigned int ch = 0; ch < context->analogChannels; ch++) { - // Two equivalent ways to write this code - - // The long way, using the buffers directly: - // context->analogOut[n * context->analogChannels + ch] = context->analogIn[n * context->analogChannels + ch]; - - // Or using the macros: - analogWrite(context, n, ch, analogRead(context, n, ch)); - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/basic_pulseIn/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <Bela.h> -#include <PulseIn.h> -#include <stdlib.h> -#include <rtdk.h> -#include <cmath> - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. -PulseIn pulseIn; -int gPulseInPin = 0; -int gDigitalOutPin = 1; -int gPulseLength = 1234; -int gSamplesBetweenPulses = 10000; - -bool setup(BelaContext *context, void *userData) -{ - pinMode(context, 0, gDigitalOutPin, OUTPUT); - pulseIn.init(context, gPulseInPin, 1); //third parameter is direction - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - static bool pulseOut = 0; - static int count = 0; - for(unsigned int n = 0; n < context->digitalFrames; n++){ - // detect if a pulse just ended - int duration = pulseIn.hasPulsed(context, n); - if(duration > 0){ - rt_printf("duration = %d\n", duration); - } - - // generate a rectangular waveform as a test signal. - // Connect gDigitalOutPin to gPulseInPin - // to verify that the detected pulse length is gPulseLength - if(count == gPulseLength ){ - pulseOut = false; - } - if(count == (gPulseLength + gSamplesBetweenPulses)){ - pulseOut = true; - count = 0; - } - digitalWrite(context, n, gDigitalOutPin, pulseOut); - count++; - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/basic_writeFile/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ -#include <unistd.h> -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - float frequency = 440.0; // Frequency of oscillator - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"frequency", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - frequency = atof(optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &frequency) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/basic_writeFile/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -#include <Bela.h> -#include <cmath> -#include <WriteFile.h> - -float gPhase1, gPhase2; -float gFrequency1, gFrequency2; -float gInverseSampleRate; - -WriteFile file1; -WriteFile file2; - -bool setup(BelaContext *context, void *userData) -{ - gInverseSampleRate = 1.0/context->audioSampleRate; - file1.init("out1.m"); //set the file name to write to - file1.setHeader("myvar=[\n"); //set a line to be printed at the beginning of the file - file1.setFooter("];\n"); //set a line to be printed at the end of the file - file1.setEcho(true); // enable echo to the console (as well as to the file) - file1.setFormat("%.5f %.10f %f\n"); // set the format that you want to use for your output. Please use %f only (with modifiers) - file2.init("out2.m"); - file2.setHeader("input=[\n"); - file2.setFooter("];\n"); - file2.setEcho(false); - file2.setFormat("%f\n"); - gPhase1 = 0.0; - gPhase2 = 0.0; - - gFrequency1 = 200.0; - gFrequency2 = 201.0; - return true; -} - -void render(BelaContext *context, void *userData) -{ - static int count = 0; - if((count&16383) == 0){ - file2.log(context->audioIn, context->audioFrames); //write the input buffer every so often - } - for(unsigned int n = 0; n < context->audioFrames; n++) { - float chn1 = sinf(gPhase1); - float chn2 = sinf(gPhase2); - gPhase1 += 2.0 * M_PI * gFrequency1 * gInverseSampleRate; - gPhase2 += 2.0 * M_PI * gFrequency2 * gInverseSampleRate; - if(gPhase1 > 2.0 * M_PI) - gPhase1 -= 2.0 * M_PI; - if(gPhase2 > 2.0 * M_PI) - gPhase2 -= 2.0 * M_PI; - if( (count&511) == 0){ - file1.log(chn1); - file1.log(chn2); - file1.log(count); - } - count++; - } -} - -// cleanup_render() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in initialise_render(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/bucket_brigade_chorus/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -#include <Bela.h> -#include <Scope.h> -#include <cmath> - -float gPhase1, gPhase2; -float gFrequency1, gFrequency2; -float gInverseSampleRate; - -// initialise_render() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. -#include <I2c_Codec.h> -#include <PRU.h> -extern I2c_Codec *gAudioCodec; -extern PRU *gPRU; -float D=5264; -#define delayLength 256 -float delay[delayLength]; -int writePointer=0; -int readPointer=writePointer+1; -AuxiliaryTask updatePll; - -void updatePllFunction(){ -// gPRU->setGPIOTestPin(); - static int count = 0; - while(!gShouldStop){ - gAudioCodec->setPllD(D); - count++; - if((count&4095)==0) - printf("sampling rate: %f\n",gAudioCodec->getAudioSamplingRate()); - usleep(100); - } -// gPRU->clearGPIOTestPin(); -} - -bool setup(BelaContext *context, void *userData) -{ - gInverseSampleRate = 1.0/context->audioSampleRate; - - gPhase1 = 0.0; - gPhase2 = 0.0; - - gFrequency1 = 200.0; - gFrequency2 = 201.0; - updatePll=Bela_createAuxiliaryTask(&updatePllFunction, 91, "update PLL"); - for(int n=0; n<delayLength; n++){ - delay[n]=0; - } - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ -// printf("here\n"); - static bool init = false; - if(init == false){ - Bela_scheduleAuxiliaryTask(updatePll); -// gAudioCodec->setPllP(2); -// gAudioCodec->setPllR(); -// gAudioCodec->setAudioSamplingRate(43600); -// printf("samplingRate: %f, k: %f\n", gAudioCodec->getAudioSamplingRate(), gAudioCodec->getPllK()); - init = true; - } - static int count=0; - static float lfoPhase=0; - static float feedback=0; - int updateRate=1; - if((count&(updateRate-1))==0){ - float amplitude = 8000; - float rate = 2; - lfoPhase+=rate*2*M_PI*updateRate*context->analogFrames/context->audioSampleRate; - D=amplitude+amplitude*sinf(lfoPhase); - if((count&255)==0){ -// rt_printf("frequency: %f\n", gAudioCodec->getAudioSamplingRate()); -// rt_printf("D: %.0f\n", D); -// rt_printf("rate: %f\n", rate); -// rt_printf("amplitude: %.3f\n", amplitude); -// rt_printf("feedback: %.3f\n\n", feedback); - } - } - count++; - - for(unsigned int n = 0; n < context->audioFrames; n++) { - feedback = 0.4; - float input = audioRead(context, n, 0) + audioRead(context, n, 1); - delay[writePointer++] = input + delay[readPointer]*feedback; - float output = (input + 0.9*delay[readPointer++] ) * 0.5; - audioWrite(context, n, 0, output); - audioWrite(context, n, 1, output); - if(writePointer>=delayLength) - writePointer-=delayLength; - if(readPointer>=delayLength) - readPointer-=delayLength; - - gPhase1 += 2.0 * M_PI * gFrequency1 * gInverseSampleRate; - gPhase2 += 2.0 * M_PI * gFrequency2 * gInverseSampleRate; - if(gPhase1 > 2.0 * M_PI) - gPhase1 -= 2.0 * M_PI; - if(gPhase2 > 2.0 * M_PI) - gPhase2 -= 2.0 * M_PI; - } -} - -// cleanup_render() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in initialise_render(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/cape_test/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ -#include <unistd.h> -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - float frequency = 440.0; // Frequency of oscillator - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"frequency", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - frequency = atof(optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &frequency) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/cape_test/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,279 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - - -#include <Bela.h> -#include <cmath> - -#define ANALOG_LOW (2048.0 / 65536.0) -#define ANALOG_HIGH (50000.0 / 65536.0) - -const int gDACPinOrder[] = {6, 4, 2, 0, 1, 3, 5, 7}; - -enum { - kStateTestingAudioLeft = 0, - kStateTestingAudioRight, - kStateTestingAudioDone -}; - -uint64_t gLastErrorFrame = 0; -uint32_t gEnvelopeSampleCount = 0; -float gEnvelopeValueL = 0.5, gEnvelopeValueR = 0.5; -float gEnvelopeDecayRate = 0.9995; -int gEnvelopeLastChannel = 0; - -float gPositivePeakLevels[2] = {0, 0}; -float gNegativePeakLevels[2] = {0, 0}; -float gPeakLevelDecayRate = 0.999; -const float gPeakLevelLowThreshold = 0.02; -const float gPeakLevelHighThreshold = 0.2; -const float gDCOffsetThreshold = 0.1; -int gAudioTestState = kStateTestingAudioLeft; -int gAudioTestStateSampleCount = 0; -int gAudioTestSuccessCounter = 0; -const int gAudioTestSuccessCounterThreshold = 64; -const int gAudioTestStateSampleThreshold = 16384; - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - static float phase = 0.0; - static int sampleCounter = 0; - static int invertChannel = 0; - float frequency = 0; - - // Play a sine wave on the audio output - for(unsigned int n = 0; n < context->audioFrames; n++) { - - // Peak detection on the audio inputs, with offset to catch - // DC errors - for(int ch = 0; ch < 2; ch++) { - if(context->audioIn[2*n + ch] > gPositivePeakLevels[ch]) - gPositivePeakLevels[ch] = context->audioIn[2*n + ch]; - gPositivePeakLevels[ch] += 0.1; - gPositivePeakLevels[ch] *= gPeakLevelDecayRate; - gPositivePeakLevels[ch] -= 0.1; - if(context->audioIn[2*n + ch] < gNegativePeakLevels[ch]) - gNegativePeakLevels[ch] = context->audioIn[2*n + ch]; - gNegativePeakLevels[ch] -= 0.1; - gNegativePeakLevels[ch] *= gPeakLevelDecayRate; - gNegativePeakLevels[ch] += 0.1; - } - - if(gAudioTestState == kStateTestingAudioLeft) { - context->audioOut[2*n] = 0.2 * sinf(phase); - context->audioOut[2*n + 1] = 0; - - frequency = 3000.0; - phase += 2.0 * M_PI * frequency / 44100.0; - if(phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - - gAudioTestStateSampleCount++; - if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) { - // Check if we have the expected input: signal on the left but not - // on the right. Also check that there is not too much DC offset on the - // inactive signal - if((gPositivePeakLevels[0] - gNegativePeakLevels[0]) >= gPeakLevelHighThreshold - && (gPositivePeakLevels[1] - gNegativePeakLevels[1]) <= gPeakLevelLowThreshold && - fabsf(gPositivePeakLevels[1]) < gDCOffsetThreshold && - fabsf(gNegativePeakLevels[1]) < gDCOffsetThreshold) { - // Successful test: increment counter - gAudioTestSuccessCounter++; - if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) { - gAudioTestState = kStateTestingAudioRight; - gAudioTestStateSampleCount = 0; - gAudioTestSuccessCounter = 0; - } - - } - else { - if(!((context->audioFramesElapsed + n) % 22050)) { - // Debugging print messages - if((gPositivePeakLevels[0] - gNegativePeakLevels[0]) < gPeakLevelHighThreshold) - rt_printf("Left Audio In FAIL: insufficient signal: %f\n", - gPositivePeakLevels[0] - gNegativePeakLevels[0]); - else if(gPositivePeakLevels[1] - gNegativePeakLevels[1] > gPeakLevelLowThreshold) - rt_printf("Right Audio In FAIL: signal present when it should not be: %f\n", - gPositivePeakLevels[1] - gNegativePeakLevels[1]); - else if(fabsf(gPositivePeakLevels[1]) >= gDCOffsetThreshold || - fabsf(gNegativePeakLevels[1]) >= gDCOffsetThreshold) - rt_printf("Right Audio In FAIL: DC offset: (%f, %f)\n", - gPositivePeakLevels[1], gNegativePeakLevels[1]); - } - gAudioTestSuccessCounter--; - if(gAudioTestSuccessCounter <= 0) - gAudioTestSuccessCounter = 0; - } - } - } - else if(gAudioTestState == kStateTestingAudioRight) { - context->audioOut[2*n] = 0; - context->audioOut[2*n + 1] = 0.2 * sinf(phase); - - frequency = 3000.0; - phase += 2.0 * M_PI * frequency / 44100.0; - if(phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - - gAudioTestStateSampleCount++; - if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) { - // Check if we have the expected input: signal on the left but not - // on the right - if((gPositivePeakLevels[1] - gNegativePeakLevels[1]) >= gPeakLevelHighThreshold - && (gPositivePeakLevels[0] - gNegativePeakLevels[0]) <= gPeakLevelLowThreshold && - fabsf(gPositivePeakLevels[0]) < gDCOffsetThreshold && - fabsf(gNegativePeakLevels[0]) < gDCOffsetThreshold) { - // Successful test: increment counter - gAudioTestSuccessCounter++; - if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) { - gAudioTestSuccessCounter = 0; - gAudioTestStateSampleCount = 0; - gAudioTestState = kStateTestingAudioDone; - } - } - else { - if(!((context->audioFramesElapsed + n) % 22050)) { - // Debugging print messages - if((gPositivePeakLevels[1] - gNegativePeakLevels[1]) < gPeakLevelHighThreshold) - rt_printf("Right Audio In FAIL: insufficient signal: %f\n", - gPositivePeakLevels[1] - gNegativePeakLevels[1]); - else if(gPositivePeakLevels[0] - gNegativePeakLevels[0] > gPeakLevelLowThreshold) - rt_printf("Left Audio In FAIL: signal present when it should not be: %f\n", - gPositivePeakLevels[0] - gNegativePeakLevels[0]); - else if(fabsf(gPositivePeakLevels[0]) >= gDCOffsetThreshold || - fabsf(gNegativePeakLevels[0]) >= gDCOffsetThreshold) - rt_printf("Left Audio In FAIL: DC offset: (%f, %f)\n", - gPositivePeakLevels[0], gNegativePeakLevels[0]); - } - gAudioTestSuccessCounter--; - if(gAudioTestSuccessCounter <= 0) - gAudioTestSuccessCounter = 0; - } - } - } - else { - // Audio input testing finished. Play tones depending on status of - // analog testing - context->audioOut[2*n] = gEnvelopeValueL * sinf(phase); - context->audioOut[2*n + 1] = gEnvelopeValueR * sinf(phase); - - // If one second has gone by with no error, play one sound, else - // play another - if(context->audioFramesElapsed + n - gLastErrorFrame > 44100) { - gEnvelopeValueL *= gEnvelopeDecayRate; - gEnvelopeValueR *= gEnvelopeDecayRate; - gEnvelopeSampleCount++; - if(gEnvelopeSampleCount > 22050) { - if(gEnvelopeLastChannel == 0) - gEnvelopeValueR = 0.5; - else - gEnvelopeValueL = 0.5; - gEnvelopeLastChannel = !gEnvelopeLastChannel; - gEnvelopeSampleCount = 0; - } - frequency = 880.0; - } - else { - gEnvelopeValueL = gEnvelopeValueR = 0.5; - gEnvelopeLastChannel = 0; - frequency = 220.0; - } - - phase += 2.0 * M_PI * frequency / 44100.0; - if(phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - } - } - - for(unsigned int n = 0; n < context->analogFrames; n++) { - // Change outputs every 512 samples - if(sampleCounter < 512) { - for(int k = 0; k < 8; k++) { - if(k == invertChannel) - context->analogOut[n*8 + gDACPinOrder[k]] = ANALOG_HIGH; - else - context->analogOut[n*8 + gDACPinOrder[k]] = 0; - } - } - else { - for(int k = 0; k < 8; k++) { - if(k == invertChannel) - context->analogOut[n*8 + gDACPinOrder[k]] = 0; - else - context->analogOut[n*8 + gDACPinOrder[k]] = ANALOG_HIGH; - } - } - - // Read after 256 samples: input should be low - if(sampleCounter == 256) { - for(int k = 0; k < 8; k++) { - if(k == invertChannel) { - if(context->analogIn[n*8 + k] < ANALOG_HIGH) { - rt_printf("FAIL [output %d, input %d] -- output HIGH input %f (inverted)\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]); - gLastErrorFrame = context->audioFramesElapsed + n; - } - } - else { - if(context->analogIn[n*8 + k] > ANALOG_LOW) { - rt_printf("FAIL [output %d, input %d] -- output LOW --> input %f\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]); - gLastErrorFrame = context->audioFramesElapsed + n; - } - } - } - } - else if(sampleCounter == 768) { - for(int k = 0; k < 8; k++) { - if(k == invertChannel) { - if(context->analogIn[n*8 + k] > ANALOG_LOW) { - rt_printf("FAIL [output %d, input %d] -- output LOW input %f (inverted)\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]); - gLastErrorFrame = context->audioFramesElapsed + n; - } - } - else { - if(context->analogIn[n*8 + k] < ANALOG_HIGH) { - rt_printf("FAIL [output %d, input %d] -- output HIGH input %f\n", gDACPinOrder[k], k, context->analogIn[n*8 + k]); - gLastErrorFrame = context->audioFramesElapsed + n; - } - } - } - } - - if(++sampleCounter >= 1024) { - sampleCounter = 0; - invertChannel++; - if(invertChannel >= 8) - invertChannel = 0; - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/core/link_core.sh Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -#!/bin/sh -ln -f -s ../../core/ source -ln -f -s ../../include/ include
--- a/examples/core/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -#include <Bela.h> - -bool setup(BelaContext *context, void *userData) -{ - return true; -} - -void render(BelaContext *context, void *userData) -{ - -} - -void cleanup(BelaContext *context, void *userData) -{ - -} \ No newline at end of file
--- a/examples/d-box/ADSR.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -// -// ADSR.cpp -// -// Created by Nigel Redmon on 12/18/12. -// EarLevel Engineering: earlevel.com -// Copyright 2012 Nigel Redmon -// -// For a complete explanation of the ADSR envelope generator and code, -// read the series of articles by the author, starting here: -// http://www.earlevel.com/main/2013/06/01/envelope-generators/ -// -// License: -// -// This source code is provided as is, without warranty. -// You may copy and distribute verbatim copies of this document. -// You may modify and use this source code to create binary code for your own purposes, free or commercial. -// - -#include "ADSR.h" -#include <math.h> - - -ADSR::ADSR(void) { - reset(); - setAttackRate(0); - setDecayRate(0); - setReleaseRate(0); - setSustainLevel(1.0); - setTargetRatioA(0.3); - setTargetRatioDR(0.0001); -} - -ADSR::~ADSR(void) { -} - -void ADSR::setAttackRate(float rate) { - attackRate = rate; - attackCoef = calcCoef(rate, targetRatioA); - attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef); -} - -void ADSR::setDecayRate(float rate) { - decayRate = rate; - decayCoef = calcCoef(rate, targetRatioDR); - decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); -} - -void ADSR::setReleaseRate(float rate) { - releaseRate = rate; - releaseCoef = calcCoef(rate, targetRatioDR); - releaseBase = -targetRatioDR * (1.0 - releaseCoef); -} - -float ADSR::calcCoef(float rate, float targetRatio) { - return exp(-log((1.0 + targetRatio) / targetRatio) / rate); -} - -void ADSR::setSustainLevel(float level) { - sustainLevel = level; - decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); -} - -void ADSR::setTargetRatioA(float targetRatio) { - if (targetRatio < 0.000000001) - targetRatio = 0.000000001; // -180 dB - targetRatioA = targetRatio; - attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef); -} - -void ADSR::setTargetRatioDR(float targetRatio) { - if (targetRatio < 0.000000001) - targetRatio = 0.000000001; // -180 dB - targetRatioDR = targetRatio; - decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef); - releaseBase = -targetRatioDR * (1.0 - releaseCoef); -}
--- a/examples/d-box/ADSR.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -// -// ADRS.h -// -// Created by Nigel Redmon on 12/18/12. -// EarLevel Engineering: earlevel.com -// Copyright 2012 Nigel Redmon -// -// For a complete explanation of the ADSR envelope generator and code, -// read the series of articles by the author, starting here: -// http://www.earlevel.com/main/2013/06/01/envelope-generators/ -// -// License: -// -// This source code is provided as is, without warranty. -// You may copy and distribute verbatim copies of this document. -// You may modify and use this source code to create binary code for your own purposes, free or commercial. -// - -#ifndef ADRS_h -#define ADRS_h - -#include <stdio.h> -#include <string> - -using namespace std; - -enum envState { - env_idle = 0, - env_attack, - env_decay, - env_sustain, - env_release -}; - -class ADSR { -public: - ADSR(void); - ~ADSR(void); - float process(void); - float process(int sampleCount); - float getOutput(void); - int getState(void); - void gate(int on); - void setAttackRate(float rate); - void setDecayRate(float rate); - void setReleaseRate(float rate); - void setSustainLevel(float level); - void setTargetRatioA(float targetRatio); - void setTargetRatioDR(float targetRatio); - void reset(void); - -protected: - int state; - float output; - float attackRate; - float decayRate; - float releaseRate; - float attackCoef; - float decayCoef; - float releaseCoef; - float sustainLevel; - float targetRatioA; - float targetRatioDR; - float attackBase; - float decayBase; - float releaseBase; - string name; - float calcCoef(float rate, float targetRatio); -}; - -inline float ADSR::process() { - switch (state) { - case env_idle: - break; - case env_attack: - output = attackBase + output * attackCoef; - if (output >= 1.0) { - output = 1.0; - state = env_decay; - } - break; - case env_decay: - output = decayBase + output * decayCoef; - if (output <= sustainLevel) { - output = sustainLevel; - state = env_sustain; - } - break; - case env_sustain: - break; - case env_release: - output = releaseBase + output * releaseCoef; - if (output <= 0.0) { - output = 0.0; - state = env_idle; - } - break; - } - return output; -} - -inline float ADSR::process(int sampleCount) -{ - float retVal = 0; - - if(state != env_idle) - { - for(int i=0; i<sampleCount; i++) - retVal = process(); - } - - return retVal; -} - -inline void ADSR::gate(int gate) { - - if (gate) - state = env_attack; - else if (state != env_idle) - state = env_release; -} - -inline int ADSR::getState() { - return state; -} - -inline void ADSR::reset() { - state = env_idle; - output = 0.0; -} - -inline float ADSR::getOutput() { - return output; -} - - -#endif
--- a/examples/d-box/AnalogInput.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * AnalogInput.cpp - * - * Created on: Oct 17, 2013 - * Author: Victor Zappi - */ - - -#include "AnalogInput.h" - -using namespace std; - - -AnalogInput::AnalogInput() -{ - ActivateAnalogHnd = NULL; - activateAnalogPath = ""; - analogIsSet = false; - - AnalogInHnd = NULL; - analogInPath = ""; - helperNumFound = false; - - // support var for init - // these are fixed for BBB - startPath = "/sys/devices/bone_capemgr.*/slots"; - readPath = ""; - - buffer = (char*) malloc (sizeof(char)*lSize); // reading buffer - - verbose = false; -} - - -AnalogInput::~AnalogInput() -{ - free(buffer); -} - -int AnalogInput::initAnalogInputs() -{ - if(analogIsSet) - { - if(verbose) - cout << "Fine, but Analog Input already active..."<< endl; - return 0; - } - - // title - if(verbose) - cout << "Init Analog Input"<< endl; - - - // first: activate analog pins on cape manager - // cape-bone-iio > /sys/devices/bone_capemgr.*/slots - - // we have to look for the semi-random number the BBB has initialized the bone_capemgr with [value of *] - // to reach /slots and set cape-bone-iio. - // to do so, we use glob lib, which translates wildcards [*] into all the values found in paths - - - glob( startPath.c_str(), 0, NULL, &globbuf); - - if(globbuf.gl_pathc >0) - { - if (globbuf.gl_pathc == 1 ) - { - activateAnalogPath = globbuf.gl_pathv[0]; - - // check if file is existing - if((ActivateAnalogHnd = fopen(activateAnalogPath.c_str(), "r+")) != NULL) - { - // we found that current capemgr num - - fwrite("cape-bone-iio", sizeof(char), 13, ActivateAnalogHnd); // activate pins - - analogIsSet = true; - - if(verbose) - cout << "Analog Pins activated via cape-bone-iio at path " << activateAnalogPath << endl; - - fclose(ActivateAnalogHnd); // close file - } - } - //else - //printf("toomany", ); - } - - globfree(&globbuf); // self freeing - - - if(!analogIsSet) - { - cout << "cannot find bone_capemgr" << endl; - cout << "------Init failed------" << endl; - return 1; - } - - - // build read path - startPath = "/sys/devices/ocp.2/helper.*"; - - glob( startPath.c_str(), 0, NULL, &globbuf); - - if(globbuf.gl_pathc >0) - { - if (globbuf.gl_pathc == 1 ) - { - analogInPath = globbuf.gl_pathv[0] + (string)"/AIN"; - } - else - cout << "Too many analog inputs with this name! [I am puzzled...]" << endl; - } - else - cout << "Cannot find analog input dir...puzzled" << endl; - - - return 0; -} - - -int AnalogInput::read(int index) -{ - // convert int index into string - stringstream ss; - ss << index; - - readPath = analogInPath + ss.str(); // create pin0 file path - - - // check if file is existing - if((AnalogInHnd = fopen(readPath.c_str(), "rb")) != NULL) - { - // we found that current helper num - - // prepare read buffer to reading - fseek (AnalogInHnd , 0 , SEEK_END); - lSize = ftell (AnalogInHnd); - rewind (AnalogInHnd); - - result = fread (buffer, 1, lSize, AnalogInHnd); - - fclose(AnalogInHnd); // close file - - helperNumFound = true; - - //cout << "Analog Pins can be read at path " << analogInPath << endl; - //cout << "Test reading of Pin0 gives: " << buffer << endl; - } - - if(!helperNumFound) - { - cout << "cannot find helper" << endl; - cout << "------Analog Read failed------" << endl; - return -1; - } - - return atoi(buffer); - -} - - -
--- a/examples/d-box/AnalogInput.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * AnalogInput.h - * - * Created on: Oct 17, 2013 - * Author: Victor Zappi - */ - -#ifndef ANALOGINPUT_H_ -#define ANALOGINPUT_H_ - -#include <iostream> -#include <sstream> -#include <stdio.h> -#include <stdlib.h> -#include <glob.h> - -using namespace std; - -class AnalogInput -{ -private: - FILE *ActivateAnalogHnd; - string activateAnalogPath; - bool analogIsSet; - - FILE *AnalogInHnd; - string analogInPath; - bool helperNumFound; - - // suport var for init - string startPath; - string readPath; - - glob_t globbuf; - - // support vars for pin reading - long lSize; - char * buffer; - size_t result; - - bool verbose; - -public: - AnalogInput(); - ~AnalogInput(); - - int initAnalogInputs(); - int read(int index); - -}; - - - - -#endif /* ANALOGINPUT_H_ */
--- a/examples/d-box/Biquad.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -// -// Biquad.cpp -// -// Created by Nigel Redmon on 11/24/12 -// EarLevel Engineering: earlevel.com -// Copyright 2012 Nigel Redmon -// -// For a complete explanation of the Biquad code: -// http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ -// -// License: -// -// This source code is provided as is, without warranty. -// You may copy and distribute verbatim copies of this document. -// You may modify and use this source code to create binary code -// for your own purposes, free or commercial. -// - -#include <math.h> -#include "Biquad.h" -#include <iostream> - -Biquad::Biquad() { - type = bq_type_lowpass; - a0 = 1.0; - a1 = a2 = b1 = b2 = 0.0; - Fc = 0.50; - Q = 0.707; - peakGain = 0.0; - z1 = z2 = 0.0; -} - -Biquad::Biquad(int type, double Fc, double Q, double peakGainDB) { - setBiquad(type, Fc, Q, peakGainDB); - z1 = z2 = 0.0; -} - -Biquad::~Biquad() { -} - -void Biquad::setType(int type) { - this->type = type; - calcBiquad(); -} - -void Biquad::setQ(double Q) { - this->Q = Q; - calcBiquad(); -} - -void Biquad::setFc(double Fc) { - this->Fc = Fc; - calcBiquad(); -} - -void Biquad::setPeakGain(double peakGainDB) { - this->peakGain = peakGainDB; - calcBiquad(); -} - -void Biquad::setBiquad(int type, double Fc, double Q, double peakGainDB) { - this->type = type; - this->Q = Q; - this->Fc = Fc; - startFc = Fc; - startQ = Q; - startPeakGain = peakGainDB; - setPeakGain(peakGainDB); -} - -void Biquad::calcBiquad(void) { - double norm; - double V = pow(10, fabs(peakGain) / 20.0); - double K = tan(M_PI * Fc); - switch (this->type) { - case bq_type_lowpass: - norm = 1 / (1 + K / Q + K * K); - a0 = K * K * norm; - a1 = 2 * a0; - a2 = a0; - b1 = 2 * (K * K - 1) * norm; - b2 = (1 - K / Q + K * K) * norm; - break; - - case bq_type_highpass: - norm = 1 / (1 + K / Q + K * K); - a0 = 1 * norm; - a1 = -2 * a0; - a2 = a0; - b1 = 2 * (K * K - 1) * norm; - b2 = (1 - K / Q + K * K) * norm; - break; - - case bq_type_bandpass: - norm = 1 / (1 + K / Q + K * K); - a0 = K / Q * norm; - a1 = 0; - a2 = -a0; - b1 = 2 * (K * K - 1) * norm; - b2 = (1 - K / Q + K * K) * norm; - break; - - case bq_type_notch: - norm = 1 / (1 + K / Q + K * K); - a0 = (1 + K * K) * norm; - a1 = 2 * (K * K - 1) * norm; - a2 = a0; - b1 = a1; - b2 = (1 - K / Q + K * K) * norm; - break; - - case bq_type_peak: - if (peakGain >= 0) { // boost - norm = 1 / (1 + 1/Q * K + K * K); - a0 = (1 + V/Q * K + K * K) * norm; - a1 = 2 * (K * K - 1) * norm; - a2 = (1 - V/Q * K + K * K) * norm; - b1 = a1; - b2 = (1 - 1/Q * K + K * K) * norm; - } - else { // cut - norm = 1 / (1 + V/Q * K + K * K); - a0 = (1 + 1/Q * K + K * K) * norm; - a1 = 2 * (K * K - 1) * norm; - a2 = (1 - 1/Q * K + K * K) * norm; - b1 = a1; - b2 = (1 - V/Q * K + K * K) * norm; - } - break; - case bq_type_lowshelf: - if (peakGain >= 0) { // boost - norm = 1 / (1 + sqrt(2) * K + K * K); - a0 = (1 + sqrt(2*V) * K + V * K * K) * norm; - a1 = 2 * (V * K * K - 1) * norm; - a2 = (1 - sqrt(2*V) * K + V * K * K) * norm; - b1 = 2 * (K * K - 1) * norm; - b2 = (1 - sqrt(2) * K + K * K) * norm; - } - else { // cut - norm = 1 / (1 + sqrt(2*V) * K + V * K * K); - a0 = (1 + sqrt(2) * K + K * K) * norm; - a1 = 2 * (K * K - 1) * norm; - a2 = (1 - sqrt(2) * K + K * K) * norm; - b1 = 2 * (V * K * K - 1) * norm; - b2 = (1 - sqrt(2*V) * K + V * K * K) * norm; - } - break; - case bq_type_highshelf: - if (peakGain >= 0) { // boost - norm = 1 / (1 + sqrt(2) * K + K * K); - a0 = (V + sqrt(2*V) * K + K * K) * norm; - a1 = 2 * (K * K - V) * norm; - a2 = (V - sqrt(2*V) * K + K * K) * norm; - b1 = 2 * (K * K - 1) * norm; - b2 = (1 - sqrt(2) * K + K * K) * norm; - } - else { // cut - norm = 1 / (V + sqrt(2*V) * K + K * K); - a0 = (1 + sqrt(2) * K + K * K) * norm; - a1 = 2 * (K * K - 1) * norm; - a2 = (1 - sqrt(2) * K + K * K) * norm; - b1 = 2 * (K * K - V) * norm; - b2 = (V - sqrt(2*V) * K + K * K) * norm; - } - break; - } - - return; -}
--- a/examples/d-box/Biquad.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -// -// Biquad.h -// -// Created by Nigel Redmon on 11/24/12 -// EarLevel Engineering: earlevel.com -// Copyright 2012 Nigel Redmon -// -// For a complete explanation of the Biquad code: -// http://www.earlevel.com/main/2012/11/25/biquad-c-source-code/ -// -// License: -// -// This source code is provided as is, without warranty. -// You may copy and distribute verbatim copies of this document. -// You may modify and use this source code to create binary code -// for your own purposes, free or commercial. -// - -#ifndef Biquad_h -#define Biquad_h - -enum { - bq_type_lowpass = 0, - bq_type_highpass, - bq_type_bandpass, - bq_type_notch, - bq_type_peak, - bq_type_lowshelf, - bq_type_highshelf -}; - -class Biquad { -public: - Biquad(); - Biquad(int type, double Fc, double Q, double peakGainDB); - ~Biquad(); - void setType(int type); - void setQ(double Q); - void setFc(double Fc); - void setPeakGain(double peakGainDB); - void setBiquad(int type, double Fc, double Q, double peakGain); - float process(float in); - - double getQ(); - double getFc(); - double getPeakGain(); - - double getStartingQ(); - double getStartingFc(); - double getStartingPeakGain(); - -protected: - void calcBiquad(void); - - int type; - double a0, a1, a2, b1, b2; - double Fc, Q, peakGain; - double startFc, startQ, startPeakGain; - double z1, z2; -}; - -inline double Biquad::getQ() -{ - return Q; -} - -inline double Biquad::getFc() -{ - return Fc; -} - -inline double Biquad::getPeakGain() -{ - return peakGain; -} - -inline double Biquad::getStartingQ() -{ - return startQ; -} - -inline double Biquad::getStartingFc() -{ - return startFc; -} - -inline double Biquad::getStartingPeakGain() -{ - return startPeakGain; -} - -inline float Biquad::process(float in) { - double out = in * a0 + z1; - z1 = in * a1 + z2 - b1 * out; - z2 = in * a2 - b2 * out; - return out; -} - -#endif // Biquad_h
--- a/examples/d-box/DBoxSynth.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * SimpleSynth.h - * - * Created on: Oct 22, 2013 - * Author: Victor Zappi - */ - -#ifndef DBOXSYNTH_H_ -#define DBOXSYNTH_H_ - -#include <iostream> -#include <string> -#include <stdio.h> -#include <stdlib.h> - -#include "Synth.h" - - -class DBoxSynth : public Synth -{ -public: - DBoxSynth(unsigned int rate, unsigned long buffer_size); - double getSample(); - double *getBlock(int block_size); - - -private: - Sampler *smp; - -}; - - - - -#endif /* DBOXSYNTH_H_ */
--- a/examples/d-box/DboxSensors.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -/* - * DboxSensors.cpp - * - * Created on: May 19, 2014 - * Author: Victor Zappi - */ - - -#include "DboxSensors.h" -#include "config.h" - -using namespace std; - - - -int DboxSensors::initSensors(int tk0_bus, int tk0_address, int tk1_bus, int tk1_address, int tk_file, int fsr_pin, int fsrmax, int sensorTypeToUse, int gpio_0, int gpio_1) -{ - sensorType = sensorTypeToUse; - // init first touch key on i2c bus - if(tk0_address >= 0) { - if(TK0.initI2C_RW(tk0_bus, tk0_address, tk_file)>0) - return 1; - if(TK0.initTouchKey(sensorType)>0) - return 2; - } - - // init second touch key on i2c bus - if(tk1_address >= 0) { - if(TK1.initI2C_RW(tk1_bus, tk1_address, tk_file)>0) - return 1; - if(TK1.initTouchKey(sensorType)>0) - return 2; - } - - // init fsr on analog input pin - fsr_pinNum = fsr_pin; - fsr_max = fsrmax; - - if(FSR.initAnalogInputs()>0) - return 3; - - gpio[0] = gpio_0; - if(gpio[0]!=-1) - { - fdDi[0] = gpio_export(gpio[0]); - if(fdDi[0] == -1) - return 4; - } - digitalIn[0] = 1; - - return 0; -} - - -int DboxSensors::readSensors() -{ - // write data into first touch key - if(TK0.ready()) { - if(TK0.readI2C()>0) - return 1; - - // retrieve data from first touch key - tk0_touchCnt = TK0.getTouchCount(); - } - else - tk0_touchCnt = 0; - - // write data into second touch key - if(TK1.ready()) { - if(TK1.readI2C()>0) - return 1; - // retrieve data from second touch key - tk1_touchCnt = TK1.getTouchCount(); - } - else - tk1_touchCnt = 0; - - - int max = 3; - if(sensorType != kSensorTypeTouchKey) - max = 5; - // if touches detected on main touch key - if(tk0_touchCnt == 0 && tk1_touchCnt == 0) - resetSensorsData(); - else - { - for(int i=0; i<max; i++) - { - tk0_touchPosX[i] = TK0.getSliderPosition()[i]; - tk0_touchSize[i] = TK0.getSlidersize()[i]; - - tk1_touchPosX[i] = TK1.getSliderPosition()[i]; - tk1_touchSize[i] = TK1.getSlidersize()[i]; - } - tk0_touchPosY = TK0.getSliderPositionH(); - tk1_touchPosY = TK1.getSliderPositionH(); - fsr_read = (double)FSR.read(fsr_pinNum); - } - - if(gpio[0]!=-1) - { - if(gpio_read(fdDi[0], &digitalIn[0])==-1) - return 1; - } - - return 0; -} - - - -DboxSensors::DboxSensors() -{ - resetSensorsData(); -} - - - -DboxSensors::~DboxSensors() -{ - if(gpio[0]!=-1) - gpio_dismiss(fdDi[0], gpio[0]); -} - - - -//-------------------------------------------------------------------------------------------------------- -// private methods -//-------------------------------------------------------------------------------------------------------- - -// idle values -void DboxSensors::resetSensorsData() -{ - int max = 3; - if(sensorType != kSensorTypeTouchKey) - max = 5; - - for(int i=0; i<max; i++) - { - tk0_touchPosX[i] = -1; - tk0_touchPosY = -1; - tk0_touchSize[i] = 0; - - tk1_touchPosX[i] = -1; - tk1_touchPosY = -1; - tk1_touchSize[i] = 0; - - fsr_read = 0; - } - - return; -} - - - - - -
--- a/examples/d-box/DboxSensors.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * DboxSensors.h - * - * Created on: May 19, 2014 - * Author: Victor Zappi - */ - -#ifndef DBOXSENSORS_H_ -#define DBOXSENSORS_H_ - -#include <stdio.h> -#include <sys/mount.h> // mount() -#include <string.h> // strerror() -#include <fstream> // fstream -#include <iostream> -#include <unistd.h> // usleep() -#include <glob.h> // glob() -#include <sys/time.h> // elapsed time -#include <sys/stat.h> // mkdir() -#include <algorithm> // reverse() [string...] - -#include "I2c_TouchKey.h" -#include "AnalogInput.h" -#include <GPIOcontrol.h> // TODO wrap this into a class - -/*--------------------------------------------------------------------------------------------------------------------------------------------------- - * This class retrieves data from all the connected sensors, - * logs them - * and exposes to the main only the values needed to synthesize sound - * - * The simple instrument has: - * - * - * - *--------------------------------------------------------------------------------------------------------------------------------------------------- - */ -class DboxSensors -{ -public: - int initSensors(int tk0_bus, int tk0_address, int tk1_bus, int tk1_address, int tk_file, int fsr_pin, int fsrmax, int sensorTypeToUse, int gpio0=-1, int gpio1=-1); - int readSensors(); - int getTKTouchCount(int index); - float *getTKXPositions(int index); - float getTKYPosition(int index); - float *getTKTouchSize(int index); - double getFSRVAlue(); - int getDigitalIn(int index); - - DboxSensors(); - ~DboxSensors(); - -private: - int sensorType; - - I2c_TouchKey TK0; - int tk0_touchCnt; - float tk0_touchPosX[5]; - float tk0_touchPosY; - float tk0_touchSize[5]; - - I2c_TouchKey TK1; - int tk1_touchCnt; - float tk1_touchPosX[5]; - float tk1_touchPosY; - float tk1_touchSize[5]; - - AnalogInput FSR; - int fsr_pinNum; - double fsr_read; - int fsr_max; - - unsigned int digitalIn[2]; - int fdDi[2]; - int gpio[2]; - - void resetSensorsData(); - -}; - - - -//-------------------------------------------------------------------------------- -// read interface -inline int DboxSensors::getTKTouchCount(int index) -{ - if(index==0) - return tk0_touchCnt; - else - return tk1_touchCnt; -} - -inline float *DboxSensors::getTKXPositions(int index) -{ - if(index==0) - return tk0_touchPosX; - else - return tk1_touchPosX; -} - -inline float DboxSensors::getTKYPosition(int index) -{ - if(index==0) - return tk0_touchPosY; - else - return tk1_touchPosY; -} - -inline float *DboxSensors::getTKTouchSize(int index) -{ - if(index==0) - return tk0_touchSize; - else - return tk1_touchSize; -} - -inline double DboxSensors::getFSRVAlue() -{ - return fsr_read; -} - -inline int DboxSensors::getDigitalIn(int index) -{ - return digitalIn[index]; -} -//-------------------------------------------------------------------------------- - - -#endif /* DBOXSENSORS_H_ */
--- a/examples/d-box/FIRfilter.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * FIRfilter.h - * - * Created on: Aug 5, 2014 - * Author: Victor Zappi and Andrew McPherson - */ - -#ifndef FIRFILTER_H_ -#define FIRFILTER_H_ - -#define ENABLE_NE10_FIR_FLOAT_NEON // Define needed for Ne10 library -#include <ne10/NE10.h> - -//#define FILTER_TAP_NUM 21 -//ne10_float32_t filterTaps[FILTER_TAP_NUM] = { -// 0.000350, -// 0.001133, -// 0.002407, -// 0.004203, -// 0.006468, -// 0.009057, -// 0.011748, -// 0.014265, -// 0.016323, -// 0.017671, -// 0.018141, -// 0.017671, -// 0.016323, -// 0.014265, -// 0.011748, -// 0.009057, -// 0.006468, -// 0.004203, -// 0.002407, -// 0.001133, -// 0.000350 -//}; -#define FILTER_TAP_NUM 31 -ne10_float32_t filterTaps[FILTER_TAP_NUM] = { - 0.000018, - 0.000043, - 0.000078, - 0.000125, - 0.000183, - 0.000252, - 0.000330, - 0.000415, - 0.000504, - 0.000592, - 0.000677, - 0.000754, - 0.000818, - 0.000866, - 0.000897, - 0.000907, - 0.000897, - 0.000866, - 0.000818, - 0.000754, - 0.000677, - 0.000592, - 0.000504, - 0.000415, - 0.000330, - 0.000252, - 0.000183, - 0.000125, - 0.000078, - 0.000043, - 0.000018 -}; - -#endif /* FIRFILTER_H_ */
--- a/examples/d-box/FeedbackOscillator.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* - * FeedbackOscillator.cpp - * - * Recursive phase-shift oscillator implemented - * on the matrix - * - * Andrew McPherson 2014 - */ - -#include "FeedbackOscillator.h" -#include <cstdlib> -#include <cmath> - -#define COEFF_B0 0 -#define COEFF_B1 1 -#define COEFF_A1 2 - -FeedbackOscillator::FeedbackOscillator() -: wavetable1(0), wavetable2(0) -{ - -} - -FeedbackOscillator::~FeedbackOscillator() { - if(wavetable1 != 0) - free(wavetable1); - if(wavetable2 != 0) - free(wavetable2); - -} - -// Initialise the settings for the feedback oscillator -void FeedbackOscillator::initialise(int maxTableSize, float hpfCutoffFrequency, float matrixSampleRate) { - wavetableMaxLength = maxTableSize; - if(wavetable1 != 0) - free(wavetable1); - if(wavetable2 != 0) - free(wavetable2); - - wavetable1 = (float *)malloc(maxTableSize * sizeof(float)); - wavetable2 = (float *)malloc(maxTableSize * sizeof(float)); - - float omega = tan(M_PI * hpfCutoffFrequency / matrixSampleRate); - float n = 1.0f / (1.0f + omega); - - coeffs[COEFF_A1] = (omega - 1.0f) * n; - coeffs[COEFF_B0] = n; - coeffs[COEFF_B1] = -n; - - for(int n = 0; n < maxTableSize; n++) - wavetable1[n] = wavetable2[n] = 0; - - wavetableRead = wavetable1; - wavetableWrite = wavetable2; - wavetableWritePointer = 0; - sampleCount = lastTriggerCount = 0; -} - -// Process one sample and store the output value -// Returns true if the wavetable needs rendering -int FeedbackOscillator::process(float input, float *output) { - float outFloat = coeffs[COEFF_B0] * input + coeffs[COEFF_B1] * lastInput - coeffs[COEFF_A1] * lastOutput; - int requestRenderLength = 0; - - if(outFloat < -0.5) - *output = 0; - else if(outFloat > 0.5) - *output = 1; - else - *output = outFloat + 0.5; - - if(canTrigger && outFloat > 0 && lastOutput <= 0) { - triggered = true; - requestRenderLength = wavetableWritePointer; // How many samples stored thus far? - if(requestRenderLength < 4) - requestRenderLength = 0; // Ignore anything with fewer than 4 points - - lastTriggerCount = sampleCount; - canTrigger = false; - wavetableWritePointer = 0; - - // Swap buffers - float *temp = wavetableWrite; - wavetableWrite = wavetableRead; - wavetableRead = temp; - } - - if(triggered) { - wavetableWrite[wavetableWritePointer] = outFloat; - if(++wavetableWritePointer >= wavetableMaxLength) { - triggered = false; - wavetableWritePointer = 0; - } - } - - if(sampleCount - lastTriggerCount > 40) - canTrigger = true; - - sampleCount++; - - lastOutput = outFloat; - lastInput = input; - - return requestRenderLength; -}
--- a/examples/d-box/FeedbackOscillator.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * FeedbackOscillator.h - * - * Created on: June 8, 2014 - * Author: Andrew McPherson - */ - -#ifndef FEEDBACKOSCILLATOR_H -#define FEEDBACKOSCILLATOR_H - -class FeedbackOscillator -{ -public: - FeedbackOscillator(); - ~FeedbackOscillator(); - - // Initialise the settings for the feedback oscillator - void initialise(int maxTableSize, float hpfCutoffFrequency, float matrixSampleRate); - - // Process one sample and store the output value - // Returns the length of table to interpolate; or 0 if nothing to process further - int process(float input, float *output); - - float *wavetable() { return wavetableRead; } - -private: - float coeffs[3]; // Coefficients of first-order high-pass filter - float lastInput; // last input sample for HPF - float lastOutput; // last output sample of HPF - bool triggered; // whether we are currently saving samples - bool canTrigger; // whether we are able to begin saving samples - int wavetableMaxLength; // how long the stored wavetable can be - int sampleCount; // how many samples have elapsed - int lastTriggerCount; // sample count when we last triggered - - float *wavetable1, *wavetable2; // Two wavetables where we record samples - float *wavetableRead, *wavetableWrite; // Pointers to the above wavetables - int wavetableWritePointer; // Where we are currently writing -}; - -#endif
--- a/examples/d-box/OscillatorBank.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1016 +0,0 @@ -/* - * OscillatorBank.cpp - * - * Created on: May 23, 2014 - * Author: Victor Zappi and Andrew McPherson - */ - - -/* - * There is a problem with name consistency between this class and the Parser class in spear_parser files. - * There, a "frame" is each of the time values where partials are sampled, while a "hop" is the actual jump between frames [calculated in samples] - * Here, "hop" is used with the meaning of "frame", while "frame" became the local frame of a partial - * - * example - * - * frames: 0 1 2 - * p0 p0_0 p0_1 - * p1 p1_0 p1_1 p1_2 - * p2 p2_0 p2_1 - * - * In this case: - * in Parser there are 2 hops, 3 total frames and the 3 partials have respectively 2, 3 and 2 local frames - * - * here there are 3 total hops [the concept of jumps is discarded, cos not in use] and the 3 partials have respectively 2, 3 and 2 frames - * - * This must be fixed -*/ - -// TODO: fix hop-frame name consistency - - -#include <stdlib.h> - -#include "OscillatorBank.h" - -OscillatorBank::OscillatorBank() { - loaded = false; -} - -OscillatorBank::OscillatorBank(string filename, int hopsize, int samplerate) { - loaded = false; - loadFile(filename.c_str(), hopsize, samplerate); -} - -OscillatorBank::OscillatorBank(char *filename, int hopsize, int samplerate) { - loaded = false; - loadFile(filename, hopsize, samplerate); -} - -OscillatorBank::~OscillatorBank() { - free(oscillatorPhases); - free(oscillatorNextNormFreq); - free(oscillatorNextAmp); - free(oscillatorNormFrequencies); - free(oscillatorAmplitudes); - free(oscillatorNormFreqDerivatives); - free(oscillatorAmplitudeDerivatives); - free(phaseCopies); - free(nextNormFreqCopies); - free(nextAmpCopies); - - delete[] oscStatNormFrequenciesMean; - delete[] oscStatNumHops; - delete[] lookupTable; - delete[] indicesMapping; - delete[] freqFixedDeltas; - delete[] ampFixedDeltas; - delete[] nyquistCut; -} - -bool OscillatorBank::initBank(int oversamp) { - if (!loaded) - return false; - - //---prepare look-up table - lookupTableSize = 1024; - lookupTable = new float[lookupTableSize + 1]; - for (int n = 0; n < (lookupTableSize + 1); n++) - lookupTable[n] = sin(2.0 * M_PI * (float) n / (float) lookupTableSize); - frequencyScaler = (float) lookupTableSize / rate; - nyqNorm = rate / 2 * frequencyScaler; - - if (oversamp < 1) - oversamp = 1; - - //---prepare oscillators - partials = &(parser.partials); // pointer to paser's partials - partialsHopSize = parser.getHopSize(); - lastHop = partials->getHopNum(); // last bank hop is equal to last partial frame, which is equal to partial hop num - overSampling = oversamp; - hopSize = partialsHopSize / overSampling; // if oversampling, osc bank hop num > partials hop num - hopSizeReminder = partialsHopSize % overSampling; - oscBankHopSize = hopSize; - numOfPartials = partials->getPartialNum(); - numOfOscillators = partials->getMaxActivePartialNum(); // get the maximum number of active partials at the same time - - // set to next multiple of 4 [NEON] - numOfOscillators = (numOfOscillators + 3) & ~0x3; // to be sure we can add up to 3 fake oscillators - - int err; - //---allocate buffers - // alligned buffers [NEON] - err = posix_memalign((void**) &oscillatorPhases, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &oscillatorNextNormFreq, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &oscillatorNextAmp, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &oscillatorNormFrequencies, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &oscillatorAmplitudes, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &oscillatorNormFreqDerivatives, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &oscillatorAmplitudeDerivatives, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &phaseCopies, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &nextNormFreqCopies, 16, - numOfOscillators * sizeof(float)); - err += posix_memalign((void**) &nextAmpCopies, 16, - numOfOscillators * sizeof(float)); - - // regular ones - oscStatNormFrequenciesMean = new float[numOfPartials]; - oscStatNumHops = new float[numOfPartials]; - indicesMapping = new int[numOfPartials]; - freqFixedDeltas = new float[numOfPartials]; - ampFixedDeltas = new float[numOfPartials]; - nyquistCut = new bool[numOfPartials]; - - if (err > 0) { - dbox_printf("Failed memory allocations %@#!\n"); - return false; - } - - // copy stats [they do not change] - for (int n = 0; n < numOfPartials; n++) { - oscStatNormFrequenciesMean[n] = partials->partialFreqMean[n] - * frequencyScaler; - oscStatNumHops[n] = partials->partialNumFrames[n]; // in Parser and Partials "frames" are what we call here "hops" [see comment at top of file] - } - - // deafult values - actPartNum = 0; - loopStartHop = 0; - loopEndHop = (parser.partials.getHopNum() - 2) * overSampling; - ampTh = 0.0001; - hopNumTh = 0; - pitchMultiplier = 1; - freqMovement = 1; - filterNum = 0; - note = false; - speed = 1; - nextSpeed = -1; - maxSpeed = 10; - minSpeed = 0.1; - jumpHop = -1; - - // filter - filterMaxF = 22000; - filterAmpMinF = 10 * frequencyScaler; - filterAmpMaxF = 5000 * frequencyScaler; - filterAmpMul = 10.0; - - // adsr - minAttackTime = .0001; - deltaAttackTime = 2.; - minReleaseTime = 1; - deltaReleaseTime = 2.5; - - adsr.setAttackRate(minAttackTime * rate); - adsr.setDecayRate(.0001 * rate); - adsr.setSustainLevel(1); - adsr.setReleaseRate(minReleaseTime * rate); - - state = bank_stopped; - return true; -} - -void OscillatorBank::resetOscillators() { - currentHop = -1; - loopDir = 1; - loopDirShift = 0; - fill(nyquistCut, nyquistCut + numOfPartials, false); - prevAdsrVal = 0; - prevAmpTh = ampTh; - prevHopNumTh = hopNumTh; - prevPitchMultiplier = pitchMultiplier; - prevFreqMovement = freqMovement; - prevFilterNum = filterNum; - memcpy(prevFilterFreqs, filterFreqs, filterNum * sizeof(float)); - memcpy(prevFilterQ, filterQ, filterNum * sizeof(float)); - - int activePNum = partials->activePartialNum[0]; - unsigned int *activeP = partials->activePartials[0]; - for (int i = 0; i < activePNum; i++) { - freqFixedDeltas[activeP[i]] = partials->partialFreqDelta[activeP[i]][0] - / overSampling; - ampFixedDeltas[activeP[i]] = partials->partialAmpDelta[activeP[i]][0] - / overSampling; - } - // attack! - adsr.gate(1); - note = true; - - nextHop(); - - state = bank_playing; -} - -void OscillatorBank::nextHop() { - hopSize = oscBankHopSize; - - // copy phases, next freqs and next amps from previous frame - memcpy(phaseCopies, oscillatorPhases, actPartNum * sizeof(float)); - memcpy(nextNormFreqCopies, oscillatorNextNormFreq, - actPartNum * sizeof(float)); - memcpy(nextAmpCopies, oscillatorNextAmp, actPartNum * sizeof(float)); - - // next frame is forward or backwards, cos we could be in the loop - currentHop += loopDir; - - checkDirection(); - -// if((currentHop/overSampling)%100 == 0) -// dbox_printf("currentHop %d, direction: %d\n", currentHop/overSampling, loopDir); - - // if needs jump, end here this method, cos jumpToHop() will do tee rest - if (checkJump() == 0) - return; - // otherwise, if jump is not needed or fails, continue regular stuff - - if (nextEnvState() != 0) - return; // release has ended! - - checkSpeed(); - - // now let's decide how to calculate next hop - if (!checkOversampling()) - nextOscBankHop(); - else - nextPartialHop(); -} - -void OscillatorBank::nextOscBankHop() { - int parIndex, localHop; - float parDamp = 1; - int currentPartialHop = (currentHop / overSampling) + loopDirShift; - - // if going backwards in the loop, get previous frame active partials... - actPartNum = partials->activePartialNum[currentPartialHop - loopDirShift]; - actPart = partials->activePartials[currentPartialHop - loopDirShift]; - //cout << "actPartNum: " << actPartNum << endl; - - envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release] - - int parCnt = 0; - int currentHopReminder = currentHop % overSampling; - // steps to reach next bank hop from previous partial hop - int steps = currentHopReminder + 1; - if (loopDir < 0) - steps = overSampling - currentHopReminder + 1; - - for (int i = 0; i < actPartNum; i++) { - // find partial and frame - parIndex = actPart[i]; - //localHop = partials->localPartialFrames[currentPartialHop][parIndex]; - localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file] - - //float delta = partials->partialFrequencies[parIndex][localHop+loopDir] - partials->partialFrequencies[parIndex][localHop]; - - // if this partial was over nyquist on previous hop... - if (nyquistCut[parIndex]) { - // ...restart from safe values - oscillatorPhases[parCnt] = 0; - //TODO add freqmove dependency - oscillatorNextNormFreq[parCnt] = - (partials->partialFrequencies[parIndex][localHop] - + freqFixedDeltas[parIndex] * (steps - 1)) - * frequencyScaler * prevPitchMultiplier; - oscillatorNextAmp[parCnt] = 0; - } else if (loopDir == 1) // otherwise recover phase, target freq and target amp from previous frame - { - if ((localHop != 0) || (currentHopReminder != 0)) { - oscillatorPhases[parCnt] = - phaseCopies[indicesMapping[parIndex]]; - oscillatorNextNormFreq[parCnt] = - nextNormFreqCopies[indicesMapping[parIndex]]; - oscillatorNextAmp[parCnt] = - nextAmpCopies[indicesMapping[parIndex]]; - } else // first oscillator hop [both for bank and partial], so no previous data are available - { - oscillatorPhases[parCnt] = 0; - //TODO add freqmove dependency - oscillatorNextNormFreq[parCnt] = - partials->partialFrequencies[parIndex][localHop] - * frequencyScaler * prevPitchMultiplier; - parDamp = calculateParDamping(parIndex, prevHopNumTh, - prevAdsrVal, oscillatorNextNormFreq[parCnt], - prevFilterNum, prevFilterFreqs, prevFilterQ); - oscillatorNextAmp[parCnt] = - partials->partialAmplitudes[parIndex][localHop] - * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - freqFixedDeltas[parIndex] = - partials->partialFreqDelta[parIndex][localHop + loopDir] - * loopDir / overSampling; - ampFixedDeltas[parIndex] = - partials->partialAmpDelta[parIndex][localHop + loopDir] - * loopDir / overSampling; - } - } else { - oscillatorPhases[parCnt] = phaseCopies[indicesMapping[parIndex]]; - oscillatorNextNormFreq[parCnt] = - nextNormFreqCopies[indicesMapping[parIndex]]; - oscillatorNextAmp[parCnt] = nextAmpCopies[indicesMapping[parIndex]]; - } - - // remove aliasing, skipping partial over nyquist freq - if (oscillatorNextNormFreq[parCnt] > nyqNorm) { - nyquistCut[parIndex] = true; - continue; - } - nyquistCut[parIndex] = false; - - // first set up freq, cos filter affects amplitude damping according to freq content - oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts - // save next values, current for next round - oscillatorNextNormFreq[parCnt] = (freqMovement - * (partials->partialFrequencies[parIndex][localHop] - + freqFixedDeltas[parIndex] * steps) * frequencyScaler - + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex]) - * pitchMultiplier; - // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials - oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt] - - oscillatorNormFrequencies[parCnt]) / hopCounter; - // this second weird passage handles dissonance control, morphing between regular and mean frequencies - oscillatorNormFreqDerivatives[parCnt] = freqMovement - * oscillatorNormFreqDerivatives[parCnt] - + (1 - freqMovement) - * ((oscStatNormFrequenciesMean[parIndex] - * pitchMultiplier) - - oscillatorNormFrequencies[parCnt]) - / hopCounter; - - parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal, - oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ); - - // now amplitudes - oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts - // save next values, current for next round - //delta = partials->partialAmplitudes[parIndex][localHop+loopDir] - partials->partialAmplitudes[parIndex][localHop]; - oscillatorNextAmp[parCnt] = - (partials->partialAmplitudes[parIndex][localHop] - + ampFixedDeltas[parIndex] * steps) * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - if ((loopDir == -1) && (localHop = 1) && (currentHopReminder == 1)) - oscillatorNextAmp[parCnt] = 0; - // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials - oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt] - - oscillatorAmplitudes[parCnt]) / hopCounter; - - // finally update current mapping between oscillators and partials - indicesMapping[parIndex] = parCnt; - parCnt++; - } - actPartNum = parCnt; - // [NEON] if not multiple of 4... - if (actPartNum % 4 != 0) - addFakeOsc(); -} - -void OscillatorBank::nextPartialHop() { - unsigned int parIndex, localHop; - float parDamp = 1; - int currentPartialHop = currentHop / overSampling; - - // if going backwards in the loop, get previous frame active partials... - actPartNum = partials->activePartialNum[currentPartialHop - loopDirShift]; - actPart = partials->activePartials[currentPartialHop - loopDirShift]; - - envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release] - - int parCnt = 0; - int steps = overSampling - 1; // steps to reach next hop [partial or bank] from previous partial hop - - for (int i = 0; i < actPartNum; i++) { - // find partial and frame - parIndex = actPart[i]; - //localHop = partials->localPartialFrames[currentPartialHop][parIndex]; - localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file] - - // if this partial was over nyquist on previous hop... - if (nyquistCut[parIndex]) { - // ...restart from safe values - oscillatorPhases[parCnt] = 0; - //TODO add freqmove dependency - oscillatorNextNormFreq[parCnt] = - (partials->partialFrequencies[parIndex][localHop] - + freqFixedDeltas[parIndex] * steps - * (1 - loopDirShift)) * frequencyScaler - * prevPitchMultiplier; - oscillatorNextAmp[parCnt] = 0; - } else if (loopDir == 1) // otherwise recover phase, target freq and target amp from previous frame - { - if ((localHop != 0) || (overSampling > 1)) { - oscillatorPhases[parCnt] = - phaseCopies[indicesMapping[parIndex]]; - oscillatorNextNormFreq[parCnt] = - nextNormFreqCopies[indicesMapping[parIndex]]; - oscillatorNextAmp[parCnt] = - nextAmpCopies[indicesMapping[parIndex]]; - } else // first oscillator hop [both for bank and partial], so no previous data are available - { - oscillatorPhases[parCnt] = 0; - //TODO add freqmove dependency - oscillatorNextNormFreq[parCnt] = - partials->partialFrequencies[parIndex][localHop] - * frequencyScaler * prevPitchMultiplier; - parDamp = calculateParDamping(parIndex, prevHopNumTh, - prevAdsrVal, oscillatorNextNormFreq[parCnt], - prevFilterNum, prevFilterFreqs, prevFilterQ); - oscillatorNextAmp[parCnt] = - partials->partialAmplitudes[parIndex][localHop] - * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - freqFixedDeltas[parIndex] = - partials->partialFreqDelta[parIndex][localHop + loopDir] - * loopDir / overSampling; - ampFixedDeltas[parIndex] = - partials->partialAmpDelta[parIndex][localHop + loopDir] - * loopDir / overSampling; - } - } else { - if (localHop != partials->partialNumFrames[parIndex] - 1) { - oscillatorPhases[parCnt] = - phaseCopies[indicesMapping[parIndex]]; - oscillatorNextNormFreq[parCnt] = - nextNormFreqCopies[indicesMapping[parIndex]]; - oscillatorNextAmp[parCnt] = - nextAmpCopies[indicesMapping[parIndex]]; - } else // first oscillator hop [going backwards - both for bank and partial] , so no previous data are available - { - oscillatorPhases[parCnt] = 0; - //TODO add freqmove dependency - oscillatorNextNormFreq[parCnt] = - partials->partialFrequencies[parIndex][localHop] - * frequencyScaler * prevPitchMultiplier; - parDamp = calculateParDamping(parIndex, prevHopNumTh, - prevAdsrVal, oscillatorNextNormFreq[parCnt], - prevFilterNum, prevFilterFreqs, prevFilterQ); - oscillatorNextAmp[parCnt] = - partials->partialAmplitudes[parIndex][localHop] - * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - freqFixedDeltas[parIndex] = - partials->partialFreqDelta[parIndex][localHop + loopDir] - * loopDir / overSampling; - ampFixedDeltas[parIndex] = - partials->partialAmpDelta[parIndex][localHop + loopDir] - * loopDir / overSampling; - } - } - // remove aliasing, skipping partial over nyquist freq - if (oscillatorNextNormFreq[parCnt] > nyqNorm) { - //cout << nyqNorm << endl; - nyquistCut[parIndex] = true; - continue; - } - nyquistCut[parIndex] = false; - - // first set up freq, cos filter affects amplitude damping according to freq content - oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts - // save next values, current for next round - oscillatorNextNormFreq[parCnt] = (freqMovement - * (partials->partialFrequencies[parIndex][localHop + loopDir] - - freqFixedDeltas[parIndex] * steps * loopDirShift) - * frequencyScaler - + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex]) - * pitchMultiplier; - // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials - oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt] - - oscillatorNormFrequencies[parCnt]) / hopCounter; - // this second weird passage handles dissonance control, morphing between regular and mean frequencies - oscillatorNormFreqDerivatives[parCnt] = freqMovement - * oscillatorNormFreqDerivatives[parCnt] - + (1 - freqMovement) - * ((oscStatNormFrequenciesMean[parIndex] - * pitchMultiplier) - - oscillatorNormFrequencies[parCnt]) - / hopCounter; - - parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal, - oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ); - - // now amplitudes - oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts - // save next values, current for next round - //delta = partials->partialAmplitudes[parIndex][localHop+loopDir] - partials->partialAmplitudes[parIndex][localHop]; - oscillatorNextAmp[parCnt] = - (partials->partialAmplitudes[parIndex][localHop + loopDir] - - (ampFixedDeltas[parIndex]) * steps * loopDirShift) - * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - - // to avoid bursts when transients are played backwards - if ((loopDir == -1) && (localHop - 1 == 0) && (overSampling == 1)) { - oscillatorNextAmp[parCnt] = 0; - } - // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials - oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt] - - oscillatorAmplitudes[parCnt]) / hopCounter; - - // if next is not going to loop boundaries, get next deltas [same direction] - if ((((currentPartialHop + loopDir) * overSampling != loopEndHop) - || (loopDir == -1)) - && (((currentPartialHop + loopDir) * overSampling + loopDir - != loopStartHop) || (loopDir == 1))) { - freqFixedDeltas[parIndex] = - partials->partialFreqDelta[parIndex][localHop + loopDir] - * loopDir / overSampling; - ampFixedDeltas[parIndex] = - partials->partialAmpDelta[parIndex][localHop + loopDir] - * loopDir / overSampling; - } else // .. otherwise, keep deltas but change sign [co swe change direction] - { - freqFixedDeltas[parIndex] = -freqFixedDeltas[parIndex]; - ampFixedDeltas[parIndex] = -ampFixedDeltas[parIndex]; - } - - // finally update current mapping between oscillators and partials - indicesMapping[parIndex] = parCnt; - parCnt++; - } - actPartNum = parCnt; - // [NEON] if not multiple of 4... - if (actPartNum % 4 != 0) - addFakeOsc(); - - updatePrevControls(); -} - -void OscillatorBank::addFakeOsc() { - // ...calculate difference - int newPartNum = (actPartNum + 3) & ~0x3; - // ...add fake oscillators until total num is multiple of 4 - for (int i = actPartNum; i < newPartNum; i++) { - oscillatorAmplitudes[i] = 0; - oscillatorNormFrequencies[i] = 0; - oscillatorAmplitudeDerivatives[i] = 0; - oscillatorNormFreqDerivatives[i] = 0; - oscillatorPhases[i] = 0; - } - // ...and update num of active partials - actPartNum = newPartNum; -} - -void OscillatorBank::play(float vel) { - // set attack and release params according to velocity - //adsr.setAttackRate((minAttackTime + ((1 - vel) * deltaAttackTime)) * rate); - adsr.setAttackRate(minAttackTime * rate); - //adsr.setReleaseRate((minReleaseTime + (1 - vel) * deltaReleaseTime) * rate); - adsr.setReleaseRate(minReleaseTime * rate); - - // set timbre - hopNumTh = log((1 - vel) + 1) / log(2) * 20000; - - state = bank_toreset; -} - -//--------------------------------------------------------------------------------------------------------------------------- -// private methods -//--------------------------------------------------------------------------------------------------------------------------- - -bool OscillatorBank::loader(char *filename, int hopsize, int samplerate) { - rate = samplerate; - loaded = parser.parseFile(filename, hopsize, samplerate); - return loaded; -} - -int OscillatorBank::jumpToHop() { - int jumpGap = abs(jumpHop - currentHop / overSampling); // gaps in partial reference - - // can't jump to self dude - if (jumpGap == 0) - return 1; - - // direction is in general maintained with jump - if (jumpHop == 0) - setDirection(1); - else if (jumpHop == lastHop) - setDirection(-1); - - dbox_printf("\tJump from %d to %d\n", currentHop / overSampling, jumpHop); - dbox_printf("\tdirection %d\n", loopDir); - - currentHop = jumpHop * overSampling; - - if (nextEnvState() != 0) - return 0; // release has ended! - - checkSpeed(); - - int parIndex, localHop, targetHop; - float parDamp = 1; - int currentPartialHop = currentHop / overSampling; - int targetPartialHop = jumpHop; - - actPartNum = partials->activePartialNum[currentPartialHop]; - actPart = partials->activePartials[currentPartialHop]; - int targetActParNum = partials->activePartialNum[targetPartialHop]; - unsigned int *targetActPar = partials->activePartials[targetPartialHop]; - - envState = adsr.getState(); // to determine what state we will be in next hop [attack, decay, sustain, release] - - int parCnt = 0; - int currentHopReminder = currentHop % overSampling; - - // steps to walk where i am [bank of partial hop] from previous partial hop - int steps = currentHopReminder * (overSampling != 1); // no oversampling 0, oversampling and going ff currentHopReminder - - for (int i = 0; i < actPartNum; i++) { - // find partial and frame - parIndex = actPart[i]; - //localHop = partials->localPartialFrames[currentPartialHop][parIndex]; - localHop = currentPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file] - - // if this partial was over nyquist on previous hop... - if (nyquistCut[parIndex]) { - // ...restart from safe values - oscillatorPhases[parCnt] = 0; - //TODO add freqmove dependency - oscillatorNextNormFreq[parCnt] = - (partials->partialFrequencies[parIndex][localHop] - + freqFixedDeltas[parIndex] * steps * loopDir) - * frequencyScaler * prevPitchMultiplier; - oscillatorNextAmp[parCnt] = 0; - } else if (loopDir == 1) {// otherwise recover phase, target freq and target amp from previous frame - if ((localHop != 0) - || ((overSampling > 1) && (currentHopReminder != 0))) { - oscillatorPhases[parCnt] = - phaseCopies[indicesMapping[parIndex]]; - oscillatorNextNormFreq[parCnt] = - nextNormFreqCopies[indicesMapping[parIndex]]; - oscillatorNextAmp[parCnt] = - nextAmpCopies[indicesMapping[parIndex]]; - } else { // first oscillator hop [both for bank and partial], so no previous data are available - oscillatorPhases[parCnt] = 0; - //TODO add freqmove dependency - oscillatorNextNormFreq[parCnt] = - partials->partialFrequencies[parIndex][localHop] - * frequencyScaler * prevPitchMultiplier; - parDamp = calculateParDamping(parIndex, prevHopNumTh, - prevAdsrVal, oscillatorNextNormFreq[parCnt], - prevFilterNum, prevFilterFreqs, prevFilterQ); - oscillatorNextAmp[parCnt] = - partials->partialAmplitudes[parIndex][localHop] - * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - } - } else { - if (( (unsigned)localHop != partials->partialNumFrames[parIndex] - 1) - || ((overSampling > 1) && (currentHopReminder != 0))) { - oscillatorPhases[parCnt] = - phaseCopies[indicesMapping[parIndex]]; - oscillatorNextNormFreq[parCnt] = - nextNormFreqCopies[indicesMapping[parIndex]]; - oscillatorNextAmp[parCnt] = - nextAmpCopies[indicesMapping[parIndex]]; - } else // first oscillator hop [going backwards - both for bank and partial] , so no previous data are available, so retrieve where i am - { - oscillatorPhases[parCnt] = 0; - //TODO add freqmove dependency - oscillatorNextNormFreq[parCnt] = - partials->partialFrequencies[parIndex][localHop] - * frequencyScaler * prevPitchMultiplier; - parDamp = calculateParDamping(parIndex, prevHopNumTh, - prevAdsrVal, oscillatorNextNormFreq[parCnt], - prevFilterNum, prevFilterFreqs, prevFilterQ); - oscillatorNextAmp[parCnt] = - partials->partialAmplitudes[parIndex][localHop] - * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - } - } - // remove aliasing, skipping partial over nyquist freq - if (oscillatorNextNormFreq[parCnt] > nyqNorm) { - //cout << nyqNorm << endl; - nyquistCut[parIndex] = true; - continue; - } - nyquistCut[parIndex] = false; - - // check what happens of this partial at target hop - float targetFreqVal, targetAmpVal; - //targetHop = partials->localPartialFrames[targetPartialHop][parIndex]; - targetHop = targetPartialHop - partials->partialStartFrame[parIndex]; - - if (targetHop == -1) - targetFreqVal = targetAmpVal = 0; - else { - targetFreqVal = partials->partialFrequencies[parIndex][targetHop] - * frequencyScaler; // pitch shift will be multiplied later!!! - targetAmpVal = partials->partialFrequencies[parIndex][targetHop]; // parDamp will be multiplied later!!! - } - - // first set up freq, cos filter affects amplitude damping according to freq content - oscillatorNormFrequencies[parCnt] = oscillatorNextNormFreq[parCnt]; // to fix any possible drifts - // save next values, current for next round - oscillatorNextNormFreq[parCnt] = (freqMovement * targetFreqVal - + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex]) - * pitchMultiplier; - // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials - oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt] - - oscillatorNormFrequencies[parCnt]) / hopCounter; - // this second weird passage handles dissonance control, morphing between regular and mean frequencies - oscillatorNormFreqDerivatives[parCnt] = freqMovement - * oscillatorNormFreqDerivatives[parCnt] - + (1 - freqMovement) - * ((oscStatNormFrequenciesMean[parIndex] - * pitchMultiplier) - - oscillatorNormFrequencies[parCnt]) - / hopCounter; - - parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal, - oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ); - - // now amplitudes - oscillatorAmplitudes[parCnt] = oscillatorNextAmp[parCnt]; // to fix any possible drifts - // save next values, current for next round - oscillatorNextAmp[parCnt] = targetAmpVal * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - // to avoid bursts when transients are played backwards - if ((loopDir == -1) && (targetHop == 0) - && ((overSampling == 1) || (currentHopReminder == 0))) { - oscillatorNextAmp[parCnt] = 0; - } - // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials - oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt] - - oscillatorAmplitudes[parCnt]) / hopCounter; - - //if partial does not die at target, calculate deltas according to direction - if (targetHop != -1) { - freqFixedDeltas[parIndex] = - partials->partialFreqDelta[parIndex][targetHop] * loopDir - / overSampling; - ampFixedDeltas[parIndex] = - partials->partialAmpDelta[parIndex][targetHop] * loopDir - / overSampling; - } - - // finally update current mapping between oscillators and partials - indicesMapping[parIndex] = parCnt; - parCnt++; - } - actPartNum = parCnt; - - // now add the ones that start at target hop! - for (int i = 0; i < targetActParNum; i++) { - // find partial and frame - parIndex = targetActPar[i]; - //targetHop = partials->localPartialFrames[targetPartialHop][parIndex]; - targetHop = targetPartialHop - partials->partialStartFrame[parIndex]; // in Parser and Partials "frames" are what we call here "hops". These particular ones are local frames [see comment at top of file] - - // check if this partials was already active before the jump - //localHop = partials->localPartialFrames[currentPartialHop][parIndex]; - localHop = currentPartialHop - partials->partialStartFrame[parIndex]; - - // if yes, skip it - if (localHop != -1) - continue; - - // otherwise add it to active bunch and calcucalte values - - // first set up freq, cos filter affects amplitude damping according to freq content - oscillatorNormFrequencies[parCnt] = 0; - // save next values, current for next round - oscillatorNextNormFreq[parCnt] = (freqMovement - * partials->partialFrequencies[parIndex][targetHop] - * frequencyScaler - + (1 - freqMovement) * oscStatNormFrequenciesMean[parIndex]) - * pitchMultiplier; - // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials - oscillatorNormFreqDerivatives[parCnt] = (oscillatorNextNormFreq[parCnt] - - oscillatorNormFrequencies[parCnt]) / hopCounter; - // this second weird passage handles dissonance control, morphing between regular and mean frequencies - oscillatorNormFreqDerivatives[parCnt] = freqMovement - * oscillatorNormFreqDerivatives[parCnt] - + (1 - freqMovement) - * ((oscStatNormFrequenciesMean[parIndex] - * pitchMultiplier) - - oscillatorNormFrequencies[parCnt]) - / hopCounter; - - parDamp = calculateParDamping(parIndex, hopNumTh, adsrVal, - oscillatorNextNormFreq[parCnt], filterNum, filterFreqs, filterQ); - - // now amplitudes - oscillatorAmplitudes[parCnt] = 0; - // save next values, current for next round - oscillatorNextAmp[parCnt] = - partials->partialFrequencies[parIndex][targetHop] * parDamp; - if(oscillatorNextAmp[parCnt] > 1) - oscillatorNextAmp[parCnt] = 1; - // derivatives are (next hop value*next damping) - (current hop value*current damping) ---> next hop must be available, in both directions, because of control on active partials - oscillatorAmplitudeDerivatives[parCnt] = (oscillatorNextAmp[parCnt] - - oscillatorAmplitudes[parCnt]) / hopCounter; - - //calculate deltas according to direction - freqFixedDeltas[parIndex] = - partials->partialFreqDelta[parIndex][targetHop] * loopDir - / overSampling; - ampFixedDeltas[parIndex] = - partials->partialAmpDelta[parIndex][targetHop] * loopDir - / overSampling; - - // finally update current mapping between oscillators and partials - indicesMapping[parIndex] = parCnt; - parCnt++; - - } - // [NEON] if not multiple of 4... - if (actPartNum % 4 != 0) - addFakeOsc(); - - updatePrevControls(); - - jumpHop = -1; - - return 0; -} - -int OscillatorBank::nextEnvState() { - /* - envState = Attack.getState(); // to determine what state we are in [attack, decay, sustain, release] - - // osc bank is playing the tail and the tail ends... - if( (state == bank_playing)&&(envState == env_idle) ) - { - state = bank_stopped; // ...stop bank - return 1; // and return immediately - } - else if( (envState == env_attack) || (envState == env_decay) ) - { - // run envelopes until next frame - dampWeight = Attack.process(hopSize); - } - else if(envState == env_release) - { - // run envelopes until next frame - dampWeight = Attack.process(hopSize); - releaseDamp = Release.process(hopSize); - }*/ - - envState = adsr.getState(); - // osc bank is playing the tail and the tail ends... - if ((state == bank_playing) && (envState == env_idle)) { - state = bank_stopped; // ...stop bank - adsrVal = 0; - return 1; // and return immediately - } else - adsrVal = adsr.process(hopSize); - - return 0; -} - -void OscillatorBank::checkDirection() { - // end of the loop or end of file - if (((currentHop >= loopEndHop) && (loopDir == 1)) - || ((currentHop >= lastHop) && (loopDir == 1))) { - // move backwards - setDirection(-1); - //dbox_printf("backward from %d\n", loopEndHop); - } else if (((currentHop <= loopStartHop) && (loopDir == -1)) - || ((currentHop <= 0) && (loopDir == -1))) // start of the loop or start of file - { - // move forward - setDirection(1); - //dbox_printf("forward from %d\n", loopStartHop); - } -} - -void OscillatorBank::checkSpeed() { - // speed control [alike on highways, LOL] - if (nextSpeed > 0) { - nextSpeed = (nextSpeed < maxSpeed) ? nextSpeed : maxSpeed; - nextSpeed = (nextSpeed > minSpeed) ? nextSpeed : minSpeed; - speed = nextSpeed; - nextSpeed = -1; - } - hopCounter = hopSize / speed; -} - -int OscillatorBank::checkJump() { - //check if has to jump somewhere - if (jumpHop > -1) { - // needs to jump! - if (jumpToHop() == 0) - return 0; - } - return 1; // no jump -} - -bool OscillatorBank::checkOversampling() { - //TODO fix this, but need andrew to fix oversampling multiple of period size - // if partialsHopSize is not a multiple of oversampling, change hop size to periodically match next partial hop - if (hopSizeReminder > 0) { - // if next osc bank hop overtakes next partial hop... - if ((currentHop + loopDir) * hopSize > partialsHopSize) { - hopSize = hopSizeReminder; // ...shrink osc bank hop size to match partial hop - return true; // and set next hop as matching with next partial hop - } - } else if (((currentHop + (1 - loopDirShift)) % overSampling) == 0) // if next osc bank hop matches next partial hop - return true; // ...mark next hop as partial hop - - return false; // ,otherwise mark next hop as osc bank hop -} - -void OscillatorBank::updatePrevControls() { - prevAdsrVal = adsrVal; - prevAmpTh = ampTh; - prevHopNumTh = hopNumTh; - prevPitchMultiplier = pitchMultiplier; - prevFreqMovement = freqMovement; - prevFilterNum = filterNum; - memcpy(prevFilterFreqs, filterFreqs, filterNum * sizeof(float)); - memcpy(prevFilterQ, filterQ, filterNum * sizeof(float)); -} - -float OscillatorBank::calculateParDamping(int parIndex, int hopNTh, - float adsrVl, float nextFreq, int filNum, float *filFreq, float *filQ) { - float parDamp = 1; - - // timbre - parDamp = ((float) (oscStatNumHops[parIndex] + 1)) / (hopNTh + 1); - parDamp = (parDamp > 1) ? 1 : parDamp; - parDamp = adsrVl * parDamp; - - //filters - - float filterWeights[MAX_TOUCHES]; - float filterDamp[MAX_TOUCHES]; - float filDist; - float filterWeightsAcc; - float filDmp; - float filAmp; - -// band reject notch filter -// float dist, dmp; -// for(int k=0; k<filterNum; k++) -// { -// dist = fabs(oscillatorNextNormFreq[parCnt]-filterFreqs[k]); -// if(dist<=filterQ[k]) -// { -// dmp = dist/filterQ[k]; -// parDamp *= dmp*dmp*dmp; -// } -// } - - - // each filter is a band pass notch filter - - // if at least one is active - if (filNum > 0) { - // reset values - filDist = 0; - filterWeightsAcc = 0; - filDmp = 0; - filAmp = 0; - // for each filter - for (int k = 0; k < filNum; k++) { - // here are a couple of kludges to boost sound output of hi freq filters - - // damping effect of filter increases with distance, but decreases with filter frequency [kludge] - float mul = ((filterMaxF-nextFreq)/filterMaxF) * 0.9 + 0.1 ; - //filDist = fabs(nextFreq - filFreq[k])*( ((exp(a*4)-1)/EXP_DENOM) * 0.9 + 0.1 ); - filDist = fabs(nextFreq - filFreq[k])*mul; - - // these to merge all filters contributions according to distance - filterWeights[k] = filterMaxF - filDist; - filterWeightsAcc += filterWeights[k]; - // freqs very close to filter center are slightly amplified - // the size of this amp area and the effect of amplification increase with frequency [kludge] - if (filDist - < filterAmpMinF - + (filterAmpMaxF*(1-mul) - filterAmpMinF) * (1 - filQ[k]) ) - filAmp = filQ[k] * filterAmpMul*(1-mul); - else - filAmp = 0; - // actual damping - filDmp = 1 / (filDist * filQ[k]); - filDmp = (filDmp > 1) ? 1 : filDmp; - // sum damp+amplification - filterDamp[k] = filDmp + filAmp; - } - // do weighted mean to merge all filters contributions - filDmp = 0; - for (int k = 0; k < filNum; k++) - filDmp += filterDamp[k] * filterWeights[k]; - filDmp /= filterWeightsAcc; - // apply - parDamp *= filDmp; - } - - - return parDamp; -}
--- a/examples/d-box/OscillatorBank.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * OscillatorBank.h - * - * Created on: May 23, 2014 - * Author: Victor Zappi and Andrew McPherson - */ - -#ifndef OSCILLATORBANK_H_ -#define OSCILLATORBANK_H_ - - -#include <string> - -#include "spear_parser.h" -#include "ADSR.h" -#include "config.h" - -using namespace std; - -enum OscBankstates {bank_stopped, bank_playing, bank_toreset}; - -class OscillatorBank -{ -public: - OscillatorBank(); - OscillatorBank(string filename, int hopsize=-1, int samplerate=44100); - OscillatorBank(char *filename, int hopsize=-1, int samplerate=44100); - ~OscillatorBank(); - float *oscillatorPhases; - float *oscillatorNormFrequencies; - float *oscillatorNormFreqDerivatives; - float *oscillatorAmplitudes; - float *oscillatorAmplitudeDerivatives; - float *oscStatNormFrequenciesMean; - float *oscStatNumHops; - OscBankstates state; - bool note; - int actPartNum; - unsigned int *actPart; - int hopCounter; - int lookupTableSize; - float *lookupTable; - float ampTh; - int hopNumTh; - float pitchMultiplier; - float freqMovement; - int filterNum; - float filterFreqs[5]; - float filterQ[5]; - float filterMaxF; - float filterAmpMinF; - float filterAmpMaxF; - float filterAmpMul; - - bool loadFile(string filename, int hopsize=-1, int samplerate=44100); - bool loadFile(char *filename, int hopsize=-1, int samplerate=44100); - bool initBank(int oversamp=1); - void resetOscillators(); - int getHopSize() { return hopSize; } - void nextHop(); - void setLoopHops(int start, int end); - void play(float vel); - void stop(); - void afterTouch(float vel); - int getEnvelopeState(); - float getFrequencyScaler(); - void setSpeed(float sp); - float getSpeed(); - float getMaxSpeed(); - float getMinSpeed(); - void setJumpHop(int hop); - int getLastHop(); - int getCurrentHop() { return currentHop; } - -private: - - bool loaded; - int numOfPartials; - int numOfOscillators; - int partialsHopSize; - int overSampling; - int hopSize; - int hopSizeReminder; - int oscBankHopSize; - float frequencyScaler; - float nyqNorm; - int lastHop; - int currentHop; - int loopDir; - int loopDirShift; - int loopStartHop; - int loopEndHop; - int *indicesMapping; - float *phaseCopies; - float *oscillatorNextNormFreq; - float *oscillatorNextAmp; - float *nextNormFreqCopies; - float *nextAmpCopies; - float *freqFixedDeltas; - float *ampFixedDeltas; - bool *nyquistCut; - Spear_parser parser; - Partials *partials; - ADSR adsr; - float minAttackTime; - float deltaAttackTime; - float minReleaseTime; - float deltaReleaseTime; - int envState; - int rate; - float speed; - float nextSpeed; - float maxSpeed; - float minSpeed; - int jumpHop; - float adsrVal; - float prevAdsrVal; - float prevAmpTh; - int prevHopNumTh; - float prevPitchMultiplier; - float prevFreqMovement; - int prevFilterNum; - float prevFilterFreqs[5]; - float prevFilterQ[5]; - - bool loader(char *filename, int hopsize=-1, int samplerate=44100); - void addFakeOsc(); - void nextOscBankHop(); - void nextPartialHop(); - int jumpToHop(); - void setDirection(int dir); - int nextEnvState(); - void checkDirection(); - void checkSpeed(); - int checkJump(); - bool checkOversampling(); - void updatePrevControls(); - float calculateParDamping(int parIndex, int hopNTh, float adsrVl, float nextFreq, - int filNum, float *filFreq, float *filQ); -}; - -inline bool OscillatorBank::loadFile(string filename, int hopsize, int samplerate) -{ - return loader((char *)filename.c_str(), hopsize, samplerate); -} - -inline bool OscillatorBank::loadFile(char *filename, int hopsize, int samplerate) -{ - return loader(filename, hopsize, samplerate); -} - -inline void OscillatorBank::setLoopHops(int start, int end) -{ - if(start > end) - end = start; - - if(start<0) - start = 0; - else if(start>lastHop) - start = 0; - if(end < 1) - end = 1; - end = (end<=lastHop) ? end : lastHop; - - // set it, take into consideration hop oversampling - loopStartHop = start*overSampling; - loopEndHop = end*overSampling; -} - -inline void OscillatorBank::stop() -{ - note = false; - adsr.gate(0); -} - -inline float OscillatorBank::getFrequencyScaler() -{ - return frequencyScaler; -} - -inline void OscillatorBank::afterTouch(float vel) -{ - hopNumTh = log((1-vel)+1)/log(2)*20000; - if(adsr.getState()==env_attack) - adsr.setAttackRate( (minAttackTime + ( (1-vel)*deltaAttackTime )) * rate ); - adsr.setReleaseRate( (minReleaseTime+(1-vel)*deltaReleaseTime)* rate ); -} - -inline int OscillatorBank::getEnvelopeState() -{ - return envState; -} - -inline void OscillatorBank::setSpeed(float sp) -{ - nextSpeed = sp; -} - -inline float OscillatorBank::getSpeed() -{ - return speed; -} - -inline float OscillatorBank::getMaxSpeed() -{ - return maxSpeed; -} - -inline float OscillatorBank::getMinSpeed() -{ - return minSpeed; -} - -inline void OscillatorBank::setJumpHop(int hop) -{ - if(hop<0) - return; - hop = (hop<=lastHop) ? hop : lastHop; - jumpHop = hop; -} - -inline void OscillatorBank::setDirection(int dir) -{ - if(dir>=0) - { - loopDir = 1; - loopDirShift = 0; - } - else - { - loopDir = -1; - loopDirShift = 1; - } -} - -inline int OscillatorBank::getLastHop() -{ - return lastHop; -} -#endif /* OSCILLATORBANK_H_ */
--- a/examples/d-box/PinkNoise.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -/* - * PinkNoise.cpp - * - * Created on: Oct 15, 2013 - * Author: Victor Zappi - */ - -#include "PinkNoise.h" - -// miserable definition to init static const array members...otherwise gets error when PinkNoise.h is included into another header file -const float PinkNoise::A[] = { 0.02109238, 0.07113478, 0.68873558 }; // rescaled by (1+P)/(1-P) -const float PinkNoise::P[] = { 0.3190, 0.7756, 0.9613 }; - - - -
--- a/examples/d-box/PinkNoise.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -#ifndef _PinkNoise_H -#define _PinkNoise_H - -// Technique by Larry "RidgeRat" Trammell 3/2006 -// http://home.earthlink.net/~ltrammell/tech/pinkalg.htm -// implementation and optimization by David Lowenfels - -#include <cstdlib> -#include <ctime> -#include <stdlib.h> - -#define PINK_NOISE_NUM_STAGES 3 - -class PinkNoise { -public: - PinkNoise() { - srand ( time(NULL) ); // initialize random generator - clear(); - } - - void clear() { - for( size_t i=0; i< PINK_NOISE_NUM_STAGES; i++ ) - state[ i ] = 0.0; - } - - float tick() { - static const float RMI2 = 2.0 / float(RAND_MAX); // + 1.0; // change for range [0,1) - static const float offset = A[0] + A[1] + A[2]; - - // unrolled loop - float temp = float( rand() ); - state[0] = P[0] * (state[0] - temp) + temp; - temp = float( rand() ); - state[1] = P[1] * (state[1] - temp) + temp; - temp = float( rand() ); - state[2] = P[2] * (state[2] - temp) + temp; - return ( A[0]*state[0] + A[1]*state[1] + A[2]*state[2] )*RMI2 - offset; - } - -protected: - float state[ PINK_NOISE_NUM_STAGES ]; - static const float A[ PINK_NOISE_NUM_STAGES ]; - static const float P[ PINK_NOISE_NUM_STAGES ]; -}; - -//const float PinkNoise::A[] = { 0.02109238, 0.07113478, 0.68873558 }; // rescaled by (1+P)/(1-P) -//const float PinkNoise::P[] = { 0.3190, 0.7756, 0.9613 }; - -#endif
--- a/examples/d-box/StatusLED.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * StatusLED.cpp - * - * Routines for manipulating the status LED - * - * (c) 2014 Andrew McPherson and Victor Zappi - * QMUL, Centre for Digital Music - */ - -#include <iostream> -#include "StatusLED.h" -#include <GPIOcontrol.h> - -extern int gShouldStop; -extern int gVerbose; - -using namespace std; - -StatusLED::StatusLED() { - gpio_number = -1; - milliseconds_on = 0; - milliseconds_off = 100; - blink_thread = -1; -} - -StatusLED::~StatusLED() { - if(gpio_number >= 0) { - this_should_stop = true; - pthread_join(blink_thread, NULL); - gpio_unexport(gpio_number); - } -} - -bool StatusLED::init(int gpio_pin) { - gpio_number = gpio_pin; - this_should_stop = false; - - if(gpio_export(gpio_number)) { - if(gVerbose) - cout << "Warning: couldn't export status LED pin\n"; - } - if(gpio_set_dir(gpio_number, OUTPUT_PIN)) { - if(gVerbose) - cout << "Couldn't set direction on status LED pin\n"; - return false; - } - if(gpio_set_value(gpio_number, LOW)) { - if(gVerbose) - cout << "Couldn't set value on status LED pin\n"; - return false; - } - - - if ( pthread_create(&blink_thread, NULL, static_blink_loop, this) ) - { - cout << "Error:unable to create status LED thread" << endl; - return false; - } - - return true; -} - -void StatusLED::on() { - milliseconds_on = 100; - milliseconds_off = 0; -} - -void StatusLED::off() { - milliseconds_on = 0; - milliseconds_off = 100; -} - -void StatusLED::blink(int ms_on, int ms_off) { - milliseconds_on = ms_on; - milliseconds_off = ms_off; -} - -void* StatusLED::blink_loop(void *) { - while(!gShouldStop && !this_should_stop) { - if(milliseconds_on != 0) - gpio_set_value(gpio_number, HIGH); - usleep(1000 * milliseconds_on); - if(gShouldStop) - break; - if(milliseconds_off != 0) - gpio_set_value(gpio_number, LOW); - usleep(1000 * milliseconds_off); - } - pthread_exit(NULL); -}
--- a/examples/d-box/StatusLED.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * StatusLED.h - * - * - */ - -#ifndef STATUSLED_H_ -#define STATUSLED_H_ - -#include <pthread.h> -#include <unistd.h> - -class StatusLED -{ -public: - StatusLED(); - ~StatusLED(); - - bool init(int gpio_pin); - - void on(); - void off(); - void blink(int ms_on, int ms_off); - - static void *static_blink_loop(void *data) { - ((StatusLED*)data)->blink_loop(NULL); - return 0; - } - - void* blink_loop(void *); - -private: - int gpio_number; - int milliseconds_on, milliseconds_off; - bool this_should_stop; - pthread_t blink_thread; -}; - -#endif // STATUSLED_H_
--- a/examples/d-box/audio_routines.S Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -@ -@ audio_routines.S -@ -@ NEON-based functions for time-critical audio processing -@ -@ Andrew McPherson 2014 -@ Queen Mary University of London -@ - - .syntax unified - .arch armv7-a - .fpu neon - -@ void oscillator_bank_neon(int numAudioFrames, float *audioOut, -@ int activePartialNum, int lookupTableSize, -@ float *phases, float *frequencies, float *amplitudes, -@ float *freqDerivatives, float *ampDerivatives, -@ float *lookupTable); - -@ Registers: -@ r0: numAudioFrames How many frames to render -@ r1: audioOut Buffer for audio output samples [stereo] -@ r2: activePartialNum How many active partials to render -@ r3: lookupTableSize Size of lookup table -@ ---- other arguments start on the stack and are moved: ----- -@ r4: phases Phase of each oscillator (pointer) -@ r5: frequencies Normalised frequency of each oscillator (pointer) -@ r6: amplitudes Normalised amplitude of each oscillator (pointer) -@ r7: freqDerivatives Derivative of frequency for each oscillator (pointer) -@ r8: ampDerivatives Derivative of amplitude for each oscillator (pointer) -@ r9: lookupTable Lookup table containing one oscillation -@ -@ Alignment requirements: -@ audioOut: 8-byte boundary -@ phases: 16-byte boundary -@ frequencies: 16-byte boundary -@ amplitudes: 16-byte boundary -@ freqDerivatives: 16-byte bounary -@ ampDerivatives: 16-byte boundary -@ lookupTable: 4-byte boundary (TODO: check this) - - .align 2 - .global oscillator_bank_neon - .thumb - .thumb_func - .type oscillator_bank_neon, %function -oscillator_bank_neon: - - -dSample .dn D6.F32 -qPhases .qn Q8.F32 -dPhases_0 .dn D16.F32 -dPhases_1 .dn D17.F32 -qFreqs .qn Q9.F32 -dFreqs_0 .dn D18.F32 -dFreqs_1 .dn D19.F32 -qAmps .qn Q10.F32 -dAmps_0 .dn D20.F32 -dAmps_1 .dn D21.F32 -qFreqDs .qn Q11.F32 -dFreqDs_0 .dn D22.F32 -dFreqDs_1 .dn D23.F32 -qAmpDs .qn Q12.F32 -dAmpDs_0 .dn D24.F32 -dAmpDs_1 .dn D25.F32 - -qBaseInts .qn Q13.U32 @ Base indexes: unsigned ints x4 -dBaseInts_0 .dn D26.U32 -dBaseInts_1 .dn D27.U32 -qFractions .qn Q14.F32 @ Fraction indexes: floats x4 -qTableBase .qn Q15.U32 @ Base of lookup table - - cmp r0, #0 @ Check for trivial case 1: zero frames - it eq - bxeq lr @ Return if that's the case (otherwise might have odd behaviour) - cmp r2, #4 @ Check for trivial case 2: zero oscillators - it lt - bxlt lr @ Return if that's the case - - push {r4-r11} @ Now arguments start 32 bytes above SP - add r11, sp, #32 @ Pointer to 32 bytes into the stack - ldm r11, {r4-r9} @ Load 6 arguments into registers - - vdup qTableBase, r9 @ Move lookup table base index into 4 ints - - @ Outer loop: iterate over the number of oscillators, choosing 4 at a - @ time to work with. -oscbank_oscillator_loop: - vld1 {dPhases_0, dPhases_1}, [r4] @ no increment; will store at end of sample loop - vld1 {dFreqs_0, dFreqs_1}, [r5] - vld1 {dAmps_0, dAmps_1}, [r6] - vld1 {dFreqDs_0, dFreqDs_1}, [r7]! @ increment; won't update at end of sample loop - vld1 {dAmpDs_0, dAmpDs_1}, [r8]! - - push {r0-r1,r4-r8} - @ --- inner loop: iterate over the number of samples --- -oscbank_sample_loop: - vcvt qBaseInts, qPhases @ Take floor(phases) - vmov q2.f32, #1.0 @ Load 1.0 into every slot of q2 - vshl q0.U32, qBaseInts, #2 @ Shift the indexes left 2 (*4 for float addressing) - vcvt qFractions, qBaseInts @ int back to float - vadd q0.U32, q0.U32, qTableBase @ Find memory addresses - - vmov r4, r5, d0 @ Move two indexes to ARM registers - vmov r6, r7, d1 @ Move two more indexes to ARM registers - vsub qFractions, qPhases, qFractions @ fraction = phase - floor(phase) - - vldr.64 d0, [r4] @ Load two consecutive floats at each location - vldr.64 d1, [r5] @ These hold the previous and following samples in the table - vldr.64 d2, [r6] @ TODO: check whether these work at 4-byte alignment - vldr.64 d3, [r7] - - @ Format at this point: - @ Osc0(before) Osc0(after) Osc1(before) Osc1(after) Osc2(before) Osc2(after) Osc3(before) Osc3(after) - @ We want: - @ Osc0(before) Osc1(before) Osc2(before) Osc3(before) Osc0(after) Osc1(after) Osc2(after) Osc3(after) - - vuzp.32 q0, q1 @ Now q0 contains before, q1 contains after - vsub q2.f32, q2.f32, qFractions @ q2 = 1.0 - fraction - vmul q1.f32, q1.f32, qFractions @ q1 = fraction * after - vmul q0.f32, q0.f32, q2.f32 @ q0 = (1.0 - fraction) * before - - vadd qPhases, qPhases, qFreqs @ Update phases - vadd qFreqs, qFreqs, qFreqDs @ Update frequencies - - vadd q0.f32, q0.f32, q1.f32 @ Add two interpolated components to get the final sample - vdup q2.u32, r3 @ Put lookup table size into each element of q2 - vcvt qBaseInts, qPhases @ Take floor of new phases - vmul q0.f32, q0.f32, qAmps @ Multiply samples by current amplitude - - vld1 dSample, [r1] @ Load the current stereo samples - vpadd d2.f32, d0.f32, d1.f32 @ Pairwise accumulate q0 (output sample) into d2 - - vand q2, q2, qBaseInts @ Logical AND of new phase int leaves 1 bit set only if phase >= table size - vpadd d3.f32, d2.f32, d2.f32 @ Pairwise accumulate d2 into d0 --> d0[0] and d0[1] both hold total of 4 oscillators - vadd qAmps, qAmps, qAmpDs @ Update amplitudes - vcvt q0.f32, q2.u32 @ Convert int back to float after AND operation - - vadd dSample, dSample, d3.f32 @ Add oscillator outputs to each channel - - subs r0, r0, #1 @ numFrames-- - vsub qPhases, qPhases, q0.f32 @ Keep phases in table range - vst1 dSample, [r1]! @ Store back in buffer and increment by 8 - - it gt - bgt oscbank_sample_loop @ Loop if numFrames > 0 - - @ --- end inner loop --- - pop {r0-r1,r4-r8} @ Restore registers: restores audioOut and numFrames, among others - - vst1 {dPhases_0, dPhases_1}, [r4]! @ Store phases back to array - vst1 {dFreqs_0, dFreqs_1}, [r5]! @ Store frequencies back to array - vst1 {dAmps_0, dAmps_1}, [r6]! @ Store amplitudes back to array - @ No need to update r7, r8 - - subs r2, r2, #4 @ numPartials -= 4 - it gt - bgt oscbank_oscillator_loop @ Loop if numPartials > 0 - - pop {r4-r11} - bx lr - - -@ void wavetable_interpolate_neon(int numSamplesIn, int numSamplesOut, -@ float *tableIn, float *tableOut); - -@ Registers: -@ r0: numSamplesIn Size of the input table -@ r1: numSamplesOut Size of the output table -@ r2: tableIn Pointer to input table -@ r3: tableOut Pointer to output table - -@ Alignment requirements: -@ tableIn: 8-byte boundary -@ tableOut: 8-byte boundary - - .align 2 - .global wavetable_interpolate_neon - .thumb - .thumb_func - .type wavetable_interpolate_neon, %function -wavetable_interpolate_neon: - @ TODO - - bx lr
--- a/examples/d-box/config.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * config.h - * - * Global settings for D-Box project - * - * Andrew McPherson and Victor Zappi 2014 - */ - - -#ifndef DBOX_CONFIG_H_ -#define DBOX_CONFIG_H_ - - -/* Number of maximum touches used by the TouchKey sensors */ -#define MAX_TOUCHES 5 - -// for sensor 1 filter -#define EXP_DENOM 53.5981500331 // exp(4)-1 - -/* Define this to use Xenomai real-time extensions */ -#define DBOX_USE_XENOMAI -//#define OLD_OSCBANK - -#ifdef DBOX_USE_XENOMAI -// Xenomai-specific includes -#include <sys/mman.h> - -#include <native/task.h> -#include <native/timer.h> -#include <rtdk.h> -#endif - -#ifdef DBOX_USE_XENOMAI - -#define dbox_printf rt_printf - -#else - -#define dbox_printf printf - -#endif - -#endif /* DBOX_CONFIG_H */
--- a/examples/d-box/how_to_build_dbox.txt Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -The D-Box code can be built on the board using the scripts included with -Bela. To build the code, do the following from the scripts/ directory: - -./setup_board.sh # Only if Bela is not already copied to the board -./build_project.sh -n ../projects/d-box # -n means don't run yet - -You will now need to copy the .dbx sound files to the box. These need to -be in a directory: /root/d-box/sounds - -Log into the board via ssh to create the d-box directory, or run: - -ssh root@192.168.7.2 "mkdir /root/d-box" - -Now copy the .dbx files from a source of your choice to the board. Assuming -they are in a directory called "sounds": - -scp -r sounds root@192.168.7.2:/root/d-box/ - -Now you can run the D-Box program to make sure it plays. You will need the -sensors and matrix connected to the box (i.e. a complete hardware D-Box). -From the scripts/ directory: - -./run_project.sh -f -c "-q 24 -r 25 -t 2 -s -p 2 -l 0 -u 0 -i 1 -n f -g 3 -v" - -If this plays properly, the D-Box can then be set to run automatically on boot: - -./set_startup.sh -l -c "-q 24 -r 25 -t 2 -s -p 2 -l 0 -u 0 -i 1 -n f -g 3 -v" - -If at any time you want to stop the D-Box program running, you can run: - -./stop_running.sh - -To turn off further autoboot, run: - -./set_startup.sh -n
--- a/examples/d-box/logger.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * logger.cpp - * - * Created on: Aug 6, 2014 - * Author: VIctor Zappi and Andrew McPherson - */ - -#include "logger.h" - -// main extern vars -extern int gShouldStop; -extern int gVerbose; - -// file nanme extern vars -extern char gId; -extern char gGroup; - - -// logged extern vars -extern int s0TouchNum; -extern float s0Touches_[MAX_TOUCHES]; -extern float s0Size_[MAX_TOUCHES]; -extern int s0LastIndex; - -extern int s1TouchNum; -extern float s1Touches_[MAX_TOUCHES]; -extern float s1Size_[MAX_TOUCHES]; -extern int s1LastIndex; - -extern int fsr; - - - -string logPath = "/boot/uboot/instrumentLog"; -string logFileIncipit = "/datalog"; -string logFileName = ""; -ofstream logFile; -timeval logTimeVal; -unsigned long long logTimeOrig; -int logCnt = 0; // counts how many lines so far -int logCntSwap = 50; // how many log lines before closing and re-opening the file - - -// create the log file, using incremental name convention -int initLogLoop() -{ - if(gVerbose==1) - cout << "---------------->Init Log Thread" << endl; - - - // transform chars into strings via stringstream objs - stringstream id_ss, group_ss, freedom_ss; - id_ss << gId; - group_ss << gGroup; - - int logNum = -1; - int logMax = -1; - int pathLen = logPath.length() + logFileIncipit.length() + 4; // + 4 is: "_", id, group, "_" - glob_t globbuf; - - // check how many log files are already there, and choose name according to this - glob( (logPath + logFileIncipit + "*").c_str(), 0, NULL, &globbuf); - - // cycle through all and find the highest index - for(unsigned int i=0; i<globbuf.gl_pathc; i++) - { - // playing with 0-9 char digits, forming a number from 0 to 9999 - logNum = (globbuf.gl_pathv[i][pathLen]-48) * 1000; // 42 to 45 are the indices of the chars forming the file index - logNum += (globbuf.gl_pathv[i][pathLen+1]-48) * 100; - logNum += (globbuf.gl_pathv[i][pathLen+2]-48) * 10; - logNum += globbuf.gl_pathv[i][pathLen+3]-48; - if(logNum > logMax) - logMax = logNum; - } - logNum = logMax + 1; // new index - - globfree(&globbuf); - - ostringstream numString; - numString << setw (4) << setfill ('0') << logNum; // set integer with 4 figures - - // here are the new names: PATH + DIR + INCIPIT + _ + id + group + freedom + _ + NUM (4figures) + _A.txt - logFileName = logPath + logFileIncipit; - logFileName += "_" + id_ss.str() + group_ss.str() + freedom_ss.str(); - logFileName += "_" + numString.str(); //static_cast<ostringstream*>( &(ostringstream() << logNum) )->str(); - logFileName += ".txt"; - - - // create new files - FILE *fp_a = fopen(logFileName.c_str(), "wb"); - if(!fp_a) - { - dbox_printf("Cannot create files...\n"); - return 2; - } - fclose(fp_a); - - // ready to append - logFile.open(logFileName.c_str(), ios::out | ios::app); - - dbox_printf("Logging on file %s\n", logFileName.c_str()); - - return 0; -} - - -void writeData(unsigned long long time) -{ - - float fsr_ = ((float)(1799-fsr)/1799.0); - logFile << time << "\t" // timestamp - << s0TouchNum << "\t"; // sensor 0 touch count - for(int i=0; i<MAX_TOUCHES; i++) - logFile << s0Touches_[i] << "\t"; // sensor 0 touch pos x - for(int i=0; i<MAX_TOUCHES; i++) - logFile << s0Size_[i] << "\t"; // sensor 0 touch size - logFile << s0LastIndex << "\t" // sensor 0 last index - << fsr_ << "\t" // sensor 0 FSR pressure - << s1TouchNum << "\t"; // sensor 1 touch count - for(int i=0; i<MAX_TOUCHES; i++) - logFile << s1Touches_[i] << "\t"; // sensor 1 touch pos x - for(int i=0; i<MAX_TOUCHES; i++) - logFile << s1Size_[i] << "\t"; // sensor 1 touch size - logFile << s1LastIndex << "\t" // sensor 1 last index - //... AND SO ON - << "\n"; - - //dbox_printf("%d\n", s0LastIndex); - //dbox_printf("s0TouchNum: %d\t s0Touches[0]: %f\t s0Size[0]: %f\t s0LastIndex: %d\n", s0TouchNum, s0Touches_[0], s0Size_[0], s0LastIndex); - -} - -void logData(unsigned long long time) -{ - // if it's time to change write-file - if(logCnt >= logCntSwap) - { - logFile.close(); // close file, dump stream - logCnt = 0; // ready for another whole round - - // open again, ready to append - logFile.open(logFileName.c_str(), ios::out | ios::app); - } - - writeData(time); - - logCnt++; -} - - - - -void *logLoop(void *) -{ - set_realtime_priority(10); - - if(gVerbose==1) - dbox_printf("_________________Log Thread!\n"); - - // get time reference - gettimeofday(&logTimeVal, NULL); - logData(0); - - logTimeOrig = logTimeVal.tv_usec; - logTimeOrig *= 0.001; // from usec to msec - logTimeOrig += logTimeVal.tv_sec*1000; // from sec to msec - - usleep(5000); - - while(!gShouldStop) - { - gettimeofday(&logTimeVal, NULL); - unsigned long long currentTime = logTimeVal.tv_usec; - currentTime *= 0.001; // from usec to msec - currentTime += logTimeVal.tv_sec*1000; // from sec to msec - - logData(currentTime-logTimeOrig); - - usleep(5000); - } - - if(logFile!=NULL) - logFile.close(); - - dbox_printf("log thread ended\n"); - - return (void *)0; -}
--- a/examples/d-box/logger.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * logger.h - * - * Created on: Aug 6, 2014 - * Author: Victor Zappi and Andrew McPherson - */ - -#ifndef LOGGER_H_ -#define LOGGER_H_ - -#include <string.h> -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> -#include <fstream> // file handle -#include <iostream> // stringstream -#include <sstream> // stringstream -#include <glob.h> // alternative to dirent.h to handle files in dirs -#include <iomanip> // setfill -#include <sys/time.h> // elapsed time - -#include "config.h" -#include "prio.h" - -using namespace std; - -int initLogLoop(); -void *logLoop(void *); - - -#endif /* LOGGER_H_ */
--- a/examples/d-box/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,491 +0,0 @@ -/* - * RTAudio.cpp - * - * Central control code for hard real-time audio on BeagleBone Black - * using PRU and Xenomai Linux extensions. This code began as part - * of the Hackable Instruments project (EPSRC) at Queen Mary University - * of London, 2013-14. - * - * (c) 2014 Victor Zappi and Andrew McPherson - * Queen Mary University of London - */ - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <math.h> -#include <iostream> -#include <signal.h> // interrupt handler -#include <assert.h> -#include <vector> -#include <dirent.h> // to handle files in dirs -#include <mntent.h> // to check if device is mounted -#include <sys/mount.h> // mount() -#include <sys/time.h> // elapsed time -#include <ne10/NE10.h> // neon library - -// thread priority -#include <pthread.h> -#include <sched.h> - -// get_opt_long -#include <getopt.h> - -#include <Bela.h> -#include "config.h" -#include "sensors.h" -#include "OscillatorBank.h" -#include "StatusLED.h" -#include "logger.h" - -using namespace std; - -//---------------------------------------- -// main variables -//---------------------------------------- -vector<OscillatorBank*> gOscBanks; -int gCurrentOscBank = 0; -int gNextOscBank = 0; -int oscBnkOversampling = 1; // oscillator bank frame oversampling - -const int kStatusLEDPin = 30; // P9-11 controls status LED -StatusLED gStatusLED; - -pthread_t keyboardThread; -pthread_t logThread; - -// general settings -int gVerbose = 0; // verbose flag -bool forceKeyboard = true; // activate/deactivate keyboard control -bool forceSensors = false; // activate/deactivate sensor control -bool forceLog = true; // activate/deactivate log on boot partition -bool useSD = true; // activate/deactivate file loading from SD [as opposed to emmc] -bool useAudioTest = false; // activate/deactivate sensors and test audio only - -// audio settings -unsigned int gPeriodSize = 8; // period size for audio -char* gPartialFilename = 0; // name of the partials file to load -bool gAudioIn = false; // stereo audio in status - -int touchSensor0Address = 0x0C; // I2C addresses of touch sensors -int touchSensor1Address = 0x0B; -int sensorType = 0; - -char sdPath[256] = "/dev/mmcblk0p2"; // system path of the SD, partition 2 -char mountPath[256] = "/root/d-box/usersounds"; // mount point of SD partition 2 [where user files are] -char gUserDirName[256] = "usersounds"; // Directory in which user analysis files can be found [dir of mountPath] -char gDefaultDirName[256] = "/root/d-box/sounds"; // Directory in which built in analysis files can be found -char *gDirName; -bool gIsLoading = false; -int fileCnt = 0; -std::vector <std::string> files; - -char gId = 'f'; // from 0 to 14, hexadecimal [0-d]! f means not set -char gGroup = '2'; // 0 is no info, 1 info. 2 is not set - -// audio in filter -extern ne10_float32_t *filterState[2]; -extern ne10_float32_t *filterIn[2]; -extern ne10_float32_t *filterOut[2]; - -struct arg_data -{ - int argc; - char **argv; -}; - -arg_data args; - - -int readFiles() -{ - if(useSD) - gDirName = gUserDirName; - else - gDirName = gDefaultDirName; - DIR *dir; - struct dirent *ent; - - // From http://stackoverflow.com/questions/612097/how-can-i-get-a-list-of-files-in-a-directory-using-c-or-c - if ((dir = opendir (gDirName)) != NULL) { - /* print all the files and directories within directory */ - while ((ent = readdir (dir)) != NULL) { - // Ignore dotfiles and . and .. paths - if(!strncmp(ent->d_name, ".", 1)) - continue; - - //dbox_printf("%s\n", ent->d_name); - - // take only .dbx and .txt files - string name = string(ent->d_name); - int len = name.length(); - - bool dboxFile = false; - - if( (name[len-4]=='.') && (name[len-3]=='d') && (name[len-2]=='b') && (name[len-1]=='x') ) - dboxFile = true; - if( (name[len-4]=='.') && (name[len-3]=='t') && (name[len-2]=='x') && (name[len-1]=='t') ) - dboxFile = true; - - if(dboxFile) - { - fileCnt++; - //dbox_printf("%s\n", ent->d_name); - files.push_back( std::string( ent->d_name ) ); - } - } - closedir (dir); - } else { - /* could not open directory */ - printf("Could not open directory %s\n", gDirName); - return 1; - } - - // order by name - std::sort( files.begin(), files.end() ); - - if(fileCnt==0) - { - printf("No .dbx or .txt files in %s!\n", gDirName); - return 1; - } - - return 0; -} - -/* Load sounds from the directory */ -void loadAudioFiles(bool loadFirstFile) -{ - char fullFileName[256]; - - if(loadFirstFile) { - strcpy(fullFileName, gDirName); - strcat(fullFileName, "/"); - strncat(fullFileName, files[0].c_str(), 255 - strlen(gDirName)); - dbox_printf("Loading first file %s...\n", fullFileName); - OscillatorBank *bank = new OscillatorBank(fullFileName); - if(bank->initBank(oscBnkOversampling)) { - bank->setLoopHops(100, bank->getLastHop()); - gOscBanks.push_back(bank); - } - } - - else { - for(int i=1; i<fileCnt; i++){ - strcpy(fullFileName, gDirName); - strcat(fullFileName, "/"); - strncat(fullFileName, files[i].c_str(), 255 - strlen(gDirName)); - dbox_printf("Loading file %s...\n", fullFileName); - OscillatorBank *bank = new OscillatorBank(fullFileName); - if(bank->initBank(oscBnkOversampling)) { - bank->setLoopHops(100, bank->getLastHop()); - gOscBanks.push_back(bank); - } - } - } -} - -// adapted from http://program-nix.blogspot.co.uk/2008/08/c-language-check-filesystem-is-mounted.html -int checkIfMounted (char * dev_path) -{ - FILE * mtab = NULL; - struct mntent * part = NULL; - int is_mounted = 0; - - if ( ( mtab = setmntent ("/etc/mtab", "r") ) != NULL) - { - while ( ( part = getmntent ( mtab) ) != NULL) - { - if ( ( part->mnt_fsname != NULL ) && ( strcmp ( part->mnt_fsname, dev_path ) ) == 0 ) - is_mounted = 1; - } - endmntent(mtab); - } - return is_mounted; -} - -int mountSDuserPartition() -{ - if(checkIfMounted(sdPath)) - { - printf("device %s already mounted, fair enough, let's move on\n", sdPath); - return 0; - } - // if mount rootfs from SD [rootfs eMMC not used] or from eMMC via properly formatted SD [SD rootfs used as storage volume] - // we always use rootfs on SD as storage volume ----> "/dev/mmcblk0p2" - int ret = mount(sdPath, "/root/d-box/usersounds", "vfat", 0, NULL); - if (ret!=0) - { - printf("Error in mount...%s\n", strerror(ret)); - return 1; - } - return 0; -} - -int initSoundFiles() -{ - if(gVerbose==1) - cout << "---------------->Init Audio Thread" << endl; - - if(useSD) - { - // mount the SD partition where user sounds are located - // [this is p2, p1 is already mounted and we will log data there] - if(mountSDuserPartition()!=0) - return -1; - } - - gIsLoading = true; - - // read files from SD and order them alphabetically - if(readFiles()!=0) - return 1; - - // load first file into oscBank - loadAudioFiles(true); - - return 0; -} - -//--------------------------------------------------------------------------------------------------------- - -// Handle Ctrl-C -void interrupt_handler(int var) -{ - // kill keyboard thread mercilessly - if(forceKeyboard) - pthread_cancel(keyboardThread); - - gShouldStop = true; -} - - -void parseArguments(arg_data args, BelaInitSettings *settings) -{ - // Default filename; - gPartialFilename = strdup("D-Box_sound_250_60_40_h88_2.txt"); - - const int kOptionAudioTest = 1000; - - // TODO: complete this - struct option long_option[] = - { - {"help", 0, NULL, 'h'}, - {"audioin", 1, NULL, 'i'}, - {"file", 1, NULL, 'f'}, - {"keyboard", 1, NULL, 'k'}, - {"audio-test", 0, NULL, kOptionAudioTest}, - {"sensor-type", 1, NULL, 't'}, - {"sensor0", 1, NULL, 'q'}, - {"sensor1", 1, NULL, 'r'}, - {"log", 1, NULL, 'l'}, - {"usesd", 1, NULL, 'u'}, - {"oversamp", 1, NULL, 'o'}, - {"boxnumber", 1, NULL, 'n'}, - {"group", 1, NULL, 'g'}, - {NULL, 0, NULL, 0}, - }; - int morehelp = 0; - int tmp = -1; - - Bela_defaultSettings(settings); - - while (1) - { - int c; - if ((c = Bela_getopt_long(args.argc, args.argv, "hf:ki:sq:r:t:l:u:o:n:g:", long_option, settings)) < 0) - break; - switch (c) - { - case 'h': - morehelp++; - break; - case 'f': - free(gPartialFilename); - gPartialFilename = strdup(optarg); - break; - case 'k': - forceKeyboard = true; - break; - case 'i': - gAudioIn = (atoi(optarg)==0) ? false : true; - break; - case 's': - forceSensors = true; - break; - case kOptionAudioTest: - useAudioTest = true; - break; - case 't': - sensorType = atoi(optarg); - break; - case 'q': - touchSensor0Address = atoi(optarg); - break; - case 'r': - touchSensor1Address = atoi(optarg); - break; - case 'l': - tmp = atoi(optarg); - if(tmp==0) - forceLog = false; - else if(tmp>0) - forceLog = true; - break; - case 'u': - tmp = atoi(optarg); - if(tmp==0) - useSD = false; - else if(tmp>0) - useSD = true; - break; - case 'o': - oscBnkOversampling = atoi(optarg); - break; - case 'n': - gId = *optarg; - cout << "-set box number to: " << gId << endl; - break; - case 'g': - gGroup = *optarg; - cout << "-set group to: " << gId << endl; - break; - default: - break; - } - } - - gPeriodSize = settings->periodSize; - gVerbose = settings->verbose; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - RT_TASK rtSensorThread; - const char rtSensorThreadName[] = "dbox-sensor"; - int oscBankHopSize; - - // Parse command-line arguments - args.argc = argc; - args.argv = argv; - parseArguments(args, &settings); - - Bela_setVerboseLevel(gVerbose); - if(gVerbose == 1 && useAudioTest) - cout << "main() : running in audio test mode" << endl; - - // Load sound files from directory - if(initSoundFiles() != 0) - return -1; - - oscBankHopSize = gOscBanks[gCurrentOscBank]->getHopSize()/gOscBanks[gCurrentOscBank]->getMinSpeed(); - - // Initialise the audio device - if(Bela_initAudio(&settings, &oscBankHopSize) != 0) - return -1; - - // Initialise the status LED - if(!gStatusLED.init(kStatusLEDPin)) { - if(gVerbose) - cout << "Couldn't initialise status LED pin\n"; - } - - // Free file name string which is no longer needed - if(gPartialFilename != 0) - free(gPartialFilename); - - if(!useAudioTest) { - if(initSensorLoop(touchSensor0Address, touchSensor1Address, sensorType) != 0) - return -1; - } - - if(gVerbose == 1) - cout << "main() : creating audio thread" << endl; - - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // LED on... - gStatusLED.on(); - - if(forceSensors && !useAudioTest) { - if(gVerbose==1) - cout << "main() : creating control thread" << endl; - - if(rt_task_create(&rtSensorThread, rtSensorThreadName, 0, BELA_AUDIO_PRIORITY - 5, T_JOINABLE | T_FPU)) { - cout << "Error:unable to create Xenomai control thread" << endl; - return -1; - } - if(rt_task_start(&rtSensorThread, &sensorLoop, 0)) { - cout << "Error:unable to start Xenomai control thread" << endl; - return -1; - } - } - - if(forceKeyboard) { - if(gVerbose==1) - cout << "main() : creating keyboard thread" << endl; - - if ( pthread_create(&keyboardThread, NULL, keyboardLoop, NULL) ) { - cout << "Error:unable to create keyboard thread" << endl; - return -1; - } - } - - if(forceLog) { - if(gVerbose==1) - cout << "main() : creating log thread" << endl; - - if(initLogLoop()!=0) { - cout << "Error:unable to create log thread" << endl; - return -1; - } - - if ( pthread_create(&logThread, NULL, logLoop, NULL) ) { - cout << "Error:unable to create keyboard thread" << endl; - return -1; - } - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // load all other files into oscBanks - loadAudioFiles(false); - cout << "Finished loading analysis files\n"; - gIsLoading = false; - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - Bela_stopAudio(); - - if(!useAudioTest) - rt_task_join(&rtSensorThread); - - Bela_cleanupAudio(); - - pthread_join( keyboardThread, NULL); - pthread_join( logThread, NULL); - - for(unsigned int i = 0; i < gOscBanks.size(); i++) - delete gOscBanks[i]; - - NE10_FREE(filterState[0]); - NE10_FREE(filterState[1]); - NE10_FREE(filterIn[0]); - NE10_FREE(filterIn[1]); - NE10_FREE(filterOut[0]); - NE10_FREE(filterOut[1]); - - printf("Program ended\nBye bye\n"); - return 0; -}
--- a/examples/d-box/prio.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * prio.cpp - * - * Created on: May 14, 2014 - * Author: Victor Zappi - */ - -#include "prio.h" -using namespace std; -//----------------------------------------------------------------------------------------------------------- -// set wanted real-time priority to this thread -//----------------------------------------------------------------------------------------------------------- -void set_realtime_priority(int order) -{ - int ret; - - // We'll operate on the currently running thread. - pthread_t this_thread = pthread_self(); - // struct sched_param is used to store the scheduling priority - struct sched_param params; - // We'll set the priority to the maximum. - params.sched_priority = sched_get_priority_max(SCHED_FIFO) - order; - - // Attempt to set thread real-time priority to the SCHED_FIFO policy - ret = pthread_setschedparam(this_thread, SCHED_FIFO, ¶ms); - if (ret != 0) { - // Print the error - cout << "Unsuccessful in setting thread realtime prio" << endl; - return; - } - - // Now verify the change in thread priority - int policy = 0; - ret = pthread_getschedparam(this_thread, &policy, ¶ms); - if (ret != 0) { - cout << "Couldn't retrieve real-time scheduling parameters" << endl; - return; - } - - // Check the correct policy was applied - if(policy != SCHED_FIFO) { - cout << "Scheduling is NOT SCHED_FIFO!" << endl; - } -} - -//----------------------------------------------------------------------------------------------------------- - -
--- a/examples/d-box/prio.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -/* - * prio.h - * - * Created on: May 14, 2014 - * Author: Victor Zappi - */ - -#ifndef PRIO_H_ -#define PRIO_H_ - - -#include <pthread.h> -#include <sched.h> -#include <iostream> - -//----------------------------------------------------------------------------------------------------------- -// set maximum real-time priority to this thread -//----------------------------------------------------------------------------------------------------------- -void set_realtime_priority(int order); -//----------------------------------------------------------------------------------------------------------- - -#endif /* PRIO_H_ */
--- a/examples/d-box/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,870 +0,0 @@ -/* - * render.cpp - * - * Created on: May 28, 2014 - * Author: Victor Zappi - */ - -#include <Bela.h> -#include <PRU.h> - -#include "StatusLED.h" -#include "config.h" -#include "OscillatorBank.h" -#include "FeedbackOscillator.h" -#include "ADSR.h" -#include "FIRfilter.h" -#include <assert.h> -#include <cmath> -#include <vector> - -#undef DBOX_CAPE_TEST - -// Mappings from pin numbers on PCB to actual DAC channels -// This gives the DAC and ADC connectors the same effective pinout -// Update June 2016: this is no longer needed in the latest Bela -// release, but is kept here for convenience: it used to be -// 6 4 2 0 1 3 5 7 for the DAC pins -#define DAC_PIN0 0 -#define DAC_PIN1 1 -#define DAC_PIN2 2 -#define DAC_PIN3 3 -#define DAC_PIN4 4 -#define DAC_PIN5 5 -#define DAC_PIN6 6 -#define DAC_PIN7 7 - -#define ADC_PIN0 0 -#define ADC_PIN1 1 -#define ADC_PIN2 2 -#define ADC_PIN3 3 -#define ADC_PIN4 4 -#define ADC_PIN5 5 -#define ADC_PIN6 6 -#define ADC_PIN7 7 - -#define N_OCT 4.0 // maximum number of octaves on sensor 1 - -extern vector<OscillatorBank*> gOscBanks; -extern int gCurrentOscBank; -extern int gNextOscBank; -extern PRU *gPRU; -extern StatusLED gStatusLED; -extern bool gIsLoading; -extern bool gAudioIn; - -float *gOscillatorBuffer1, *gOscillatorBuffer2; -float *gOscillatorBufferRead, *gOscillatorBufferWrite; -int gOscillatorBufferReadPointer = 0; -int gOscillatorBufferReadCurrentSize = 0; -int gOscillatorBufferWriteCurrentSize = 0; -bool gOscillatorNeedsRender = false; - -int gMatrixSampleCount = 0; // How many samples have elapsed on the matrix - -// Wavetable which changes in response to an oscillator -float *gDynamicWavetable; -int gDynamicWavetableLength; -bool gDynamicWavetableNeedsRender = false; - -// These variables handle the hysteresis oscillator used for setting the playback speed -bool gSpeedHysteresisOscillatorRising = false; -int gSpeedHysteresisLastTrigger = 0; - -// These variables handle the feedback oscillator used for controlling the wavetable -FeedbackOscillator gFeedbackOscillator; -float *gFeedbackOscillatorTable; -int gFeedbackOscillatorTableLength; - -// This comes from sensor.cpp where it records the most recent touch location on -// sensor 0. -extern float gSensor0LatestTouchPos; -extern int gSensor0LatestTouchNum; -float gPitchLatestInput = 0; - -extern float gSensor1LatestTouchPos[]; -//extern float gSensor1LatestTouchSizes[]; -extern int gSensor1LatestTouchCount; -extern int gSensor1LatestTouchIndex; -int gSensor1LastTouchIndex = -1; -int gSensor1InputDelayCounter = -1; -int gSensor1InputIndex = 0; -float gSensor1MatrixTouchPos[5] = {0}; - -// FSR value from matrix input -extern int gLastFSRValue; - -// Loop points from matrix input 4 -const int gLoopPointsInputBufferSize = 256; -float gLoopPointsInputBuffer[gLoopPointsInputBufferSize]; -int gLoopPointsInputBufferPointer = 0; -float gLoopPointMin = 0, gLoopPointMax = 0; - -// multiplier to activate or mute audio in -int audioInStatus = 0; - -// xenomai timer -SRTIME prevChangeNs = 0; - -// pitch vars -float octaveSplitter; -float semitones[((int)N_OCT*12)+1]; -float deltaTouch = 0; -float deltaWeightP = 0.5 / 65536.0; -float deltaWeightI = 0.0005 / 65536.0; - -// filter vars -ne10_fir_instance_f32_t filter[2]; -ne10_float32_t *filterIn[2]; -ne10_float32_t *filterOut[2]; -ne10_uint32_t blockSize; -ne10_float32_t *filterState[2]; -ne10_float32_t prevFiltered[2]; -int filterGain = 80; -ADSR PeakBurst[2]; -float peak[2]; -float peakThresh = 0.2; - -// Tasks for lower-priority calculation -AuxiliaryTask gMediumPriorityRender, gLowPriorityRender; - - -extern "C" { - // Function prototype for ARM assembly implementation of oscillator bank - void oscillator_bank_neon(int numAudioFrames, float *audioOut, - int activePartialNum, int lookupTableSize, - float *phases, float *frequencies, float *amplitudes, - float *freqDerivatives, float *ampDerivatives, - float *lookupTable); - - void wavetable_interpolate_neon(int numSamplesIn, int numSamplesOut, - float *tableIn, float *tableOut); -} - -void wavetable_interpolate(int numSamplesIn, int numSamplesOut, - float *tableIn, float *tableOut, - float *sineTable, float sineMix); - -inline float hysteresis_oscillator(float input, float risingThreshold, - float fallingThreshold, bool *rising); - -void render_medium_prio(); -void render_low_prio(); - -#ifdef DBOX_CAPE_TEST -void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, - uint16_t *matrixIn, uint16_t *matrixOut); -#endif - -bool setup(BelaContext *context, void *userData) { - int oscBankHopSize = *(int *)userData; - - if(context->analogChannels != 8) { - printf("Error: D-Box needs matrix enabled with 8 channels.\n"); - return false; - } - - // Allocate two buffers for rendering oscillator bank samples - // One will be used for writing in the background while the other is used for reading - // on the audio thread. 8-byte alignment needed for the NEON code. - if(posix_memalign((void **)&gOscillatorBuffer1, 8, oscBankHopSize * context->audioChannels * sizeof(float))) { - printf("Error allocating render buffers\n"); - return false; - } - if(posix_memalign((void **)&gOscillatorBuffer2, 8, oscBankHopSize * context->audioChannels * sizeof(float))) { - printf("Error allocating render buffers\n"); - return false; - } - gOscillatorBufferWrite = gOscillatorBuffer1; - gOscillatorBufferRead = gOscillatorBuffer2; - - memset(gOscillatorBuffer1, 0, oscBankHopSize * context->audioChannels * sizeof(float)); - memset(gOscillatorBuffer2, 0, oscBankHopSize * context->audioChannels * sizeof(float)); - - // Initialise the dynamic wavetable used by the oscillator bank - // It should match the size of the static one already allocated in the OscillatorBank object - // Don't forget a guard point at the end of the table - gDynamicWavetableLength = gOscBanks[gCurrentOscBank]->lookupTableSize; - if(posix_memalign((void **)&gDynamicWavetable, 8, (gDynamicWavetableLength + 1) * sizeof(float))) { - printf("Error allocating wavetable\n"); - return false; - } - - gFeedbackOscillator.initialise(8192, 10.0, context->analogSampleRate); - - for(int n = 0; n < gDynamicWavetableLength + 1; n++) - gDynamicWavetable[n] = 0; - - // pitch - float midPos = 0.5; - octaveSplitter = 1.0 / N_OCT; - int numOfSemi = 12*N_OCT; - int middleSemitone = 12*N_OCT/2; - int lastSemitone = middleSemitone+numOfSemi/2; - float inc = 1.0 / (N_OCT*12.0); - int i = -1; - for(int semi=middleSemitone; semi<=lastSemitone; semi++) - semitones[semi] = ( midPos + (++i)*inc) + 0.5; - i = 0; - for(int semi=middleSemitone-1; semi>=0; semi--) - semitones[semi] = ( midPos - (++i)*inc) + 0.5; - - if(gAudioIn) - audioInStatus = 1; - - // filter - blockSize = context->audioFrames; - filterState[0] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); - filterState[1] = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); - filterIn[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); - filterIn[1] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); - filterOut[0] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); - filterOut[1] = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); - ne10_fir_init_float(&filter[0], FILTER_TAP_NUM, filterTaps, filterState[0], blockSize); - ne10_fir_init_float(&filter[1], FILTER_TAP_NUM, filterTaps, filterState[1], blockSize); - - // peak outputs - PeakBurst[0].setAttackRate(.00001 * context->analogSampleRate); - PeakBurst[1].setAttackRate(.00001 * context->analogSampleRate); - PeakBurst[0].setDecayRate(.5 * context->analogSampleRate); - PeakBurst[1].setDecayRate(.5 * context->analogSampleRate); - PeakBurst[0].setSustainLevel(0.0); - PeakBurst[1].setSustainLevel(0.0); - - // Initialise auxiliary tasks - if((gMediumPriorityRender = Bela_createAuxiliaryTask(&render_medium_prio, BELA_AUDIO_PRIORITY - 10, "dbox-calculation-medium")) == 0) - return false; - if((gLowPriorityRender = Bela_createAuxiliaryTask(&render_low_prio, BELA_AUDIO_PRIORITY - 15, "dbox-calculation-low")) == 0) - return false; - - return true; -} - -void render(BelaContext *context, void *userData) -{ -#ifdef DBOX_CAPE_TEST - render_capetest(numMatrixFrames, numAudioFrames, audioIn, audioOut, matrixIn, matrixOut); -#else - if(gOscBanks[gCurrentOscBank]->state==bank_toreset) - gOscBanks[gCurrentOscBank]->resetOscillators(); - - if(gOscBanks[gCurrentOscBank]->state==bank_playing) - { - assert(context->audioChannels == 2); - -#ifdef OLD_OSCBANK - memset(audioOut, 0, numAudioFrames * * sizeof(float)); - - /* Render the oscillator bank. The oscillator bank function is written in NEON assembly - * and it strips out all extra checks, so find out in advance whether we can render a whole - * block or whether the frame will increment in the middle of this buffer. - */ - - int framesRemaining = numAudioFrames; - float *audioOutWithOffset = audioOut; - - while(framesRemaining > 0) { - if(gOscBanks[gCurrentOscBank]->hopCounter >= framesRemaining) { - /* More frames left in this hop than we need this time. Render and finish */ - oscillator_bank_neon(framesRemaining, audioOutWithOffset, - gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, - gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies, - gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, - gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, - gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, - gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/); - gOscBanks[gCurrentOscBank]->hopCounter -= framesRemaining; - if(gOscBanks[gCurrentOscBank]->hopCounter <= 0) - gOscBanks[gCurrentOscBank]->nextHop(); - framesRemaining = 0; - } - else { - /* More frames to render than are left in this hop. Render and decrement the - * number of remaining frames; then advance to the next oscillator frame. - */ - oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, audioOutWithOffset, - gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, - gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies, - gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, - gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, - gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, - gDynamicWavetable/*gOscBanks[gCurrentOscBank]->lookupTable*/); - framesRemaining -= gOscBanks[gCurrentOscBank]->hopCounter; - audioOutWithOffset += * gOscBanks[gCurrentOscBank]->hopCounter; - gOscBanks[gCurrentOscBank]->sampleCount += gOscBanks[gCurrentOscBank]->hopCounter; - gOscBanks[gCurrentOscBank]->nextHop(); - } - } -#else - for(unsigned int n = 0; n < context->audioFrames; n++) { - context->audioOut[2*n] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n]*audioInStatus; - context->audioOut[2*n + 1] = gOscillatorBufferRead[gOscillatorBufferReadPointer++]+context->audioIn[2*n+1]*audioInStatus; - - filterIn[0][n] = fabs(context->audioIn[2*n]); // rectify for peak detection in 1 - filterIn[1][n] = fabs(context->audioIn[2*n+1]); // rectify for peak detection in 2 - - /* FIXME why doesn't this work? */ - /* - if(gOscillatorBufferReadPointer == gOscillatorBufferCurrentSize/2) { - gOscillatorNeedsRender = true; - scheduleAuxiliaryTask(gLowPriorityRender); - } */ - - if(gOscillatorBufferReadPointer >= gOscillatorBufferReadCurrentSize) { - // Finished reading from the buffer: swap to the next buffer - if(gOscillatorBufferRead == gOscillatorBuffer1) { - gOscillatorBufferRead = gOscillatorBuffer2; - gOscillatorBufferWrite = gOscillatorBuffer1; - } - else { - gOscillatorBufferRead = gOscillatorBuffer1; - gOscillatorBufferWrite = gOscillatorBuffer2; - } - - // New buffer size is whatever finished writing last hop - gOscillatorBufferReadCurrentSize = gOscillatorBufferWriteCurrentSize; - gOscillatorBufferReadPointer = 0; - - gOscillatorNeedsRender = true; - Bela_scheduleAuxiliaryTask(gMediumPriorityRender); - } - } -#endif - } - else - { - for(unsigned int n = 0; n < context->audioFrames; n++) { - context->audioOut[2*n] = context->audioIn[2*n]*audioInStatus; - context->audioOut[2*n + 1] = context->audioIn[2*n+1]*audioInStatus; - - filterIn[0][n] = fabs(context->audioIn[2*n]); // rectify for peak detection in 1 - filterIn[1][n] = fabs(context->audioIn[2*n+1]); // rectify for peak detection in 2 - } - } - - // low pass filter audio in 1 and 2 for peak detection - ne10_fir_float_neon(&filter[0], filterIn[0], filterOut[0], blockSize); - ne10_fir_float_neon(&filter[1], filterIn[1], filterOut[1], blockSize); - - for(unsigned int n = 0; n < context->analogFrames; n++) { - - - /* Matrix Out 0, In 0 - * - * CV loop - * Controls pitch of sound - */ - float touchPosInt = gSensor0LatestTouchPos; - if(touchPosInt < 0) touchPosInt = 0; - if(touchPosInt > 1.0) touchPosInt = 1.0; - context->analogOut[n*8 + DAC_PIN0] = touchPosInt; - - gPitchLatestInput = context->analogIn[n*8 + ADC_PIN0]; - - - /* Matrix Out 7 - * - * Loop feedback with Matrix In 0 - * Controls discreet pitch - */ - float deltaTarget = 0; - int semitoneIndex = 0; - if(gSensor0LatestTouchNum>0) - { - // current pitch is gPitchLatestInput, already retrieved - semitoneIndex = ( gPitchLatestInput * 12 * N_OCT )+0.5; // closest semitone - deltaTarget = (semitones[semitoneIndex]-gPitchLatestInput); // delta between pitch and target - deltaTouch += deltaTarget*(deltaWeightI); // update feedback [previous + current] - } - else - deltaTouch = 0; - - float nextOut = touchPosInt + deltaTarget*deltaWeightP + deltaTouch; // add feedback to touch -> next out - if(nextOut < 0) nextOut = 0; // clamp - if(nextOut > 1.0) nextOut = 1.0; // clamp - context->analogOut[n*8 + DAC_PIN7] = nextOut; // send next nextOut - - - /* - * Matrix Out 1, In 1 - * - * Hysteresis (comparator) oscillator - * Controls speed of playback - */ - bool wasRising = gSpeedHysteresisOscillatorRising; - context->analogOut[n*8 + DAC_PIN1] = hysteresis_oscillator(context->analogIn[n*8 + ADC_PIN1], 48000.0/65536.0, - 16000.0/65536.0, &gSpeedHysteresisOscillatorRising); - - // Find interval of zero crossing - if(wasRising && !gSpeedHysteresisOscillatorRising) { - int interval = gMatrixSampleCount - gSpeedHysteresisLastTrigger; - - // Interval since last trigger will be the new hop size; calculate to set speed - if(interval < 1) - interval = 1; - //float speed = (float)gOscBanks[gCurrentOscBank]->getHopSize() / (float)interval; - float speed = 144.0 / interval; // Normalise to a fixed expected speed - gOscBanks[gCurrentOscBank]->setSpeed(speed); - - gSpeedHysteresisLastTrigger = gMatrixSampleCount; - } - - /* - * Matrix Out 2, In 2 - * - * Feedback (phase shift) oscillator - * Controls wavetable used for oscillator bank - */ - - int tableLength = gFeedbackOscillator.process(context->analogIn[n*8 + ADC_PIN2], &context->analogOut[n*8 + DAC_PIN2]); - if(tableLength != 0) { - gFeedbackOscillatorTableLength = tableLength; - gFeedbackOscillatorTable = gFeedbackOscillator.wavetable(); - gDynamicWavetableNeedsRender = true; - Bela_scheduleAuxiliaryTask(gLowPriorityRender); - } - - /* - * Matrix Out 3, In 3 - * - * CV loop with delay for time alignment - * Touch positions from sensor 1 - * Change every 32 samples (ca. 1.5 ms) - */ - volatile int touchCount = gSensor1LatestTouchCount; - if(touchCount == 0) - context->analogOut[n*8 + DAC_PIN3] = 0; - else { - int touchIndex = (gMatrixSampleCount >> 5) % touchCount; - context->analogOut[n*8 + DAC_PIN3] = gSensor1LatestTouchPos[touchIndex] * 56000.0f / 65536.0f; - if(touchIndex != gSensor1LastTouchIndex) { - // Just changed to a new touch output. Reset the counter. - // It will take 2*matrixFrames samples for this output to come back to the - // ADC input. But we also want to read near the end of the 32 sample block; - // let's say 24 samples into it. - - // FIXME this won't work for p > 2 - gSensor1InputDelayCounter = 24 + 2*context->analogFrames; - gSensor1InputIndex = touchIndex; - } - gSensor1LastTouchIndex = touchIndex; - } - - if(gSensor1InputDelayCounter-- >= 0 && touchCount > 0) { - gSensor1MatrixTouchPos[gSensor1InputIndex] = context->analogIn[n*8 + ADC_PIN3]; - } - - /* Matrix Out 4 - * - * Sensor 1 last pos - */ - touchPosInt = gSensor1LatestTouchPos[gSensor1LatestTouchIndex]; - if(touchPosInt < 0) touchPosInt = 0; - if(touchPosInt > 1.0) touchPosInt = 1.0; - context->analogOut[n*8 + DAC_PIN4] = touchPosInt; - - /* Matrix In 4 - * - * Loop points selector - */ - gLoopPointsInputBuffer[gLoopPointsInputBufferPointer++] = context->analogIn[n*8 + ADC_PIN4]; - if(gLoopPointsInputBufferPointer >= gLoopPointsInputBufferSize) { - // Find min and max values - float loopMax = 0, loopMin = 1.0; - for(int i = 0; i < gLoopPointsInputBufferSize; i++) { - if(gLoopPointsInputBuffer[i] < loopMin) - loopMin = gLoopPointsInputBuffer[i]; - if(gLoopPointsInputBuffer[i] > loopMax/* && gLoopPointsInputBuffer[i] != 65535*/) - loopMax = gLoopPointsInputBuffer[i]; - } - - if(loopMin >= loopMax) - loopMax = loopMin; - - gLoopPointMax = loopMax; - gLoopPointMin = loopMin; - gLoopPointsInputBufferPointer = 0; - } - - /* Matrix Out 5 - * - * Audio In 1 peak detection and peak burst output - */ - - filterOut[0][n*2+1] *= filterGain; - float burstOut = PeakBurst[0].getOutput(); - if( burstOut < 0.1) - { - if( (prevFiltered[0]>=peakThresh) && (prevFiltered[0]>=filterOut[0][n*2+1]) ) - { - peak[0] = prevFiltered[0]; - PeakBurst[0].gate(1); - } - } - - PeakBurst[0].process(1); - - float convAudio = burstOut*peak[0]; - context->analogOut[n*8 + DAC_PIN5] = convAudio; - prevFiltered[0] = filterOut[0][n*2+1]; - if(prevFiltered[0]>1) - prevFiltered[0] = 1; - - /* Matrix In 5 - * - * Dissonance, via changing frequency motion of partials - */ - float amount = (float)context->analogIn[n*8 + ADC_PIN5]; - gOscBanks[gCurrentOscBank]->freqMovement = 1.0 - amount; - - - - - /* Matrix Out 6 - * - * Audio In 2 peak detection and peak burst output - */ - - filterOut[1][n*2+1] *= filterGain; - burstOut = PeakBurst[1].getOutput(); - if( burstOut < 0.1) - { - if( (prevFiltered[1]>=peakThresh) && (prevFiltered[1]>=filterOut[1][n*2+1]) ) - { - peak[1] = prevFiltered[1]; - PeakBurst[1].gate(1); - } - } - - PeakBurst[1].process(1); - - convAudio = burstOut*peak[1]; - context->analogOut[n*8 + DAC_PIN6] = convAudio; - prevFiltered[1] = filterOut[1][n*2+1]; - if(prevFiltered[1]>1) - prevFiltered[1] = 1; - - /* Matrix In 6 - * - * Sound selector - */ - if(!gIsLoading) { - // Use hysteresis to avoid jumping back and forth between sounds - if(gOscBanks.size() > 1) { - float input = context->analogIn[n*8 + ADC_PIN6]; - const float hystValue = 16000.0 / 65536.0; - - float upHysteresisValue = ((gCurrentOscBank + 1) + hystValue) / gOscBanks.size(); - float downHysteresisValue = (gCurrentOscBank - hystValue) / gOscBanks.size(); - - if(input > upHysteresisValue || input < downHysteresisValue) { - gNextOscBank = input * gOscBanks.size(); - if(gNextOscBank < 0) - gNextOscBank = 0; - if((unsigned)gNextOscBank >= gOscBanks.size()) - gNextOscBank = gOscBanks.size() - 1; - } - } - } - - /* - * Matrix In 7 - * - * FSR from primary touch sensor - * Value ranges from 0-1799 - */ - gLastFSRValue = context->analogIn[n*8 + ADC_PIN7] * 1799.0; - //gLastFSRValue = 1799 - context->analogIn[n*8 + ADC_PIN7] * (1799.0 / 65535.0); - //dbox_printf("%i\n",gLastFSRValue); - - gMatrixSampleCount++; - } - -#endif /* DBOX_CAPE_TEST */ -} - -// Medium-priority render function used for audio hop calculations -void render_medium_prio() -{ - - if(gOscillatorNeedsRender) { - gOscillatorNeedsRender = false; - - /* Render one frame into the write buffer */ - memset(gOscillatorBufferWrite, 0, gOscBanks[gCurrentOscBank]->hopCounter * 2 * sizeof(float)); /* assumes 2 audio channels */ - - oscillator_bank_neon(gOscBanks[gCurrentOscBank]->hopCounter, gOscillatorBufferWrite, - gOscBanks[gCurrentOscBank]->actPartNum, gOscBanks[gCurrentOscBank]->lookupTableSize, - gOscBanks[gCurrentOscBank]->oscillatorPhases, gOscBanks[gCurrentOscBank]->oscillatorNormFrequencies, - gOscBanks[gCurrentOscBank]->oscillatorAmplitudes, - gOscBanks[gCurrentOscBank]->oscillatorNormFreqDerivatives, - gOscBanks[gCurrentOscBank]->oscillatorAmplitudeDerivatives, - /*gOscBanks[gCurrentOscBank]->lookupTable*/gDynamicWavetable); - - gOscillatorBufferWriteCurrentSize = gOscBanks[gCurrentOscBank]->hopCounter * 2; - - /* Update the pitch right before the hop - * Total CV range +/- N_OCT octaves - */ - float pitch = (float)gPitchLatestInput / octaveSplitter - N_OCT/2; - //gOscBanks[gCurrentOscBank]->pitchMultiplier = powf(2.0f, pitch); - gOscBanks[gCurrentOscBank]->pitchMultiplier = pow(2.0f, pitch); - -#ifdef FIXME_LATER // This doesn't work very well yet - gOscBanks[gCurrentOscBank]->filterNum = gSensor1LatestTouchCount; - float freqScaler = gOscBanks[gCurrentOscBank]->getFrequencyScaler(); - for(int i=0; i < gOscBanks[gCurrentOscBank]->filterNum; i++) - { - // touch pos is linear but freqs are log - gOscBanks[gCurrentOscBank]->filterFreqs[i] = ((expf(gSensor1MatrixTouchPos[i]*4)-1)/(expf(4)-1))*gOscBanks[gCurrentOscBank]->filterMaxF*freqScaler; - gOscBanks[gCurrentOscBank]->filterQ[i] = gSensor1LatestTouchSizes[i]; - if(gOscBanks[gCurrentOscBank]->filterFreqs[i]>500*freqScaler) - gOscBanks[gCurrentOscBank]->filterPadding[i] = 1+100000*( (gOscBanks[gCurrentOscBank]->filterFreqs[i]-500*freqScaler)/(gOscBanks[gCurrentOscBank]->filterMaxF-500)*freqScaler ); - else - gOscBanks[gCurrentOscBank]->filterPadding[i] = 1; - } -#endif - - RTIME ticks = rt_timer_read(); - SRTIME ns = rt_timer_tsc2ns(ticks); - SRTIME delta = ns-prevChangeNs; - - // switch to next bank cannot be too frequent, to avoid seg fault! [for example sef fault happens when removing both VDD and GND from breadboard] - if(gNextOscBank != gCurrentOscBank && delta>100000000) { - - /*printf("ticks %llu\n", (unsigned long long)ticks); - printf("ns %llu\n", (unsigned long long)ns); - printf("prevChangeNs %llu\n", (unsigned long long)prevChangeNs); - printf("-------------------------->%llud\n", (unsigned long long)(ns-prevChangeNs));*/ - - prevChangeNs = ns; - dbox_printf("Changing to bank %d...\n", gNextOscBank); - if(gOscBanks[gCurrentOscBank]->state==bank_playing){ - gOscBanks[gCurrentOscBank]->stop(); - } - - gCurrentOscBank = gNextOscBank; - gOscBanks[gCurrentOscBank]->hopNumTh = 0; - } - else { - /* Advance to the next oscillator frame */ - gOscBanks[gCurrentOscBank]->nextHop(); - } - } -} - -// Lower-priority render function which performs matrix calculations -// State should be transferred in via global variables -void render_low_prio() -{ - gPRU->setGPIOTestPin(); - if(gDynamicWavetableNeedsRender) { - // Find amplitude of wavetable - float meanAmplitude = 0; - float sineMix; - - for(int i = 0; i < gFeedbackOscillatorTableLength; i++) { - //meanAmplitude += fabsf(gFeedbackOscillatorTable[i]); - meanAmplitude += fabs(gFeedbackOscillatorTable[i]); - } - meanAmplitude /= (float)gFeedbackOscillatorTableLength; - - if(meanAmplitude > 0.35) - sineMix = 0; - else - sineMix = (.35 - meanAmplitude) / .35; - - //dbox_printf("amp %f mix %f\n", meanAmplitude, sineMix); - - // Copy to main wavetable - wavetable_interpolate(gFeedbackOscillatorTableLength, gDynamicWavetableLength, - gFeedbackOscillatorTable, gDynamicWavetable, - gOscBanks[gCurrentOscBank]->lookupTable, sineMix); - } - - if(gLoopPointMin >= 60000.0/65536.0 && gLoopPointMax >= 60000.0/65536.0) { - // KLUDGE! - if(gCurrentOscBank == 0) - gOscBanks[gCurrentOscBank]->setLoopHops(50, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.6) - 1); - else - gOscBanks[gCurrentOscBank]->setLoopHops(5, ((float)gOscBanks[gCurrentOscBank]->getLastHop() * 0.7) - 1); - } - else { - float normLoopPointMin = (float)gLoopPointMin * gOscBanks[gCurrentOscBank]->getLastHop(); - float normLoopPointMax = (float)gLoopPointMax * gOscBanks[gCurrentOscBank]->getLastHop(); - - int intLoopPointMin = normLoopPointMin; - if(intLoopPointMin < 1) - intLoopPointMin = 1; - int intLoopPointMax = normLoopPointMax; - if(intLoopPointMax <= intLoopPointMin) - intLoopPointMax = intLoopPointMin + 1; - if(intLoopPointMax > gOscBanks[gCurrentOscBank]->getLastHop() - 1) - intLoopPointMax = gOscBanks[gCurrentOscBank]->getLastHop() - 1; - - //dbox_printf("Loop points %d-%d / %d-%d\n", gLoopPointMin, gLoopPointMax, intLoopPointMin, intLoopPointMax); - - /* WORKS, jsut need to fix the glitch when jumps! - * *int currentHop = gOscBanks[gCurrentOscBank]->getCurrentHop(); - if(currentHop < intLoopPointMin -1 ) - gOscBanks[gCurrentOscBank]->setJumpHop(intLoopPointMin + 1); - else if(currentHop > intLoopPointMax + 1) - gOscBanks[gCurrentOscBank]->setJumpHop(intLoopPointMax - 1);*/ - gOscBanks[gCurrentOscBank]->setLoopHops(intLoopPointMin, intLoopPointMax); - } - - if(gIsLoading) - gStatusLED.blink(25, 75); // Blink quickly until load finished - else - gStatusLED.blink(250 / gOscBanks[gCurrentOscBank]->getSpeed(), 250 / gOscBanks[gCurrentOscBank]->getSpeed()); - gPRU->clearGPIOTestPin(); - -// static int counter = 32; -// if(--counter == 0) { -// for(int i = 0; i < gLoopPointsInputBufferSize; i++) { -// dbox_printf("%d ", gLoopPointsInputBuffer[i]); -// if(i % 32 == 31) -// dbox_printf("\n"); -// } -// dbox_printf("\n\n"); -// counter = 32; -// } - - //dbox_printf("min %d max %d\n", gLoopPointMin, gLoopPointMax); -} - -// Clean up at the end of render -void cleanup(BelaContext *context, void *userData) -{ - free(gOscillatorBuffer1); - free(gOscillatorBuffer2); - free(gDynamicWavetable); -} - -// Interpolate one wavetable into another. The output size -// does not include the guard point at the end which will be identical -// to the first point -void wavetable_interpolate(int numSamplesIn, int numSamplesOut, - float *tableIn, float *tableOut, - float *sineTable, float sineMix) -{ - float fractionalScaler = (float)numSamplesIn / (float)numSamplesOut; - - for(int k = 0; k < numSamplesOut; k++) { - float fractionalIndex = (float) k * fractionalScaler; - //int sB = (int)floorf(fractionalIndex); - int sB = (int)floor(fractionalIndex); - int sA = sB + 1; - if(sA >= numSamplesIn) - sA = 0; - float fraction = fractionalIndex - sB; - tableOut[k] = fraction * tableIn[sA] + (1.0f - fraction) * tableIn[sB]; - tableOut[k] = sineMix * sineTable[k] + (1.0 - sineMix) * tableOut[k]; - } - - tableOut[numSamplesOut] = tableOut[0]; -} - -// Create a hysteresis oscillator with a matrix input and output -inline float hysteresis_oscillator(float input, float risingThreshold, float fallingThreshold, bool *rising) -{ - float value; - - if(*rising) { - if(input > risingThreshold) { - *rising = false; - value = 0; - } - else - value = 1.0; - } - else { - if(input < fallingThreshold) { - *rising = true; - value = 1.0; - } - else - value = 0; - } - - return value; -} - -#ifdef DBOX_CAPE_TEST -// Test the functionality of the D-Box cape by checking each input and output -// Loopback cable from ADC to DAC needed -void render_capetest(int numMatrixFrames, int numAudioFrames, float *audioIn, float *audioOut, - uint16_t *matrixIn, uint16_t *matrixOut) -{ - static float phase = 0.0; - static int sampleCounter = 0; - static int invertChannel = 0; - - // Play a sine wave on the audio output - for(int n = 0; n < numAudioFrames; n++) { - audioOut[2*n] = audioOut[2*n + 1] = 0.5*sinf(phase); - phase += 2.0 * M_PI * 440.0 / 44100.0; - if(phase >= 2.0 * M_PI) - phase -= 2.0 * M_PI; - } - - for(int n = 0; n < numMatrixFrames; n++) { - // Change outputs every 512 samples - if(sampleCounter < 512) { - for(int k = 0; k < 8; k++) { - if(k == invertChannel) - matrixOut[n*8 + k] = 50000; - else - matrixOut[n*8 + k] = 0; - } - } - else { - for(int k = 0; k < 8; k++) { - if(k == invertChannel) - matrixOut[n*8 + k] = 0; - else - matrixOut[n*8 + k] = 50000; - } - } - - // Read after 256 samples: input should be low - if(sampleCounter == 256) { - for(int k = 0; k < 8; k++) { - if(k == invertChannel) { - if(matrixIn[n*8 + k] < 50000) { - dbox_printf("FAIL channel %d -- output HIGH input %d (inverted)\n", k, matrixIn[n*8 + k]); - } - } - else { - if(matrixIn[n*8 + k] > 2048) { - dbox_printf("FAIL channel %d -- output LOW input %d\n", k, matrixIn[n*8 + k]); - } - } - } - } - else if(sampleCounter == 768) { - for(int k = 0; k < 8; k++) { - if(k == invertChannel) { - if(matrixIn[n*8 + k] > 2048) { - dbox_printf("FAIL channel %d -- output LOW input %d (inverted)\n", k, matrixIn[n*8 + k]); - } - } - else { - if(matrixIn[n*8 + k] < 50000) { - dbox_printf("FAIL channel %d -- output HIGH input %d\n", k, matrixIn[n*8 + k]); - } - } - } - } - - if(++sampleCounter >= 1024) { - sampleCounter = 0; - invertChannel++; - if(invertChannel >= 8) - invertChannel = 0; - } - } -} -#endif - -
--- a/examples/d-box/sensors.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,642 +0,0 @@ -/* - * sensors.cpp - * - * Created on: May 28, 2014 - * Author: Victor Zappi - */ - -#include <stdio.h> -#include <pthread.h> -#include <unistd.h> -#include <math.h> -#include <vector> -#include "prio.h" -#include "sensors.h" -#include "OscillatorBank.h" -#include "DboxSensors.h" - - -//---------------------------------------- -// main extern variables -//---------------------------------------- -extern vector<OscillatorBank*> gOscBanks; -extern int gCurrentOscBank; -extern int gNextOscBank; -extern int gShouldStop; -extern int gVerbose; - -float gSensor0LatestTouchPos = 0; // most recent pitch touch location [0-1] on sensor 0, used by render.cpp -int gSensor0LatestTouchNum = 0; // most recent num of touches on sensor 0, used by render.cpp -float gSensor1LatestTouchPos[5]; // most recent touche locations on sensor 1, used by render.cpp -//float gSensor1LatestTouchSizes[5]; -int gSensor1LatestTouchCount; // most recent number touches on sensor 1, used by render.cpp -int gSensor1LatestTouchIndex = 0; // index of last touch in gSensor1LatestTouchPos[5], used by render.cpp -int gLastFSRValue = 1799; // most recent fsr value, used by render.cpp - - -DboxSensors Sensors; - - -//---------------------------------------- -// var shared with logger -//---------------------------------------- -int s0TouchNum = 0; -float s0Touches_[MAX_TOUCHES]; -float s0Size_[MAX_TOUCHES]; -int s0LastIndex; - -int s1TouchNum = 0; -float s1Touches_[MAX_TOUCHES]; -float s1Size_[MAX_TOUCHES]; -int s1LastIndex; - -int fsr = 1799; - - - -using namespace std; - -int initSensorLoop(int sensorAddress0, int sensorAddress1, int sensorType) -{ - int tk0_bus = 1; - int tk0_address = sensorAddress0; - int tk1_bus = 1; - int tk1_address = sensorAddress1; - int tk_file = 0; - int fsr_max = 1799; - int fsr_pinNum = 4; - - if(gVerbose==1) - cout << "---------------->Init Control Thread" << endl; - - if(Sensors.initSensors(tk0_bus, tk0_address, tk1_bus, tk1_address, tk_file, fsr_pinNum, fsr_max, sensorType)>0) - { - gShouldStop = 1; - cout << "control cannot start" << endl; - return -1; - } - - for(int i=0; i<MAX_TOUCHES; i++) - { - s0Touches_[i] = 0.0; - s0Size_[i] = 0.0; - - s1Touches_[i] = 0.0; - s1Size_[i] = 0.0; - } - - return 0; -} - -void sensorLoop(void *) -{ - timeval start, end; - unsigned long elapsedTime; - //float touchSize = 0; // once used for timbre - - - - float *s0Touches; - float *s0Size; - int s0PrevTouchNum = 0; - int s0SortedTouchIndices[MAX_TOUCHES]; - float s0SortedTouches[MAX_TOUCHES]; - float s0PrevSortedTouches[MAX_TOUCHES]; - - float *s1Touches; - float *s1Size; - int s1PrevTouchNum = 0; - int s1SortedTouchIndices[MAX_TOUCHES]; - float s1SortedTouches[MAX_TOUCHES]; - float s1PrevSortedTouches[MAX_TOUCHES]; - - float freqScaler = 0; - int fsrMin = 0;//50; // was 200 - int fsrMax = 1799;//1300; // was 800 - float vel = 0; - float prevVel = 0; - float filterMaxF = 0; - if(gVerbose==1) - dbox_printf("__________set Control Thread priority\n"); - - if(gVerbose==1) - dbox_printf("_________________Control Thread!\n"); - - // get freq scaler, cos freqs must be scaled according to the wavetable used in the oscillator bank - freqScaler = gOscBanks[gCurrentOscBank]->getFrequencyScaler(); - filterMaxF = gOscBanks[gCurrentOscBank]->filterMaxF; - - // init time vals - gettimeofday(&start, NULL); - - // here we go, sensor loop until the end of the application - while(!gShouldStop) - { - gettimeofday(&end, NULL); - elapsedTime = ( (end.tv_sec*1000000+end.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); - if( elapsedTime<4000 ) - usleep(4000-elapsedTime); - else - dbox_printf("%d\n", (int)elapsedTime); // this print happens when something's gone bad... - - if(Sensors.readSensors()==0) - { - s0TouchNum = Sensors.getTKTouchCount(0); - s0Touches = Sensors.getTKXPositions(0); - s0Size = Sensors.getTKTouchSize(0); - - s1TouchNum = Sensors.getTKTouchCount(1); - s1Touches = Sensors.getTKXPositions(1); - s1Size = Sensors.getTKTouchSize(1); - - for(int i=0; i<MAX_TOUCHES; i++) - { - s0Touches_[i] = s0Touches[i]; - s0Size_[i] = s0Size[i]; - - s1Touches_[i] = s1Touches[i]; - s1Size_[i] = s1Size[i]; - } - - gSensor0LatestTouchNum = s0TouchNum; - if(s0TouchNum > 0) - { - //----------------------------------------------------------------------------------- - // timbre, speed and pitch - //touchSize = 0; \\ once used for timbre - - // if we have a number of touches different from previous round, track their order of arrival [calculated using distance comparison] - if(s0PrevTouchNum!=s0TouchNum) - { - float distances[MAX_TOUCHES*(MAX_TOUCHES-1)]; // maximum number of current+previous touches between rounds with different num of touches - int ids[MAX_TOUCHES*(MAX_TOUCHES-1)]; - // calculate all distance permutations between previous and current touches - for(int i=0; i<s0TouchNum; i++) - { - for(int p=0; p<s0PrevTouchNum; p++) - { - int index = i*s0PrevTouchNum+p; // permutation id [says between which touches we are calculating distance] - distances[index] = fabs(s0Touches[i]-s0PrevSortedTouches[p]); - ids[index] = index; - if(index>0) - { - // sort, from min to max distance - float tmp; - while(distances[index]<distances[index-1]) - { - tmp = ids[index-1]; - ids[index-1] = ids[index]; - ids[index] = tmp; - - tmp = distances[index-1]; - distances[index-1] = distances[index]; - distances[index] = tmp; - - index--; - - if(index == 0) - break; - } - } - } - } - - int sorted = 0; - bool currAssigned[MAX_TOUCHES] = {false}; - bool prevAssigned[MAX_TOUCHES] = {false}; - - // track touches assigning index according to shortest distance - for(int i=0; i<s0TouchNum*s0PrevTouchNum; i++) - { - int currentIndex = ids[i]/s0PrevTouchNum; - int prevIndex = ids[i]%s0PrevTouchNum; - // avoid double assignment - if(!currAssigned[currentIndex] && !prevAssigned[prevIndex]) - { - currAssigned[currentIndex] = true; - prevAssigned[prevIndex] = true; - s0SortedTouchIndices[currentIndex] = prevIndex; - sorted++; - } - } - // we still have to assign a free index to new touches - if(s0PrevTouchNum<s0TouchNum) - { - for(int i=0; i<s0TouchNum; i++) - { - if(!currAssigned[i]) - s0SortedTouchIndices[i] = sorted++; // assign next free index - - // update tracked value - s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i]; - s0PrevSortedTouches[i] = s0SortedTouches[i]; - if(s0SortedTouchIndices[i]==s0TouchNum-1) - s0LastIndex = i; - - // accumulate sizes for timbre - //touchSize += s0Size[i]; - } - } - else // some touches have disappeared... - { - // ...we have to shift all indices... - for(int i=s0PrevTouchNum-1; i>=0; i--) - { - if(!prevAssigned[i]) - { - for(int j=0; j<s0TouchNum; j++) - { - // ...only if touches that disappeared were before the current one - if(s0SortedTouchIndices[j]>i) - s0SortedTouchIndices[j]--; - } - } - } - // done! now update - for(int i=0; i<s0TouchNum; i++) - { - // update tracked value - s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i]; - s0PrevSortedTouches[i] = s0SortedTouches[i]; - if(s0SortedTouchIndices[i]==s0TouchNum-1) - s0LastIndex = i; - - // accumulate sizes for timbre - //touchSize += s0Size[i]; - } - } - } - else // nothing's changed since last round - { - for(int i=0; i<s0TouchNum; i++) - { - // update tracked value - s0SortedTouches[s0SortedTouchIndices[i]] = s0Touches[i]; - s0PrevSortedTouches[i] = s0SortedTouches[i]; - - // accumulate sizes for timbre - //touchSize += s0Size[i]; - } - } - - if(s0TouchNum == 0) - s0LastIndex = -1; - - // timbre - //touchSize = (touchSize > 0.7) ? 1 : touchSize/0.7; - //gOscBanks[gCurrentOscBank]->hopNumTh = log((1-touchSize)+1)/log(2)*20000; - //gOscBanks[gCurrentOscBank]->hopNumTh = 0; - - - // pitch, controlled by last touch - //prevTouchPos = touch[touchIndex]; - //touchPos = (s0SortedTouches[s0TouchNum-1]-0.5)/0.5; // from [0,1] to [-1,1] - gSensor0LatestTouchPos = s0SortedTouches[s0TouchNum-1]; - //touchPos = s0Touches[0]; - //gOscBanks[gCurrentOscBank]->pitchMultiplier = pow(2, touchPos); - //----------------------------------------------------------------------------------- - - - - //----------------------------------------------------------------------------------- - // note on - //if(s0PrevTouchNum == 0) - // gOscBanks[gCurrentOscBank]->play(); - // fsr = Sensors.getFSRVAlue(); - fsr = gLastFSRValue; - //dbox_printf("fsr: %d\n", fsr); - if(!gOscBanks[gCurrentOscBank]->note) - { - vel = fsr; - vel /= (float)(fsrMax-fsrMin); - - vel = 1-vel; - dbox_printf("Attack vel: %f\n", vel); - gOscBanks[gCurrentOscBank]->play(vel); - prevVel = vel; - } - else if(gOscBanks[gCurrentOscBank]->getEnvelopeState() != env_release) - { - fsr = (fsr > fsrMax) ? fsrMax : fsr; - vel = (fsr < fsrMin) ? fsrMin : fsr; - vel -= fsrMin; - vel /= (float)(fsrMax-fsrMin); - vel = 1-vel; - if(vel > prevVel) - { - gOscBanks[gCurrentOscBank]->afterTouch(vel); - prevVel = vel; - } - } - //----------------------------------------------------------------------------------- - } - else - { - //prevFsr = 1799; - //prevTouchPos = -1; - //----------------------------------------------------------------------------------- - // note off - if(s0PrevTouchNum > 0) - { - if(gOscBanks[gCurrentOscBank]->state==bank_playing) - gOscBanks[gCurrentOscBank]->stop(); - } - //----------------------------------------------------------------------------------- - } - - - - // sensor 2 - //----------------------------------------------------------------------------------- - //filter - calculated even when no touches on first sensor, to filter also release tail - gOscBanks[gCurrentOscBank]->filterNum = s1TouchNum; - - gSensor1LatestTouchCount = gOscBanks[gCurrentOscBank]->filterNum; - for(int i = 0; i < gSensor1LatestTouchCount; i++) { - gSensor1LatestTouchPos[i] = s1Touches[i]; - //gSensor1LatestTouchSizes[i] = s1Size[i]; - } - -/* for(int i=0; i<gOscBanks[gCurrentOscBank]->filterNum; i++) - { - // touch pos is linear but freqs are log - gOscBanks[gCurrentOscBank]->filterFreqs[i] = ((exp(s0Touches[i]*4)-1)/(exp(4)-1))*filterMaxF*freqScaler; - //gOscBanks[gCurrentOscBank]->filterQ[i] = size[i]*5*(1+touch[i]*1000)*freqScaler; - gOscBanks[gCurrentOscBank]->filterQ[i] = s0Size[i]; - if(gOscBanks[gCurrentOscBank]->filterFreqs[i]>500*freqScaler) - gOscBanks[gCurrentOscBank]->filterPadding[i] = 1+100000*( (gOscBanks[gCurrentOscBank]->filterFreqs[i]-500*freqScaler)/(filterMaxF-500)*freqScaler ); - else - gOscBanks[gCurrentOscBank]->filterPadding[i] = 1; - }*/ - - // each touch on sensor 2 is a notch filter, whose Q is determined by touch size - for(int i=0; i<gOscBanks[gCurrentOscBank]->filterNum; i++) - { - // map touch pos [which is linear] on freqs exponentially - float freq = ((exp(s1Touches[i]*4)-1)/EXP_DENOM)*filterMaxF; - gOscBanks[gCurrentOscBank]->filterFreqs[i] = freq*freqScaler; - // also size is mapped exponentially on Q - float siz = (exp(s1Size[i])-1)/1.71828; - gOscBanks[gCurrentOscBank]->filterQ[i] = siz*( (filterMaxF-freq)/filterMaxF * 0.9 + 0.1 ); // size weight on Q decreases with frequency - } - //----------------------------------------------------------------------------------- - - - - //----------------------------------------------------------------------------------- - // sort touches on sensor 2 - if(s1TouchNum > 0) - { - // if we have a number of touches different from previous round, track their order of arrival [calculated using distance comparison] - if(s1PrevTouchNum!=s1TouchNum) - { - float distances[MAX_TOUCHES*(MAX_TOUCHES-1)]; // maximum number of current+previous touches between rounds with different num of touches - int ids[MAX_TOUCHES*(MAX_TOUCHES-1)]; - // calculate all distance permutations between previous and current touches - for(int i=0; i<s1TouchNum; i++) - { - for(int p=0; p<s1PrevTouchNum; p++) - { - int index = i*s1PrevTouchNum+p; // permutation id [says between which touches we are calculating distance] - distances[index] = fabs(s1Touches[i]-s1PrevSortedTouches[p]); - ids[index] = index; - if(index>0) - { - // sort, from min to max distance - float tmp; - while(distances[index]<distances[index-1]) - { - tmp = ids[index-1]; - ids[index-1] = ids[index]; - ids[index] = tmp; - - tmp = distances[index-1]; - distances[index-1] = distances[index]; - distances[index] = tmp; - - index--; - - if(index == 0) - break; - } - } - } - } - - int sorted = 0; - bool currAssigned[MAX_TOUCHES] = {false}; - bool prevAssigned[MAX_TOUCHES] = {false}; - - // track touches assigning index according to shortest distance - for(int i=0; i<s1TouchNum*s1PrevTouchNum; i++) - { - int currentIndex = ids[i]/s1PrevTouchNum; - int prevIndex = ids[i]%s1PrevTouchNum; - // avoid double assignment - if(!currAssigned[currentIndex] && !prevAssigned[prevIndex]) - { - currAssigned[currentIndex] = true; - prevAssigned[prevIndex] = true; - s1SortedTouchIndices[currentIndex] = prevIndex; - sorted++; - } - } - // we still have to assign a free index to new touches - if(s1PrevTouchNum<s1TouchNum) - { - for(int i=0; i<s1TouchNum; i++) - { - if(!currAssigned[i]) - s1SortedTouchIndices[i] = sorted++; // assign next free index - - // update tracked value - s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i]; - s1PrevSortedTouches[i] = s1SortedTouches[i]; - if(s1SortedTouchIndices[i]==s1TouchNum-1) - s1LastIndex = i; - } - } - else // some touches have disappeared... - { - // ...we have to shift all indices... - for(int i=s1PrevTouchNum-1; i>=0; i--) - { - if(!prevAssigned[i]) - { - for(int j=0; j<s1TouchNum; j++) - { - // ...only if touches that disappeared were before the current one - if(s1SortedTouchIndices[j]>i) - s1SortedTouchIndices[j]--; - } - } - } - // done! now update - for(int i=0; i<s1TouchNum; i++) - { - // update tracked value - s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i]; - s1PrevSortedTouches[i] = s1SortedTouches[i]; - if(s1SortedTouchIndices[i]==s1TouchNum-1) - s1LastIndex = i; - } - } - } - else // nothing's changed since last round - { - for(int i=0; i<s1TouchNum; i++) - { - // update tracked value - s1SortedTouches[s1SortedTouchIndices[i]] = s1Touches[i]; - s1PrevSortedTouches[i] = s1SortedTouches[i]; - } - } - } - - if(s1TouchNum > 0) - { - gSensor1LatestTouchIndex = s1LastIndex; - } - else - s1LastIndex = -1; - -/* dbox_printf("-----------------------------\nnum: %d, latest: %d\n", s1TouchNum, gSensor1LatestTouchIndex); - for(int i=0; i<s1TouchNum; i++) - dbox_printf("\t%f\n", gSensor1LatestTouchPos[i]); - dbox_printf("------\n"); - for(int i=0; i<s1TouchNum; i++) - dbox_printf("\t%f\n", s1SortedTouches[i]);*/ - - - - // update variables for both sensors - s0PrevTouchNum = s0TouchNum; - s1PrevTouchNum = s1TouchNum; - } - else - dbox_printf("Come on instrument!\n"); //break - - gettimeofday(&start, NULL); - } - - dbox_printf("sensor thread ended\n"); -} - -void *keyboardLoop(void *) -{ - if(gVerbose==1) - cout << "_________________Keyboard Control Thread!" << endl; - - char keyStroke = '.'; - cout << "Press q to quit." << endl; - - float speed; - - do - { - keyStroke = getchar(); - while(getchar()!='\n'); // to read the first stroke - - switch (keyStroke) - { - //---------------------------------------------------------------------------- - case 'a': - gOscBanks[gCurrentOscBank]->hopNumTh = 0; - gOscBanks[gCurrentOscBank]->play(1); - //cout << "Note on" << endl; - break; - case 's': - if(gOscBanks[gCurrentOscBank]->state==bank_playing) - { - gOscBanks[gCurrentOscBank]->stop(); - //cout << "Note off" << endl; - } - break; - //---------------------------------------------------------------------------- - case '[': - gOscBanks[gCurrentOscBank]->freqMovement-=0.05; - if(gOscBanks[gCurrentOscBank]->freqMovement<0) - gOscBanks[gCurrentOscBank]->freqMovement = 0; - //cout << "gOscBanks[gCurrentOscBank]->FreqMov: " << gOscBanks[gCurrentOscBank]->freqMovement << endl; - break; - case ']': - gOscBanks[gCurrentOscBank]->freqMovement+=0.05; - if(gOscBanks[gCurrentOscBank]->freqMovement>1) - gOscBanks[gCurrentOscBank]->freqMovement = 1; - //cout << "gOscBanks[gCurrentOscBank]->FreqMov: " << gOscBanks[gCurrentOscBank]->freqMovement << endl; - break; - //---------------------------------------------------------------------------- - case '<': - speed = gOscBanks[gCurrentOscBank]->getSpeed() - 0.1 ; - gOscBanks[gCurrentOscBank]->setSpeed(speed); - dbox_printf("Speed: %f\n", speed); - - break; - case '>': - speed = gOscBanks[gCurrentOscBank]->getSpeed() + 0.1 ; - gOscBanks[gCurrentOscBank]->setSpeed(speed); - dbox_printf("Speed: %f\n", speed); - break; - case '0': - speed = 0.1; - gOscBanks[gCurrentOscBank]->setSpeed(speed); - dbox_printf("Speed: %f\n", speed); - break; - case '1': - speed = 0.5; - gOscBanks[gCurrentOscBank]->setSpeed(speed); - dbox_printf("Speed: %f\n", speed); - break; - case '2': - speed = 1; - gOscBanks[gCurrentOscBank]->setSpeed(speed); - dbox_printf("Speed: %f\n", speed); - break; - case '3': - speed = 2; - gOscBanks[gCurrentOscBank]->setSpeed(speed); - dbox_printf("Speed: %f\n", speed); - break; - case '4': - speed = 3; - gOscBanks[gCurrentOscBank]->setSpeed(speed); - dbox_printf("Speed: %f\n", speed); - break; - //---------------------------------------------------------------------------- - case 'z': - gOscBanks[gCurrentOscBank]->setJumpHop(0); - break; - case 'x': - gOscBanks[gCurrentOscBank]->setJumpHop(100); - break; - case 'c': - gOscBanks[gCurrentOscBank]->setJumpHop(600); - break; - case 'v': - gOscBanks[gCurrentOscBank]->setJumpHop(1100); - break; - case 'b': - gOscBanks[gCurrentOscBank]->setJumpHop(2000); - break; - case 'n': - gOscBanks[gCurrentOscBank]->setJumpHop(gOscBanks[gCurrentOscBank]->getLastHop()); - break; - //---------------------------------------------------------------------------- - case 'q': - gShouldStop = true; - break; - case 'o': - gNextOscBank = (gCurrentOscBank + 1) % gOscBanks.size(); - break; - default: - break; - //---------------------------------------------------------------------------- - } - usleep(1000); /* Wait 1ms to avoid checking too quickly */ - } - while (keyStroke!='q'); - - cout << "keyboard thread ended" << endl; - - return (void *)0; -}
--- a/examples/d-box/sensors.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* - * sensors.h - * - * Created on: May 28, 2014 - * Author: Victor Zappi - */ - -#ifndef SENSORS_H_ -#define SENSORS_H_ - -#include "config.h" - -int initSensorLoop(int sensorAddress0, int sensorAddress1, int sensorType); - -void sensorLoop(void *); -void *keyboardLoop(void *); - - -#endif /* SENSORS_H_ */
--- a/examples/d-box/spear_parser.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,641 +0,0 @@ -/* - * spear_parser.cpp v1.2 - * - * Created on: May 6, 2014 - * Author: Victor Zappi - */ - -#include "spear_parser.h" - -using namespace std; - -//#define DO_CHECKS - -//------------------------------------------------------------------------------------------------ -// partials -//------------------------------------------------------------------------------------------------ - -Partials::Partials() -{ - partialFrequencies = NULL; -// partialAmplitudes = NULL; -// partialNumFrames = NULL; -// partialStartSample = NULL; -// partialEndSample = NULL; -// partialCurrentFrame = NULL; -// partialFreqDelta = NULL; -// partialAmpDelta = NULL; - - - activePartialNum = NULL; -// activePartials = NULL; - - currentSample = -1; -} - -Partials::~Partials() -{ - if(partialFrequencies != NULL) // check on one is enough - { - if(partialFrequencies[0] != NULL) // check on one is enough - { - for(unsigned int i=0; i<parNum; i++) - { - delete[] partialFrequencies[i]; - delete[] partialAmplitudes[i]; - delete[] partialFreqDelta[i]; - delete[] partialAmpDelta[i]; - - } - } - - delete[] partialFrequencies; - delete[] partialAmplitudes; - delete[] partialNumFrames; - delete[] partialFreqDelta; - delete[] partialAmpDelta; - delete[] partialFreqMean; - } - - if(activePartialNum != NULL) - { - for(unsigned int i=0; i<hopNum+1; i++) - delete[] activePartials[i]; - - delete[] activePartialNum; - delete[] activePartials ; - } -} - -void Partials::init(int parN, int hopS, bool isDBX) -{ - if(!isDBX) - { - parNum = parN; - hopSize = hopS; - - partialFrequencies = new float *[parNum]; - partialAmplitudes = new float *[parNum]; - partialNumFrames = new unsigned int[parNum]; - partialStartFrame = new unsigned int[parNum]; - partialStartSample = new unsigned int[parNum]; - partialEndSample = new unsigned int[parNum]; - partialFreqDelta = new float *[parNum]; - partialAmpDelta = new float *[parNum]; - partialFreqMean = new float[parNum]; - - - - // init in one shot - fill(partialFreqMean, partialFreqMean+parNum, 0); // mean is zero - - partialFrequencies[0] = NULL; // for free check - } - else - { - parNum = parN; - hopSize = hopS; - - partialFrequencies = new float *[parNum]; - partialAmplitudes = new float *[parNum]; - partialNumFrames = new unsigned int[parNum]; - partialStartFrame = new unsigned int[parNum]; - partialFreqDelta = new float *[parNum]; - partialAmpDelta = new float *[parNum]; - partialFreqMean = new float[parNum]; - - partialFrequencies[0] = NULL; // for free check - } -} - - - -void Partials::update(int parIndex, int frameNum) -{ - partialFrequencies[parIndex] = new float[frameNum]; - partialAmplitudes[parIndex] = new float[frameNum]; - partialFreqDelta[parIndex] = new float[frameNum]; - partialAmpDelta[parIndex] = new float[frameNum]; - - fill(partialFreqDelta[parIndex], partialFreqDelta[parIndex]+frameNum, 99999.0); // in the end, only the last one will have 99999 - fill(partialAmpDelta[parIndex], partialAmpDelta[parIndex]+frameNum, 99999.0); // in the end, only the last one will have 99999 -} - - - - - - - - - - - - - - - - - - - - -//------------------------------------------------------------------------------------------------ -// spear parser -//------------------------------------------------------------------------------------------------ -Spear_parser::Spear_parser() -{ - // some default values - hopSize = -1; - fileSampleRate = -1; -} - -Spear_parser::~Spear_parser() -{ -} - -void Spear_parser::calculateHopSize(char *filename) -{ - int index = 0; - bool prevWas_ = false; - bool found_h = false; - int n = 0; - - hopSize = 0; - - do - { - // check if '_' - if(filename[index] == '_') - prevWas_ = true; - else if( (filename[index] == 'h') && prevWas_) // if it is not, but it is 'h' and previous was '_', found "_h"! - { - found_h = true; - while(filename[index] != '\0') - { - index++; - if( (filename[index] == '.') || (filename[index] == '_')) - break; - else // i am not checking if char are digits...! - { - n = filename[index]; - hopSize = hopSize*10+(n-48); - } - } - } - else // else, nothing - prevWas_ = false; - index++; - } - while( (filename[index] != '\0') && !found_h ); - - if( !found_h || (hopSize<1) ) - hopSize = 551; // default val - -} - - -bool Spear_parser::parser(char *filename, int hopsize, int samplerate) -{ - string name = string(filename); - int len = name.length(); - // invoke correct parser according to the type of file...just checking the extension, crude but functional - if( (name[len-4]=='.') && (name[len-3]=='d') && (name[len-2]=='b') && (name[len-1]=='x') ) - return DBXparser(filename, samplerate); // .dbox - else - return TXTparser(filename, hopSize, samplerate); // .txt, or whatever -} - - -bool Spear_parser::DBXparser(char *filename, int samplerate) -{ - fileSampleRate = samplerate; - - // working vars - int parNum = 0; // total num of partials - int hopNum = 0; // total num of hops - - //---------------------------------------------------------------------------------------- - // open a file - ifstream fin; - fin.open(filename, ios::in | ios::binary); - if (!fin.good()) - { - cout << "Parser Error: file not found" << endl; // exit if file not found - return false; - } - - gettimeofday(&start, NULL); - //---------------------------------------------------------------------------------------- - // general data - - // look for partial count - fin.read((char *) &parNum, sizeof(int)); - partials.parNum = parNum; - - // look for hop count - fin.read((char *) &hopNum, sizeof(int)); - partials.setHopNum(hopNum); - - // look for hop size - fin.read((char *) &hopSize, sizeof(int)); - partials.hopSize = hopSize; // it's handy for both classes to know it - - // init partials data structure - partials.init(parNum, hopSize, true); - - // look for max active par num - fin.read((char *) &(partials.maxActiveParNum), sizeof(int)); - - - - // partial data - - // start frame of each partial - fin.read((char *) partials.partialStartFrame, sizeof(int)*parNum); - - // num of frames of each partial - fin.read((char *) partials.partialNumFrames, sizeof(int)*parNum); - - // frequency mean of each partial - fin.read((char *) partials.partialFreqMean, sizeof(int)*parNum); - - for(int par=0; par<parNum; par++) - { - int frameNum = partials.partialNumFrames[par]; - partials.update(par, frameNum); - fin.read((char *)partials.partialAmplitudes[par], sizeof(float)*frameNum); // amplitude of each partial in each frame - fin.read((char *)partials.partialFrequencies[par], sizeof(float)*frameNum); // frequency of each partial in each frame - fin.read((char *)partials.partialAmpDelta[par], sizeof(float)*frameNum); // amplitude delta of each partial in each frame - fin.read((char *)partials.partialFreqDelta[par], sizeof(float)*frameNum); // frequency delta of each partial in each frame - } - - - - - // frame data - - // number of active partial per each frame - fin.read((char *) partials.activePartialNum, sizeof(short)*(hopNum+1)); - // init array - for(int frame=0; frame<hopNum+1; frame++) - { - partials.activePartials[frame] = new unsigned int[partials.activePartialNum[frame]]; - fin.read((char *)partials.activePartials[frame], sizeof(int)*partials.activePartialNum[frame]); // active partials per each frame - } - - - - - - gettimeofday(&stop, NULL); - parserT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); - - - printf("\n-----------------------\n"); - printf("\nFile: %s\n", filename); - printf("\n-----------------------\n"); - printf("Profiler\n"); - printf("-----------------------\n"); - printf("File parser:\t\t\t%lu usec\n", parserT); - printf("\n\nTotal:\t\t%lu usec\n", parserT); - printf("-----------------------\n"); - - fin.close(); - - return true; -} - - - - -bool Spear_parser::TXTparser(char *filename, int hopsize, int samplerate) -{ - hopSize = hopsize; - fileSampleRate = samplerate; - if(hopsize<0) - { - gettimeofday(&start, NULL); - calculateHopSize(filename); - gettimeofday(&stop, NULL); - hopSizeT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); - } - else - hopSizeT = 0; - - calculateDeltaTime(); - - // working vars - char * token; // where to save single figures from file - string s = ""; // where to save lines from file - int parNum = 0; // total num of partials - int parIndex = -1; // index of current partial - int frameNum = 0; // total num of frames - int frameIndex = -1; // index of current frame - int startSample = -1; // sample value for first frame of partials - int endSample = -1; // sample value for last frame of partials - int maxSample = 0; // to calculate total number of hops in file - int missSampCnt = 0; // number of mising samples - double freq = 0; // to calculate frequency delta - double prevFreq = 0; // to calculate frequency delta - double amp = 0; // to calculate amplitude delta - double prevAmp = 0; // to calculate amplitude delta - - - //---------------------------------------------------------------------------------------- - // open a file - ifstream fin; - fin.open(filename); - if (!fin.good()) - { - cout << "Parser Error: file not found" << endl; // exit if file not found - return false; - } - - gettimeofday(&start, NULL); - //---------------------------------------------------------------------------------------- - // init partials data structure - getline(fin, s); - getline(fin, s); - getline(fin, s); // third line is the first we are interested into - - // look for partial count - token = strtok((char *)s.c_str(), " "); - // check if first token is there - if(token) - { - token = strtok(0, " "); - // check if second token is there - if(token) - parNum = atoi(token); - #ifdef DO_CHECKS - else - { - cout << "Parser Error: partial count not found, bad file format" << endl; // exit if value not found - return false; - } - #endif - } - #ifdef DO_CHECKS - else - { - cout << "Parser Error: partial count not found, bad file format" << endl; // exit if value not found - return false; - } - #endif - // from now on we take for granted that format is correct - - // init partials data structure - partials.init(parNum, hopSize); - - //---------------------------------------------------------------------------------------- - // fill in partials data structure - getline(fin, s); // get rid of intro line "partials-data" - getline(fin, s); // first important line - - while (!fin.eof()) - { - //------------------------------------- - // partial specific info - token = strtok((char *)s.c_str(), " "); - parIndex = atoi(token); // partial index - - token = strtok(0, " "); // num of frames, not used, cos we will do linear interpolation for missing frames -// frameNum = atoi(token); -// partials.partialNumFrames[parIndex] = frameNum; - - token = strtok(0, " "); // time of first frame, still char * - startSample = fromTimeToSamples(atof(token)); // convert time to samples - partials.partialStartSample[parIndex] = startSample; - - token = strtok(0, " "); // time of last frame, still char * - endSample = fromTimeToSamples(atof(token)); // convert time to samples - partials.partialEndSample[parIndex] = endSample; - - frameNum = ((endSample-startSample)/hopSize) + 1; // num of frames, including missing consecutive ones [+1 one cos we count frames, not hops] - partials.partialNumFrames[parIndex] = frameNum; - - - // check if this is the highest sample value so far - if(endSample > maxSample) - maxSample = endSample; - - // update data structure - partials.update(parIndex, frameNum); - - - //------------------------------------- - // frames - getline(fin, s); - token = strtok((char *)s.c_str(), " "); // frame time - frameIndex = -1; - - // unroll first iteration, so that in the following loop we save the check on the last frame to calculate increments - if(token) // all frames data are on one line, in groups of 3 entries - { - frameIndex++; - - endSample = fromTimeToSamples(atof(token)); - - token = strtok(0, " "); // frame frequency - prevFreq = atof(token); - partials.partialFrequencies[parIndex][frameIndex] = (float)prevFreq; - partials.partialFreqMean[parIndex] += prevFreq; // for frequency mean - - token = strtok(0, " "); // frame amplitude - prevAmp = atof(token); - partials.partialAmplitudes[parIndex][frameIndex] = (float)prevAmp; - - token = strtok(0, " "); // next frame frequency, to be checked - } - - // here the loop starts - while(token) // all frames data are on one line, in groups of 3 entries - { - frameIndex++; - missSampCnt = 0; - - startSample = fromTimeToSamples(atof(token)); - - token = strtok(0, " "); // frame frequency - freq = atof(token); - - token = strtok(0, " "); // frame amplitude - amp = atof(token); - // now we know all about the current frame, but we want to know if some frames are missing between this and the last one - - // while current frame sample is farther than one hopsize... - while(startSample > endSample+hopSize) - { - missSampCnt++; // ...one sample is missing - endSample += hopSize; // move to next hop - } - - // if frames are missing do interpolation and update indices - if(missSampCnt>0) - startSample = interpolateSamples(parIndex, &frameIndex, missSampCnt, endSample+hopSize, freq, amp, &prevFreq, &prevAmp); - - partials.partialFrequencies[parIndex][frameIndex] = (float)freq; - partials.partialFreqMean[parIndex] += freq; // for frequency mean - partials.setFreqDelta(parIndex, frameIndex-1, (freq-prevFreq)/hopSize); // freq delta between prev and current frame - prevFreq = freq; - - partials.partialAmplitudes[parIndex][frameIndex] = (float)amp; - partials.setAmpDelta(parIndex, frameIndex-1, (amp-prevAmp)/hopSize); // amp delta between prev and current frame - prevAmp = amp; - - endSample = startSample; - token = strtok(0, " "); // next frame frequency, to be checked - } - #ifdef DO_CHECKS - if(frameIndex != (frameNum-1)) - { - cout << "Parser Error: frame count mismatch on partial " << parIndex << ", bad file format" << endl; // exit if mismatch - cout << "frameIndex: " << frameIndex << endl; - cout << "frameNum: " << frameNum << endl; - return false; - } - #endif - - partials.partialFreqMean[parIndex] /= partials.partialNumFrames[parIndex]; // frequency mean - - getline(fin, s); // next partial line, to check - } - #ifdef DO_CHECKS - if(parIndex != (parNum-1)) - { - cout << "Parser Error: partial count mismatch, bad file format" << endl; // exit if mismatch - return false; - } - #endif - - partials.setHopNum(maxSample/hopSize); - - gettimeofday(&stop, NULL); - parserT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); - - gettimeofday(&start, NULL); - staticCalculations(); - gettimeofday(&stop, NULL); - staticT = ( (stop.tv_sec*1000000+stop.tv_usec) - (start.tv_sec*1000000+start.tv_usec) ); - - fin.close(); - - - printf("\n-----------------------\n"); - printf("\nFile: %s\n", filename); - printf("\n-----------------------\n"); - printf("Profiler\n"); - printf("-----------------------\n"); - printf("Hop size parser:\t\t%lu usec\n", hopSizeT); - printf("File parser:\t\t\t%lu usec\n", parserT); - printf("Static calculations:\t\t%lu usec\n", staticT); - printf("\n\nTotal:\t\t%lu usec\n", hopSizeT+parserT+staticT); - printf("-----------------------\n"); - - return true; -} - - -int Spear_parser::interpolateSamples(int parIndex, int *frameIndex, int missCnt, int nextSample, double nextFreq, double nextAmp, double *prevFreq, double *prevAmp) -{ - int frame = *frameIndex; // current frame index - int sample = nextSample - (hopSize*(missCnt)); // move from next real frame sample to first missing frame sample - double freq = *prevFreq; // freq of the prev real frame - double freqStep = (nextFreq-*prevFreq)/(missCnt+1); // fixed freq step between hops, for missing frames [linear interpolation] - double deltaFreq = freqStep/hopSize; // fixed hop freq step in samples - double amp = *prevAmp; // same for amp... - double ampStep = (nextAmp-*prevAmp)/(missCnt+1); - double deltaAmp = ampStep/hopSize; - - // for each missing frame - for(int i=0; i<missCnt; i++) - { - // calculate values for current missing frame - freq += freqStep; - amp += ampStep; - // save values - partials.partialFrequencies[parIndex][frame] = freq; - partials.partialAmplitudes[parIndex][frame] = amp; - partials.partialFreqMean[parIndex] += freq; // for frequency mean - // set deltas of previous frame [real or missing] - partials.setFreqDelta(parIndex, frame-1, deltaFreq); - partials.setAmpDelta(parIndex, frame-1, deltaAmp); - // move to next frame [missing or real] - sample += hopSize; - frame++; - } - - // update global values - *frameIndex = frame; - *prevFreq = freq; - *prevAmp = amp; - - return sample; // return the frame sample of the next real frame -} - - - -// for each frame, statically calculate: -// - which partial is active [and the total num of active partials] -// - at which local frame each partial is -void Spear_parser::staticCalculations() -{ - partials.maxActiveParNum = 0; // init to find maximum - - unsigned short *indices = new unsigned short[partials.parNum]; // temp array to store up to the maximum num of active partial indices - unsigned int activeCnt = 0; // counts the num of active partials in each frame - - unsigned int frameSample = 0; // current frame in samples - - char *partialStarted = new char [partials.parNum]; // index of the last local frame found per each partial - fill(partialStarted, partialStarted+partials.parNum, 0); - - for(unsigned int i=0; i<partials.hopNum+1; i++) // for each frame [not hops, this explains the +1] - { - //partials.localPartialFrames[i] = new int[partials.parNum]; // init all local frames to -1 - //fill(partials.localPartialFrames[i], partials.localPartialFrames[i]+partials.parNum, -1); - - frameSample = i*hopSize; // current frame, expressed in samples - activeCnt = 0; // reset a each frame - - for(unsigned int j=0; j<partials.parNum; j++) // for each partial - { - // check if inside active time region [expressed in samples] - if( (frameSample>=partials.partialStartSample[j]) && (frameSample<partials.partialEndSample[j]) ) // frame sample not equal to end sample, this filters out last frames and partials with one frame only - { - // activity - indices[activeCnt] = j; // save active index - activeCnt++; // increase counter - - // partial local frames - if(partialStarted[j]==0) // this partial has just started, so current local frame is first frame - { - partialStarted[j] = 1; - partials.partialStartFrame[j] = i; // here is the number of the first frame - } - } - } - - // activity - partials.activePartialNum[i] = activeCnt; // save number of active partials for this frame - partials.activePartials[i] = new unsigned int[activeCnt]; // set correct size to save all indices - - // look for maximum number of active partials at the same time - if(activeCnt > partials.maxActiveParNum) - partials.maxActiveParNum = activeCnt; - - // copy indices - for(unsigned int k=0; k<activeCnt; k++) - partials.activePartials[i][k] = indices[k]; - } - - delete[] indices; - delete[] partialStarted; - - delete[] partials.partialStartSample; - delete[] partials.partialEndSample; -} - - -
--- a/examples/d-box/spear_parser.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * spear_parser.h v1.2 - * - * Created on: May 6, 2014 - * Author: Victor Zappi - */ - -#ifndef SPEAR_PARSER_H_ -#define SPEAR_PARSER_H_ - -#include <iostream> -#include <fstream> -#include <cstring> -#include <string> -#include <stdlib.h> // atoi, atof -#include <math.h> -#include <algorithm> // std::fill - -#include <sys/time.h> - -using namespace std; - - -//------------------------------------------------------------------------------------------------ -// partials -//------------------------------------------------------------------------------------------------ - -class Spear_parser; // for class friendship - -class Partials -{ - friend class Spear_parser; - friend class Dbox_parser; - -public: - int **partialSamples; // sample at which each frame is - float **partialFrequencies; // frequencies at each frame - float **partialAmplitudes; // amplitudes at each frame - unsigned int *partialNumFrames; // Length of each partial in frames - unsigned int *partialStartFrame; // frame at which each partial begins - float **partialFreqDelta; // constant frequency slope for each partial in each frame interval - float **partialAmpDelta; // constant amplitude slope for each partial in each frame interval - float *partialFreqMean; // frequency mean for each partial, over all its frames - - unsigned short *activePartialNum; // num of each active partial at each frame - unsigned int **activePartials; // indices of all active partials at each frame - - - int getPartialNum(); - int getHopNum(); - int getMaxActivePartialNum(); - -private: - Partials(); - ~Partials(); - - unsigned int *partialStartSample; // sample at which each partial begins - unsigned int *partialEndSample; // sample at which each partial ends [sample gap between 2 consecutive frames can be an integer multiple of hopSize] - unsigned int parNum; - unsigned int currentSample; - unsigned int hopSize; - unsigned int hopNum; - unsigned int maxActiveParNum; - - void init(int parNum, int hopSize, bool isDBX=false); - void update(int parIndex, int frameNum); - void setFreqDelta(int parIndex, int frameNum, double delta); - void setAmpDelta(int parIndex, int frameNum, double delta); - void setHopNum(int hopNum); -}; - -inline int Partials::getPartialNum() -{ - return parNum; -} - -inline void Partials::setHopNum(int hopN) -{ - hopNum = hopN; - - // prepare data structures - activePartialNum = new unsigned short[hopNum+1]; // +1 cos total num of frames = num of hops+1 - activePartials = new unsigned int *[hopNum+1]; -} - -// useful to increase current sample using a modulo on the total number of samples [easy to be deduced from the total num or hops] -inline int Partials::getHopNum() -{ - return hopNum; -} - -inline void Partials::setFreqDelta(int parIndex, int frameNum, double delta) -{ - partialFreqDelta[parIndex][frameNum] = delta; -} - -inline void Partials::setAmpDelta(int parIndex, int frameNum, double delta) -{ - partialAmpDelta[parIndex][frameNum] = delta; -} - -inline int Partials::getMaxActivePartialNum() -{ - return maxActiveParNum; -} - - - - - - - -//------------------------------------------------------------------------------------------------ -// spear parser -//------------------------------------------------------------------------------------------------ - -class Spear_parser -{ -public: - Spear_parser(); - ~Spear_parser(); - - Partials partials; - - bool parseFile(string filename, int hopsize=-1, int samplerate = 44100); - bool parseFile(char *filename, int hopsize=-1, int samplerate = 44100); - int getHopSize(); - int getFileSampleRate(); - double getDeltaTime(); - -private: - - int hopSize; - int fileSampleRate; - double deltaTime; // min time gap between consecutive frames - - timeval start, stop; - unsigned long hopSizeT, parserT, staticT; - - void calculateDeltaTime(); - void calculateHopSize(char *filename); - bool parser(char *filename, int hopsize=-1, int samplerate=44100); - bool DBXparser(char *filename, int samplerate=44100); - bool TXTparser(char *filename, int hopsize=-1, int samplerate=44100); - int fromTimeToSamples(float time); - int interpolateSamples(int parIndex, int *frameIndex, int missCnt, int nextSample, - double nextFreq, double nextAmp, double *prevFreq, double *prevAmp); - void staticCalculations(); - -}; - -inline bool Spear_parser::parseFile(string filename, int hopsize, int samplerate) -{ - return parser((char *)filename.c_str(), hopsize, samplerate); -} - -inline bool Spear_parser::parseFile(char *filename, int hopsize, int samplerate) -{ - return parser(filename, hopsize, samplerate); -} - -inline void Spear_parser::calculateDeltaTime() -{ - deltaTime = (double)hopSize/ (double)fileSampleRate; -} - -// each time value in the file is rounded, and 2 consecutive frames can differ of a time gap = i*deltaTime, where i is a positive integer -inline int Spear_parser::fromTimeToSamples(float time) -{ - return round(time/deltaTime)*hopSize; // round is necessary since in the file log time values are rounded, so they do not apparently look like integer multiples of deltaTime -} - -inline int Spear_parser::getHopSize() -{ - return hopSize; -} - -inline int Spear_parser::getFileSampleRate() -{ - return fileSampleRate; -} - -inline double Spear_parser::getDeltaTime() -{ - return deltaTime; -} - -#endif /* SPEAR_PARSER_H_ */
--- a/examples/filter_FIR/FIRfilter.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * FIRfilter.h - * - * Created on: Aug 5, 2014 - * Author: Victor Zappi and Andrew McPherson - */ - -#ifndef FIRFILTER_H_ -#define FIRFILTER_H_ - - -#include <ne10/NE10.h> - -#define FILTER_TAP_NUM 31 - -// Coefficients for FIR High Pass Filter at 3 KHz -ne10_float32_t filterTaps[FILTER_TAP_NUM] = { - -0.000055, - 0.000318, - 0.001401, - 0.003333, - 0.005827, - 0.007995, - 0.008335, - 0.004991, - -0.003764, - -0.018906, - -0.040112, - -0.065486, - -0.091722, - -0.114710, - -0.130454, - 0.863946, - -0.130454, - -0.114710, - -0.091722, - -0.065486, - -0.040112, - -0.018906, - -0.003764, - 0.004991, - 0.008335, - 0.007995, - 0.005827, - 0.003333, - 0.001401, - 0.000318, - -0.000055 -}; - -#endif /* FIRFILTER_H_ */
--- a/examples/filter_FIR/SampleData.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* - * SampleData.h - * - * Created on: Nov 5, 2014 - * Author: Victor Zappi - */ - -#ifndef SAMPLEDATA_H_ -#define SAMPLEDATA_H_ - -// User defined structure to pass between main and rendere complex data retrieved from file -struct SampleData { - float *samples; // Samples in file - int sampleLen; // Total nume of samples -}; - - - -#endif /* SAMPLEDATA_H_ */
--- a/examples/filter_FIR/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,180 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: Andrew McPherson and Victor Zappi - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <string> -#include <getopt.h> -#include <sndfile.h> // to load audio files - -#include <Bela.h> -#include "SampleData.h" - -using namespace std; - -// Load samples from file -int initFile(string file, SampleData *smp)//float *& smp) -{ - SNDFILE *sndfile ; - SF_INFO sfinfo ; - - if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { - cout << "Couldn't open file " << file << endl; - return 1; - } - - int numChan = sfinfo.channels; - if(numChan != 1) - { - cout << "Error: " << file << " is not a mono file" << endl; - return 1; - } - - smp->sampleLen = sfinfo.frames * numChan; - smp->samples = new float[smp->sampleLen]; - if(smp == NULL){ - cout << "Could not allocate buffer" << endl; - return 1; - } - - int subformat = sfinfo.format & SF_FORMAT_SUBMASK; - int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); - - // Pad with zeros in case we couldn't read whole file - for(int k = readcount; k <smp->sampleLen; k++) - smp->samples[k] = 0; - - if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { - double scale ; - int m ; - - sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; - if (scale < 1e-10) - scale = 1.0 ; - else - scale = 32700.0 / scale ; - cout << "File samples scale = " << scale << endl; - - for (m = 0; m < smp->sampleLen; m++) - smp->samples[m] *= scale; - } - - sf_close(sndfile); - - return 0; -} - - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - //rt_task_delete ((RT_TASK *) &gTriggerSamplesTask); - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --file [-f] filename: Name of the file to load (default is \"longsample.wav\")\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - string fileName; // Name of the sample to load - - SampleData sampleData; // User define structure to pass data retrieved from file to render function - sampleData.samples = 0; - sampleData.sampleLen = -1; - - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"file", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - fileName = string((char *)optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - if(fileName.empty()){ - fileName = "filter/longsample.wav"; - } - - if(settings.verbose) { - cout << "Loading file " << fileName << endl; - } - - // Load file - if(initFile(fileName, &sampleData) != 0) - { - cout << "Error: unable to load samples " << endl; - return -1; - } - - if(settings.verbose) - cout << "File contains " << sampleData.sampleLen << " samples" << endl; - - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &sampleData) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -} -
--- a/examples/filter_FIR/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,180 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - -*/ - -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: Andrew McPherson and Victor Zappi - */ - -/** -\example 4_filter_FIR - -Finite Impulse Response Filter ------------------------------- - -This is an example of a finite impulse response filter implementation. -*/ - -#define ENABLE_NE10_FIR_FLOAT_NEON // Define needed for Ne10 library - -#include <Bela.h> -#include <cmath> -#include <ne10/NE10.h> // neon library -#include "SampleData.h" -#include "FIRfilter.h" - -SampleData gSampleData; // User defined structure to get complex data from main -int gReadPtr; // Position of last read sample from file - -// filter vars -ne10_fir_instance_f32_t gFIRfilter; -ne10_float32_t *gFIRfilterIn; -ne10_float32_t *gFIRfilterOut; -ne10_uint32_t blockSize; -ne10_float32_t *gFIRfilterState; - -void initialise_filter(BelaContext *context); - -// Task for handling the update of the frequencies using the matrix -AuxiliaryTask gTriggerSamplesTask; - -bool initialise_trigger(); -void trigger_samples(); - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - - // Retrieve a parameter passed in from the initAudio() call - gSampleData = *(SampleData *)userData; - - gReadPtr = -1; - - initialise_filter(context); - - // Initialise auxiliary tasks - if(!initialise_trigger()) - return false; - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - float in = 0; - - // If triggered... - if(gReadPtr != -1) - in += gSampleData.samples[gReadPtr++]; // ...read each sample... - - if(gReadPtr >= gSampleData.sampleLen) - gReadPtr = -1; - - gFIRfilterIn[n] = in; - } - - ne10_fir_float_neon(&gFIRfilter, gFIRfilterIn, gFIRfilterOut, blockSize); - - for(unsigned int n = 0; n < context->audioFrames; n++) { - for(unsigned int channel = 0; channel < context->audioChannels; channel++) - context->audioOut[n * context->audioChannels + channel] = gFIRfilterOut[n]; // ...and put it in both left and right channel - } - - - // Request that the lower-priority task run at next opportunity - Bela_scheduleAuxiliaryTask(gTriggerSamplesTask); -} - -// Initialise NE10 data structures to define FIR filter - -void initialise_filter(BelaContext *context) -{ - blockSize = context->audioFrames; - gFIRfilterState = (ne10_float32_t *) NE10_MALLOC ((FILTER_TAP_NUM+blockSize-1) * sizeof (ne10_float32_t)); - gFIRfilterIn = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); - gFIRfilterOut = (ne10_float32_t *) NE10_MALLOC (blockSize * sizeof (ne10_float32_t)); - ne10_fir_init_float(&gFIRfilter, FILTER_TAP_NUM, filterTaps, gFIRfilterState, blockSize); -} - - -// Initialise the auxiliary task -// and print info - -bool initialise_trigger() -{ - if((gTriggerSamplesTask = Bela_createAuxiliaryTask(&trigger_samples, 50, "bela-trigger-samples")) == 0) - return false; - - rt_printf("Press 'a' to trigger sample, 's' to stop\n"); - rt_printf("Press 'q' to quit\n"); - - return true; -} - -// This is a lower-priority call to periodically read keyboard input -// and trigger samples. By placing it at a lower priority, -// it has minimal effect on the audio performance but it will take longer to -// complete if the system is under heavy audio load. - -void trigger_samples() -{ - // This is not a real-time task! - // Cos getchar is a system call, not handled by Xenomai. - // This task will be automatically down graded. - - char keyStroke = '.'; - - keyStroke = getchar(); - while(getchar()!='\n'); // to read the first stroke - - switch (keyStroke) - { - case 'a': - gReadPtr = 0; - break; - case 's': - gReadPtr = -1; - break; - case 'q': - gShouldStop = true; - break; - default: - break; - } -} - - - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - delete[] gSampleData.samples; - - NE10_FREE(gFIRfilterState); - NE10_FREE(gFIRfilterIn); - NE10_FREE(gFIRfilterOut); -}
--- a/examples/filter_IIR/SampleData.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* - * SampleData.h - * - * Created on: Nov 5, 2014 - * Author: Victor Zappi - */ - -#ifndef SAMPLEDATA_H_ -#define SAMPLEDATA_H_ - -// User defined structure to pass between main and rendere complex data retrieved from file -struct SampleData { - float *samples; // Samples in file - int sampleLen; // Total nume of samples -}; - - - -#endif /* SAMPLEDATA_H_ */
--- a/examples/filter_IIR/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: Andrew McPherson and Victor Zappi - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <string> -#include <getopt.h> -#include <sndfile.h> // to load audio files - -#include <Bela.h> -#include "SampleData.h" - -using namespace std; - -float gCutFreq = 100; - -// Load samples from file -int initFile(string file, SampleData *smp)//float *& smp) -{ - SNDFILE *sndfile ; - SF_INFO sfinfo ; - - if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { - cout << "Couldn't open file " << file << endl; - return 1; - } - - int numChan = sfinfo.channels; - if(numChan != 1) - { - cout << "Error: " << file << " is not a mono file" << endl; - return 1; - } - - smp->sampleLen = sfinfo.frames * numChan; - smp->samples = new float[smp->sampleLen]; - if(smp == NULL){ - cout << "Could not allocate buffer" << endl; - return 1; - } - - int subformat = sfinfo.format & SF_FORMAT_SUBMASK; - int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); - - // Pad with zeros in case we couldn't read whole file - for(int k = readcount; k <smp->sampleLen; k++) - smp->samples[k] = 0; - - if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { - double scale ; - int m ; - - sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; - if (scale < 1e-10) - scale = 1.0 ; - else - scale = 32700.0 / scale ; - cout << "File samples scale = " << scale << endl; - - for (m = 0; m < smp->sampleLen; m++) - smp->samples[m] *= scale; - } - - sf_close(sndfile); - - return 0; -} - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - //rt_task_delete ((RT_TASK *) &gTriggerSamplesTask); - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --file [-f] filename: Name of the file to load (default is \"longsample.wav\")\n"; - cerr << " --cutfreq [-c] freq: Set the cut off frequency of the filter in Hz\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - string fileName; // Name of the sample to load - - SampleData sampleData; // User define structure to pass data retrieved from file to render function - sampleData.samples = 0; - sampleData.sampleLen = -1; - - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"cutfreq", 1, NULL, 'c'}, - {"file", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:c:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - fileName = string((char *)optarg); - break; - case 'c': - gCutFreq = atof(optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - if(fileName.empty()){ - fileName = "filter/longsample.wav"; - } - - if(settings.verbose) { - cout << "Loading file " << fileName << endl; - } - - // Load file - if(initFile(fileName, &sampleData) != 0) - { - cout << "Error: unable to load samples " << endl; - return -1; - } - - if(settings.verbose) - cout << "File contains " << sampleData.sampleLen << " samples" << endl; - - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &sampleData) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -} -
--- a/examples/filter_IIR/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - -*/ - -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: Andrew McPherson and Victor Zappi - */ - -/** -\example 4_filter_IIR - -Infinite Impulse Response Filter ------------------------------- - -This is an example of a infinite impulse response filter implementation. -*/ - -#include <Bela.h> // to schedule lower prio parallel process -#include <rtdk.h> -#include <cmath> -#include <stdio.h> -#include "SampleData.h" - -SampleData gSampleData; // User defined structure to get complex data from main -int gReadPtr; // Position of last read sample from file - -// filter vars -float gLastX[2]; -float gLastY[2]; -double lb0, lb1, lb2, la1, la2 = 0.0; - -// communication vars between the 2 auxiliary tasks -int gChangeCoeff = 0; -int gFreqDelta = 0; - -void initialise_filter(float freq); - -void calculate_coeff(float cutFreq); - -bool initialise_aux_tasks(); - -// Task for handling the update of the frequencies using the matrix -AuxiliaryTask gChangeCoeffTask; - -void check_coeff(); - -// Task for handling the update of the frequencies using the matrix -AuxiliaryTask gInputTask; - -void read_input(); - - -extern float gCutFreq; - - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - - // Retrieve a parameter passed in from the initAudio() call - gSampleData = *(SampleData *)userData; - - gReadPtr = -1; - - initialise_filter(200); - - // Initialise auxiliary tasks - if(!initialise_aux_tasks()) - return false; - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - float sample = 0; - float out = 0; - - // If triggered... - if(gReadPtr != -1) - sample += gSampleData.samples[gReadPtr++]; // ...read each sample... - - if(gReadPtr >= gSampleData.sampleLen) - gReadPtr = -1; - - out = lb0*sample+lb1*gLastX[0]+lb2*gLastX[1]-la1*gLastY[0]-la2*gLastY[1]; - - gLastX[1] = gLastX[0]; - gLastX[0] = out; - gLastY[1] = gLastY[0]; - gLastY[0] = out; - - for(unsigned int channel = 0; channel < context->audioChannels; channel++) - context->audioOut[n * context->audioChannels + channel] = out; // ...and put it in both left and right channel - - } - - // Request that the lower-priority tasks run at next opportunity - Bela_scheduleAuxiliaryTask(gChangeCoeffTask); - Bela_scheduleAuxiliaryTask(gInputTask); -} - -// First calculation of coefficients - -void initialise_filter(float freq) -{ - calculate_coeff(freq); -} - - -// Calculate the filter coefficients -// second order low pass butterworth filter - -void calculate_coeff(float cutFreq) -{ - // Initialise any previous state (clearing buffers etc.) - // to prepare for calls to render() - float sampleRate = 44100; - double f = 2*M_PI*cutFreq/sampleRate; - double denom = 4+2*sqrt(2)*f+f*f; - lb0 = f*f/denom; - lb1 = 2*lb0; - lb2 = lb0; - la1 = (2*f*f-8)/denom; - la2 = (f*f+4-2*sqrt(2)*f)/denom; - gLastX[0] = gLastX [1] = 0; - gLastY[0] = gLastY[1] = 0; - -} - - -// Initialise the auxiliary tasks -// and print info - -bool initialise_aux_tasks() -{ - if((gChangeCoeffTask = Bela_createAuxiliaryTask(&check_coeff, 90, "bela-check-coeff")) == 0) - return false; - - if((gInputTask = Bela_createAuxiliaryTask(&read_input, 50, "bela-read-input")) == 0) - return false; - - rt_printf("Press 'a' to trigger sample, 's' to stop\n"); - rt_printf("Press 'z' to low down cut-off freq of 100 Hz, 'x' to raise it up\n"); - rt_printf("Press 'q' to quit\n"); - - return true; -} - -// Check if cut-off freq has been changed -// and new coefficients are needed - -void check_coeff() -{ - if(gChangeCoeff == 1) - { - gCutFreq += gFreqDelta; - gCutFreq = gCutFreq < 0 ? 0 : gCutFreq; - gCutFreq = gCutFreq > 22050 ? 22050 : gCutFreq; - - rt_printf("Cut-off frequency: %f\n", gCutFreq); - - calculate_coeff(gCutFreq); - gChangeCoeff = 0; - } -} - -// This is a lower-priority call to periodically read keyboard input -// and trigger samples. By placing it at a lower priority, -// it has minimal effect on the audio performance but it will take longer to -// complete if the system is under heavy audio load. - -void read_input() -{ - // This is not a real-time task! - // Cos getchar is a system call, not handled by Xenomai. - // This task will be automatically down graded. - - char keyStroke = '.'; - - keyStroke = getchar(); - while(getchar()!='\n'); // to read the first stroke - - switch (keyStroke) - { - case 'a': - gReadPtr = 0; - break; - case 's': - gReadPtr = -1; - break; - case 'z': - gChangeCoeff = 1; - gFreqDelta = -100; - break; - case 'x': - gChangeCoeff = 1; - gFreqDelta = 100; - break; - case 'q': - gShouldStop = true; - break; - default: - break; - } -} - - - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - delete[] gSampleData.samples; -}
--- a/examples/gpioAnalogLoopbackTest/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,209 +0,0 @@ -#include <Bela.h> -#include <cmath> -#include <rtdk.h> -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> -#include <stats.hpp> -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - - -// digital inputs can be changed at will (as they are all being processed at the same time) -// analog channels must be as per below -int gAnalogOutCh = 1; -int gDigitalOutCh = 2; -int gDigitalInACh = 0; -int gDigitalInDCh = 3; -int gAnalogOutLoopDelay; -int gDigitalOutLoopDelay; -bool setup(BelaContext *context, void *userData) -{ - rt_printf("For this test you need the following connections:\n" - "analog%d out->digital%d in, analog%d out->analog%d in, " - "digital%d out -> digital%d in, digital%d out-> analog%d in\n", - gAnalogOutCh, gDigitalInACh, gAnalogOutCh, 0, gDigitalOutCh, gDigitalInDCh, gDigitalOutCh, 0); - rt_printf("Running test with %d analog channels and a buffer size of %d\n", - context->analogChannels, context->audioFrames); - - for(unsigned int n = 0; n < context->digitalFrames; n++){ - pinMode(context, n, gDigitalInACh, INPUT); - pinMode(context, n, gDigitalInDCh, INPUT); - pinMode(context, n, gDigitalOutCh, OUTPUT); - } - switch (context->analogChannels){ - case 2: - gAnalogOutLoopDelay = context->audioFrames*2 + 3; - gDigitalOutLoopDelay = context->audioFrames*2 + 2; - break; - case 4: - gAnalogOutLoopDelay = context->audioFrames*2 + 3; - gDigitalOutLoopDelay = context->audioFrames*2 + 2; - break; - case 8: - gAnalogOutLoopDelay = context->audioFrames + 3; - gDigitalOutLoopDelay = context->audioFrames + 1; - break; - default: - exit(2); - } - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numAnalogFrames -// will be 0. - -const int patternLength = 31; -static int anaErrorCount = 0; -static int digErrorCount = 0; -void render(BelaContext *context, void *userData) -{ - static bool writePattern[patternLength] = { - 0,1,0,1,0,0,1,1, - 0,0,0,1,1,1,0,0, - 1,1,1,1,0,0,0,0, - 1,1,1,1,1,0,0}; -// for(int n = 0; n < patternLength; n++){ -// writePattern[n]=1; -// } - static int inPointer = 0; - static int outPointer = 0; - static int digitalOutPointer = 0; - static int digitalInPointer = 0; - static int analogOut = 1; - /** Checking offset between analog and digital - * how it should be : - * The PRU loop does the following (the loop runs at 88.2kHz): - * - Read/write audio sample (once for the left channel, once for the right channel) - * - Write DAC 0 or 0/2 or 0/2/4/6 - * - Read ADC 0 or 0/2 or 0/2/4/6, 2 samples (@176.4) older than NOW - * - /During/ the line above, every two loops we also Read/Write GPIO, - * therefore reading on ADC 0/2/4/6 a value that is being output from GPIO will lead to undefined results - * - Write DAC 1 or 1/3 or 1/3/5/7 - * - Read ADC 1 or 1/3 or 1/3/5/7, 2 samples (@176.4) older than NOW - */ - if(1) - for(unsigned int n = 0; n < context->audioFrames; n++){ - static bool analog0In = false; - static bool digitalAIn = false; - static int count = 0; - bool doReadWrite = context->analogChannels<=4 ? true : ((context->analogChannels == 8) && (n&1)==0); - if(doReadWrite){ - digitalAIn = digitalRead(context, n, gDigitalInACh); - switch(context->analogChannels){ - case 8: - analog0In = analogRead(context, n/2, 0) > 0.5; - analogWrite(context, n/2, analogOut, writePattern[outPointer]); - break; - case 4: - analog0In = analogRead(context, n, 0) > 0.5; - analogWrite(context, n, analogOut, writePattern[outPointer]); - break; - case 2: - analog0In = analogRead(context, n * 2 + 1, 0) > 0.5; - analogWrite(context, 2 * n, analogOut, writePattern[outPointer]); - analogWrite(context, 2 * n + 1, analogOut, writePattern[outPointer]); - break; - } - gAnalogOutLoopDelay--; - outPointer++; - if(gAnalogOutLoopDelay <= 0){ - if(++inPointer == patternLength){ - inPointer = 0; - } - } - } - bool expectedIn = writePattern[inPointer]; - if(gAnalogOutLoopDelay <= 0 && doReadWrite == true){ - if(analog0In != expectedIn || digitalAIn != expectedIn){ - rt_printf("expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n", - expectedIn, analog0In, digitalAIn, inPointer, gAnalogOutLoopDelay, count); - anaErrorCount++; - } - } - count++; - if(analog0In != digitalAIn){ // at any time the analog and digital in should be the same - rt_printf("ana %d_%d %d,\n", analog0In, digitalAIn, n); - } - if(outPointer == patternLength){ - outPointer = 0; - } - } - if(1) - for(unsigned int n = 0; n < context->audioFrames; n++){ - static int count = 0; - static bool analog1In = false; - static bool digitalDIn = false; -/* we need to remember the pastAnalog1In because - * reading GPIO takes place before writing to it, therefore - * when reading a GPIOout, the GPIOin samples will always be one sample late - */ - bool doReadWrite = false; - static bool pastAnalog1In = false; - digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); - if(context->analogChannels == 8){ - if((n&1) == 0){ //do it every other sample - pastAnalog1In = analogRead(context, n/2, 1) > 0.5; - digitalDIn = digitalRead(context, n, gDigitalInDCh); - doReadWrite = true; - } - } - if(context->analogChannels == 4){ - pastAnalog1In = analogRead(context, n, 1) > 0.5; - digitalDIn = digitalRead(context, n, gDigitalInDCh); - digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); - doReadWrite = true; - } - if(context->analogChannels == 2){ - pastAnalog1In = analogRead(context, n * 2, 1) > 0.5; - digitalDIn = digitalRead(context, n, gDigitalInDCh); - digitalWriteOnce(context, n, gDigitalOutCh, writePattern[digitalOutPointer]); - doReadWrite = true; - } - bool expectedDigitalIn = writePattern[digitalInPointer]; - if(doReadWrite == true){ - gDigitalOutLoopDelay--; - if(gDigitalOutLoopDelay <= 0){ - if(expectedDigitalIn != pastAnalog1In || expectedDigitalIn != digitalDIn){ - rt_printf("D expected: %d, received: %d %d, pointer: %d, delay: %d, count: %d\n", - expectedDigitalIn, pastAnalog1In, digitalDIn, inPointer, gDigitalOutLoopDelay, count); - digErrorCount++; - } - if(++digitalInPointer == patternLength){ - digitalInPointer = 0; - } - } - pastAnalog1In = analog1In; - if(++digitalOutPointer == patternLength){ - digitalOutPointer = 0; - } - } - count++; - } - if(context->audioFramesElapsed > 30000){ - gShouldStop = true; - } -} - - -void cleanup(BelaContext *context, void *userData) -{ - if(anaErrorCount == 0 && digErrorCount == 0){ - rt_printf("Test was succesful with %d analog channels and a buffer size of %d\n", context->analogChannels, context->audioFrames); - } else { - rt_printf("------------------------\n%danalog %ddigital errors over %dsamples while running test with ", - anaErrorCount, digErrorCount, context->audioFramesElapsed); - rt_printf("%d analog channels and a buffer size of %d \n\n\n", - context->analogChannels, context->audioFrames); - exit(1); - } -}
--- a/examples/level_meter/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - - -#include <Bela.h> -#include <cmath> - -#define NUMBER_OF_SEGMENTS 10 - -// Two levels of audio: one follows current value, the other holds -// peaks for longer -float gAudioLocalLevel = 0, gAudioPeakLevel = 0; - -// Decay rates for detecting levels -float gLocalDecayRate = 0.99, gPeakDecayRate = 0.999; - -// Thresholds for LEDs: set in setup() -float gThresholds[NUMBER_OF_SEGMENTS + 1]; -int gSamplesToLight[NUMBER_OF_SEGMENTS]; - -// High-pass filter on the input -float gLastX[2] = {0}; -float gLastY[2] = {0}; - -// These coefficients make a high-pass filter at 5Hz for 44.1kHz sample rate -double gB0 = 0.99949640; -double gB1 = -1.99899280; -double gB2 = gB0; -double gA1 = -1.99899254; -double gA2 = 0.99899305; - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - // This project makes the assumption that the audio and digital - // sample rates are the same. But check it to be sure! - if(context->audioFrames != context->digitalFrames) { - rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n"); - return false; - } - - // Initialise threshold levels in -3dB steps. One extra for efficiency in render() - // Level = 10^(dB/20) - for(int i = 0; i < NUMBER_OF_SEGMENTS + 1; i++) { - gThresholds[i] = powf(10.0f, (-1.0 * (NUMBER_OF_SEGMENTS - i)) * .05); - } - - for(int i = 0; i < NUMBER_OF_SEGMENTS; i++) { - gSamplesToLight[i] = 0; - pinMode(context, 0, i, OUTPUT); - } - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - // Get average of audio input channels - float sample = 0; - for(unsigned int ch = 0; ch < context->audioChannels; ch++) { - context->audioOut[n * context->audioChannels + ch] = - context->audioIn[n * context->audioChannels + ch]; - sample += context->audioIn[n * context->audioChannels + ch]; - } - - // Do DC-blocking on the sum - float out = gB0 * sample + gB1 * gLastX[0] + gB2 * gLastX[1] - - gA1 * gLastY[0] - gA2 * gLastY[1]; - - gLastX[1] = gLastX[0]; - gLastX[0] = sample; - gLastY[1] = gLastY[0]; - gLastY[0] = out; - - out = fabsf(out / (float)context->audioChannels); - - // Do peak detection: fast-responding local level - if(out > gAudioLocalLevel) - gAudioLocalLevel = out; - else - gAudioLocalLevel *= gLocalDecayRate; - - // Do peak detection: slow-responding peak level - if(out > gAudioPeakLevel) - gAudioPeakLevel = out; - else { - // Make peak decay slowly by only multiplying - // every few samples - if(((context->audioFramesElapsed + n) & 31) == 0) - gAudioPeakLevel *= gPeakDecayRate; - } - // LED bargraph on digital outputs 0-9 - for(int led = 0; led < NUMBER_OF_SEGMENTS; led++) { - // All LEDs up to the local level light up. The LED - // for the peak level also remains lit. - int state = LOW; - - if(gAudioLocalLevel > gThresholds[led]) { - state = HIGH; - gSamplesToLight[led] = 1000; - } - /*else if(gAudioPeakLevel > gThresholds[led] && gAudioPeakLevel <= gThresholds[led + 1]) { - state = HIGH; - gSamplesToLight[led] = 1000; - }*/ - else if(--gSamplesToLight[led] > 0) - state = HIGH; - - // Write LED - digitalWriteOnce(context, n, led, state); - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/loggingSensors/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ -#include <unistd.h> -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --frequency [-f] frequency: Set the frequency of the oscillator\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - float frequency = 440.0; // Frequency of oscillator - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"frequency", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - frequency = atof(optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &frequency) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/loggingSensors/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -#include <Bela.h> -#include <cmath> -#include <WriteFile.h> - -WriteFile file1; -WriteFile file2; - -bool setup(BelaContext *context, void *userData) -{ - file1.init("out.bin"); //set the file name to write to - file1.setEchoInterval(1000); - file1.setFileType(kBinary); - file1.setFormat("%.4f %.4f\n"); // set the format that you want to use for your output. Please use %f only (with modifiers). When in binary mode, this is used only for echoing to console - file2.init("out.m"); //set the file name to write to - file2.setHeader("myvar=[\n"); //set one or more lines to be printed at the beginning of the file - file2.setFooter("];\n"); //set one or more lines to be printed at the end of the file - file2.setFormat("%.4f\n"); // set the format that you want to use for your output. Please use %f only (with modifiers) - file2.setFileType(kText); - file2.setEchoInterval(10000); // only print to the console 1 line every other 10000 - return true; -} - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->analogFrames; n++) { - file1.log(&(context->analogIn[n*context->analogFrames]), 2); // log an array of values - file2.log(context->analogIn[n*context->analogFrames]); // log a single value - } -} - -// cleanup_render() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in initialise_render(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/measure_noisefloor/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -extern int gBufferSize; - -using namespace std; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --buffer-size [-b] size Set the analysis buffer size\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"buffer-size", 1, NULL, 'b'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // By default use a longer period size because latency is not an issue - settings.periodSize = 32; - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hb:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'b': - gBufferSize = atoi(optarg); - break; - case 'h': - usage(basename(argv[0])); - exit(0); - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - if(gBufferSize < settings.periodSize) - gBufferSize = settings.periodSize; - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, 0) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/measure_noisefloor/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - - -#include <Bela.h> -#include <cmath> - -int gBufferSize = 8192; - -// Double buffers to hold samples for noise analysis -float *gReadBuffers[10], *gWriteBuffers[10]; -float *gBuffers0[10], *gBuffers1[10]; - -int gWriteBufferPointers[10], gReadBufferPointers[10]; - -// Task to analyse and print results which would otherwise be too slow for render() -AuxiliaryTask gAnalysisTask; - -void analyseResults(); - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - // Clear the filter data structures - for(int i = 0; i < 10; i++) { - gReadBufferPointers[i] = gWriteBufferPointers[i] = 0; - gBuffers0[i] = new float[gBufferSize]; - gBuffers1[i] = new float[gBufferSize]; - gWriteBuffers[i] = gBuffers0[i]; - gReadBuffers[i] = gBuffers1[i]; - if(gBuffers0[i] == 0 || gBuffers1[i] == 0) { - rt_printf("Error allocating buffer %d\n", i); - return false; - } - } - - gAnalysisTask = Bela_createAuxiliaryTask(analyseResults, 50, "bela-analyse-results"); - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - bool bufferIsFull = false; // Whether at least one buffer has filled - - for(unsigned int n = 0; n < context->audioFrames; n++) { - // Store audio inputs in buffer - for(unsigned int ch = 0; ch < context->audioChannels; ch++) { - if(gWriteBufferPointers[ch] < gBufferSize) { - gWriteBuffers[ch][gWriteBufferPointers[ch]] = - context->audioIn[n * context->audioChannels + ch]; - gWriteBufferPointers[ch]++; - if(gWriteBufferPointers[ch] >= gBufferSize) - bufferIsFull = true; - } - } - } - - if(context->analogChannels != 0) { - for(unsigned int n = 0; n < context->analogFrames; n++) { - // Store analog inputs in buffer, starting at channel 2 - for(unsigned int ch = 0; ch < context->analogChannels; ch++) { - if(gWriteBufferPointers[ch + 2] < gBufferSize) { - gWriteBuffers[ch + 2][gWriteBufferPointers[ch + 2]] = - context->analogIn[n * context->analogChannels + ch]; - gWriteBufferPointers[ch + 2]++; - if(gWriteBufferPointers[ch + 2] >= gBufferSize) - bufferIsFull = true; - } - - // Set all analog outputs to halfway point so they can be more - // easily measured for noise - context->analogOut[n * context->analogChannels + ch] = 0.5; - } - } - } - - - if(bufferIsFull) { - // Swap buffers and reset write pointers - for(int ch = 0; ch < 10; ch++) { - gReadBufferPointers[ch] = gWriteBufferPointers[ch]; - gWriteBufferPointers[ch] = 0; - - if(gReadBuffers[ch] == gBuffers0[ch]) { - gReadBuffers[ch] = gBuffers1[ch]; - gWriteBuffers[ch] = gBuffers0[ch]; - } - else { - gReadBuffers[ch] = gBuffers0[ch]; - gWriteBuffers[ch] = gBuffers1[ch]; - } - } - - Bela_scheduleAuxiliaryTask(gAnalysisTask); - } -} - -void analyseResults() -{ - rt_printf("\e[1;1H\e[2J"); // Command to clear the screen - - // Print the analysis results. channels 0-1 are audio, channels 2-9 are analog - for(int ch = 0; ch < 10; ch++) { - // Skip unused channels - if(gReadBufferPointers[ch] == 0) - continue; - - float mean = 0; - for(int n = 0; n < gReadBufferPointers[ch]; n++) { - mean += gReadBuffers[ch][n]; - } - mean /= (float)gReadBufferPointers[ch]; - - float rms = 0; - for(int n = 0; n < gReadBufferPointers[ch]; n++) { - rms += (gReadBuffers[ch][n] - mean) * (gReadBuffers[ch][n] - mean); - } - rms = sqrtf(rms / (float)gReadBufferPointers[ch]); - - if(ch == 0) - rt_printf("Audio In L: "); - else if(ch == 1) - rt_printf("Audio In R: "); - else - rt_printf("Analog In %d: ", ch - 2); - - rt_printf("Noise %6.1fdB DC offset %6.4f (%6.1fdB) window size: %d\n", - 20.0f * log10f(rms), - mean, - 20.0f * log10f(fabsf(mean)), - gReadBufferPointers[ch]); - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - for(int i = 0; i < 10; i++) { - delete gBuffers0[i]; - delete gBuffers1[i]; - } -}
--- a/examples/minimal/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -#include <Bela.h> - -bool setup(BelaContext *context, void *userData) -{ - return true; -} - -void render(BelaContext *context, void *userData) -{ - -} - -void cleanup(BelaContext *context, void *userData) -{ - -} \ No newline at end of file
--- a/examples/mpr121/I2C_MPR121.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - * I2C_MPR121.cpp - * - * Created on: Oct 14, 2013 - * Author: Victor Zappi - */ - - -#include "I2C_MPR121.h" - -I2C_MPR121::I2C_MPR121() { - -} - -boolean I2C_MPR121::begin(uint8_t bus, uint8_t i2caddr) { - _i2c_address = i2caddr; - - if(initI2C_RW(bus, i2caddr, 0) > 0) - return false; - - // soft reset - writeRegister(MPR121_SOFTRESET, 0x63); - usleep(1000); - //delay(1); - for (uint8_t i=0; i<0x7F; i++) { - // Serial.print("$"); Serial.print(i, HEX); - // Serial.print(": 0x"); Serial.println(readRegister8(i)); - } - - - writeRegister(MPR121_ECR, 0x0); - - uint8_t c = readRegister8(MPR121_CONFIG2); - - if (c != 0x24) { - rt_printf("MPR121 read 0x%x instead of 0x24\n", c); - return false; - } - - setThresholds(12, 6); - writeRegister(MPR121_MHDR, 0x01); - writeRegister(MPR121_NHDR, 0x01); - writeRegister(MPR121_NCLR, 0x0E); - writeRegister(MPR121_FDLR, 0x00); - - writeRegister(MPR121_MHDF, 0x01); - writeRegister(MPR121_NHDF, 0x05); - writeRegister(MPR121_NCLF, 0x01); - writeRegister(MPR121_FDLF, 0x00); - - writeRegister(MPR121_NHDT, 0x00); - writeRegister(MPR121_NCLT, 0x00); - writeRegister(MPR121_FDLT, 0x00); - - writeRegister(MPR121_DEBOUNCE, 0); - writeRegister(MPR121_CONFIG1, 0x10); // default, 16uA charge current - writeRegister(MPR121_CONFIG2, 0x20); // 0.5uS encoding, 1ms period - -// writeRegister(MPR121_AUTOCONFIG0, 0x8F); - -// writeRegister(MPR121_UPLIMIT, 150); -// writeRegister(MPR121_TARGETLIMIT, 100); // should be ~400 (100 shifted) -// writeRegister(MPR121_LOWLIMIT, 50); - // enable all electrodes - writeRegister(MPR121_ECR, 0x8F); // start with first 5 bits of baseline tracking - - return true; -} - -void I2C_MPR121::setThresholds(uint8_t touch, uint8_t release) { - for (uint8_t i=0; i<12; i++) { - writeRegister(MPR121_TOUCHTH_0 + 2*i, touch); - writeRegister(MPR121_RELEASETH_0 + 2*i, release); - } -} - -uint16_t I2C_MPR121::filteredData(uint8_t t) { - if (t > 12) return 0; - return readRegister16(MPR121_FILTDATA_0L + t*2); -} - -uint16_t I2C_MPR121::baselineData(uint8_t t) { - if (t > 12) return 0; - uint16_t bl = readRegister8(MPR121_BASELINE_0 + t); - return (bl << 2); -} - -uint16_t I2C_MPR121::touched(void) { - uint16_t t = readRegister16(MPR121_TOUCHSTATUS_L); - return t & 0x0FFF; -} - -/*********************************************************************/ - - -uint8_t I2C_MPR121::readRegister8(uint8_t reg) { - unsigned char inbuf, outbuf; - struct i2c_rdwr_ioctl_data packets; - struct i2c_msg messages[2]; - - /* - * In order to read a register, we first do a "dummy write" by writing - * 0 bytes to the register we want to read from. This is similar to - * the packet in set_i2c_register, except it's 1 byte rather than 2. - */ - outbuf = reg; - messages[0].addr = 0x5A; - messages[0].flags = 0; - messages[0].len = sizeof(outbuf); - messages[0].buf = &outbuf; - - /* The data will get returned in this structure */ - messages[1].addr = 0x5A; - messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/; - messages[1].len = sizeof(inbuf); - messages[1].buf = &inbuf; - - /* Send the request to the kernel and get the result back */ - packets.msgs = messages; - packets.nmsgs = 2; - if(ioctl(i2C_file, I2C_RDWR, &packets) < 0) { - rt_printf("Unable to send data"); - return 0; - } - - return inbuf; -} - -uint16_t I2C_MPR121::readRegister16(uint8_t reg) { - unsigned char inbuf[2], outbuf; - struct i2c_rdwr_ioctl_data packets; - struct i2c_msg messages[2]; - - /* - * In order to read a register, we first do a "dummy write" by writing - * 0 bytes to the register we want to read from. This is similar to - * the packet in set_i2c_register, except it's 1 byte rather than 2. - */ - outbuf = reg; - messages[0].addr = _i2c_address; - messages[0].flags = 0; - messages[0].len = sizeof(outbuf); - messages[0].buf = &outbuf; - - /* The data will get returned in this structure */ - messages[1].addr = _i2c_address; - messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/; - messages[1].len = sizeof(inbuf); - messages[1].buf = inbuf; - - /* Send the request to the kernel and get the result back */ - packets.msgs = messages; - packets.nmsgs = 2; - if(ioctl(i2C_file, I2C_RDWR, &packets) < 0) { - rt_printf("Unable to send data"); - return 0; - } - - return (uint16_t)inbuf[0] | (((uint16_t)inbuf[1]) << 8); -} - -/**************************************************************************/ -/*! - @brief Writes 8-bits to the specified destination register -*/ -/**************************************************************************/ -void I2C_MPR121::writeRegister(uint8_t reg, uint8_t value) { - uint8_t buf[2] = { reg, value }; - - if(write(i2C_file, buf, 2) != 2) - { - cout << "Failed to write register " << (int)reg << " on MPR121\n"; - return; - } -} -
--- a/examples/mpr121/I2C_MPR121.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * MPR121 Bela demo - * - * Andrew McPherson - * Based on Adafruit library by Limor Fried/Ladyada - */ - -#ifndef I2CTK_H_ -#define I2CTK_H_ - -#include <I2c.h> -#include "Utilities.h" - -typedef bool boolean; - -#define MPR121_I2CADDR_DEFAULT 0x5A - -#define MPR121_TOUCHSTATUS_L 0x00 -#define MPR121_TOUCHSTATUS_H 0x01 -#define MPR121_FILTDATA_0L 0x04 -#define MPR121_FILTDATA_0H 0x05 -#define MPR121_BASELINE_0 0x1E -#define MPR121_MHDR 0x2B -#define MPR121_NHDR 0x2C -#define MPR121_NCLR 0x2D -#define MPR121_FDLR 0x2E -#define MPR121_MHDF 0x2F -#define MPR121_NHDF 0x30 -#define MPR121_NCLF 0x31 -#define MPR121_FDLF 0x32 -#define MPR121_NHDT 0x33 -#define MPR121_NCLT 0x34 -#define MPR121_FDLT 0x35 - -#define MPR121_TOUCHTH_0 0x41 -#define MPR121_RELEASETH_0 0x42 -#define MPR121_DEBOUNCE 0x5B -#define MPR121_CONFIG1 0x5C -#define MPR121_CONFIG2 0x5D -#define MPR121_CHARGECURR_0 0x5F -#define MPR121_CHARGETIME_1 0x6C -#define MPR121_ECR 0x5E -#define MPR121_AUTOCONFIG0 0x7B -#define MPR121_AUTOCONFIG1 0x7C -#define MPR121_UPLIMIT 0x7D -#define MPR121_LOWLIMIT 0x7E -#define MPR121_TARGETLIMIT 0x7F - -#define MPR121_GPIODIR 0x76 -#define MPR121_GPIOEN 0x77 -#define MPR121_GPIOSET 0x78 -#define MPR121_GPIOCLR 0x79 -#define MPR121_GPIOTOGGLE 0x7A - -#define MPR121_SOFTRESET 0x80 - -class I2C_MPR121 : public I2c -{ -public: - // Hardware I2C - I2C_MPR121(); - - boolean begin(uint8_t bus = 1, uint8_t i2caddr = MPR121_I2CADDR_DEFAULT); - - uint16_t filteredData(uint8_t t); - uint16_t baselineData(uint8_t t); - - uint8_t readRegister8(uint8_t reg); - uint16_t readRegister16(uint8_t reg); - void writeRegister(uint8_t reg, uint8_t value); - uint16_t touched(void); - - void setThresholds(uint8_t touch, uint8_t release); - - int readI2C() { return 0; } // Unused - -private: - int _i2c_address; -}; - - -#endif /* I2CTK_H_ */
--- a/examples/mpr121/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -#include <Bela.h> -#include <cmath> -#include <rtdk.h> -#include "I2C_MPR121.h" - -// How many pins there are -#define NUM_TOUCH_PINS 12 - -// Define this to print data to terminal -#undef DEBUG_MPR121 - -// Change this to change how often the MPR121 is read (in Hz) -int readInterval = 50; - -// Change this threshold to set the minimum amount of touch -int threshold = 40; - -// This array holds the continuous sensor values -int sensorValue[NUM_TOUCH_PINS]; - -// ---- test code stuff -- can be deleted for your example ---- - -// 12 notes of a C major scale... -float gFrequencies[NUM_TOUCH_PINS] = {261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25, 587.33, 659.25, 698.25, 783.99}; - -// This is internal stuff for the demo -float gNormFrequencies[NUM_TOUCH_PINS]; -float gPhases[NUM_TOUCH_PINS] = {0}; - -// ---- internal stuff -- do not change ----- - -I2C_MPR121 mpr121; // Object to handle MPR121 sensing -AuxiliaryTask i2cTask; // Auxiliary task to read I2C - -int readCount = 0; // How long until we read again... -int readIntervalSamples = 0; // How many samples between reads - -void readMPR121(); - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - if(!mpr121.begin(1, 0x5A)) { - rt_printf("Error initialising MPR121\n"); - return false; - } - - i2cTask = Bela_createAuxiliaryTask(readMPR121, 50, "bela-mpr121"); - readIntervalSamples = context->audioSampleRate / readInterval; - - for(int i = 0; i < NUM_TOUCH_PINS; i++) { - gNormFrequencies[i] = 2.0 * M_PI * gFrequencies[i] / context->audioSampleRate; - } - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numAnalogFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(int n = 0; n < context->audioFrames; n++) { - // Keep this code: it schedules the touch sensor readings - if(++readCount >= readIntervalSamples) { - readCount = 0; - Bela_scheduleAuxiliaryTask(i2cTask); - } - - float sample = 0.0; - - // This code can be replaced with your favourite audio code - for(int i = 0; i < NUM_TOUCH_PINS; i++) { - float amplitude = sensorValue[i] / 400.0; - - // Prevent clipping - if(amplitude > 0.5) - amplitude = 0.5; - - sample += amplitude * sinf(gPhases[i]); - gPhases[i] += gNormFrequencies[i]; - if(gPhases[i] > 2.0 * M_PI) - gPhases[i] -= 2.0 * M_PI; - } - - for(int ch = 0; ch < context->audioChannels; ch++) - context->audioOut[context->audioChannels * n + ch] = sample; - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - // Nothing to do here -} - - -// Auxiliary task to read the I2C board -void readMPR121() -{ - for(int i = 0; i < NUM_TOUCH_PINS; i++) { - sensorValue[i] = -(mpr121.filteredData(i) - mpr121.baselineData(i)); - sensorValue[i] -= threshold; - if(sensorValue[i] < 0) - sensorValue[i] = 0; -#ifdef DEBUG_MPR121 - rt_printf("%d ", sensorValue[i]); -#endif - } -#ifdef DEBUG_MPR121 - rt_printf("\n"); -#endif - - // You can use this to read binary on/off touch state more easily - //rt_printf("Touched: %x\n", mpr121.touched()); -}
--- a/examples/osc/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/** -\example 5_osc - -Open Sound Control ------------------- - -This example shows an implementation of OSC (Open Sound Control) which was -developed at UC Berkeley Center for New Music and Audio Technology (CNMAT). - -It is designed to be run alongside resources/osc/osc.js - -The OSC server port on which to receive is set in `setup()` -via `oscServer.setup()`. Likewise the OSC client port on which to -send is set in `oscClient.setup()`. - -In `setup()` an OSC message to address `/osc-setup`, it then waits -1 second for a reply on `/osc-setup-reply`. - -in `render()` the code receives OSC messages, parses them, and sends -back an acknowledgment. -*/ - -#include <Bela.h> -#include <OSCServer.h> -#include <OSCClient.h> - -OSCServer oscServer; -OSCClient oscClient; - -// this example is designed to be run alongside resources/osc/osc.js - -// parse messages recieved by OSC Server -// msg is Message class of oscpkt: http://gruntthepeon.free.fr/oscpkt/ -void parseMessage(oscpkt::Message msg){ - - rt_printf("recieved message to: %s\n", msg.addressPattern().c_str()); - - int intArg; - float floatArg; - if (msg.match("/osc-test").popInt32(intArg).popFloat(floatArg).isOkNoMoreArgs()){ - rt_printf("recieved int %i and float %f\n", intArg, floatArg); - } - -} - -bool setup(BelaContext *context, void *userData) -{ - // setup the OSC server to recieve on port 7562 - oscServer.setup(7562); - // setup the OSC client to send on port 7563 - oscClient.setup(7563); - - // the following code sends an OSC message to address /osc-setup - // then waits 1 second for a reply on /osc-setup-reply - bool handshakeRecieved = false; - oscClient.sendMessageNow(oscClient.newMessage.to("/osc-setup").end()); - oscServer.recieveMessageNow(1000); - while (oscServer.messageWaiting()){ - if (oscServer.popMessage().match("/osc-setup-reply")){ - handshakeRecieved = true; - } - } - - if (handshakeRecieved){ - rt_printf("handshake recieved!\n"); - } else { - rt_printf("timeout!\n"); - } - - return true; -} - -void render(BelaContext *context, void *userData) -{ - // recieve OSC messages, parse them, and send back an acknowledgment - while (oscServer.messageWaiting()){ - parseMessage(oscServer.popMessage()); - oscClient.queueMessage(oscClient.newMessage.to("/osc-acknowledge").add(5).add(4.2f).add(std::string("OSC message recieved")).end()); - } -} - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/oscillator_bank/audio_routines.S Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -@ -@ audio_routines.S -@ -@ NEON-based functions for time-critical audio processing -@ -@ Andrew McPherson 2014 -@ Queen Mary University of London -@ - - .syntax unified - .arch armv7-a - .fpu neon - -@ void oscillator_bank_neon(int numAudioFrames, float *audioOut, -@ int activePartialNum, int lookupTableSize, -@ float *phases, float *frequencies, float *amplitudes, -@ float *freqDerivatives, float *ampDerivatives, -@ float *lookupTable); - -@ Registers: -@ r0: numAudioFrames How many frames to render -@ r1: audioOut Buffer for audio output samples [stereo] -@ r2: activePartialNum How many active partials to render -@ r3: lookupTableSize Size of lookup table -@ ---- other arguments start on the stack and are moved: ----- -@ r4: phases Phase of each oscillator (pointer) -@ r5: frequencies Normalised frequency of each oscillator (pointer) -@ r6: amplitudes Normalised amplitude of each oscillator (pointer) -@ r7: freqDerivatives Derivative of frequency for each oscillator (pointer) -@ r8: ampDerivatives Derivative of amplitude for each oscillator (pointer) -@ r9: lookupTable Lookup table containing one oscillation -@ -@ Alignment requirements: -@ audioOut: 8-byte boundary -@ phases: 16-byte boundary -@ frequencies: 16-byte boundary -@ amplitudes: 16-byte boundary -@ freqDerivatives: 16-byte bounary -@ ampDerivatives: 16-byte boundary -@ lookupTable: 4-byte boundary (TODO: check this) - - .align 2 - .global oscillator_bank_neon - .thumb - .thumb_func - .type oscillator_bank_neon, %function -oscillator_bank_neon: - - -dSample .dn D6.F32 -qPhases .qn Q8.F32 -dPhases_0 .dn D16.F32 -dPhases_1 .dn D17.F32 -qFreqs .qn Q9.F32 -dFreqs_0 .dn D18.F32 -dFreqs_1 .dn D19.F32 -qAmps .qn Q10.F32 -dAmps_0 .dn D20.F32 -dAmps_1 .dn D21.F32 -qFreqDs .qn Q11.F32 -dFreqDs_0 .dn D22.F32 -dFreqDs_1 .dn D23.F32 -qAmpDs .qn Q12.F32 -dAmpDs_0 .dn D24.F32 -dAmpDs_1 .dn D25.F32 - -qBaseInts .qn Q13.U32 @ Base indexes: unsigned ints x4 -dBaseInts_0 .dn D26.U32 -dBaseInts_1 .dn D27.U32 -qFractions .qn Q14.F32 @ Fraction indexes: floats x4 -qTableBase .qn Q15.U32 @ Base of lookup table - - cmp r0, #0 @ Check for trivial case 1: zero frames - it eq - bxeq lr @ Return if that's the case (otherwise might have odd behaviour) - cmp r2, #4 @ Check for trivial case 2: zero oscillators - it lt - bxlt lr @ Return if that's the case - - push {r4-r11} @ Now arguments start 32 bytes above SP - add r11, sp, #32 @ Pointer to 32 bytes into the stack - ldm r11, {r4-r9} @ Load 6 arguments into registers - - vdup qTableBase, r9 @ Move lookup table base index into 4 ints - - @ Outer loop: iterate over the number of oscillators, choosing 4 at a - @ time to work with. -oscbank_oscillator_loop: - vld1 {dPhases_0, dPhases_1}, [r4] @ no increment; will store at end of sample loop - vld1 {dFreqs_0, dFreqs_1}, [r5] - vld1 {dAmps_0, dAmps_1}, [r6] - vld1 {dFreqDs_0, dFreqDs_1}, [r7]! @ increment; won't update at end of sample loop - vld1 {dAmpDs_0, dAmpDs_1}, [r8]! - - push {r0-r1,r4-r8} - @ --- inner loop: iterate over the number of samples --- -oscbank_sample_loop: - vcvt qBaseInts, qPhases @ Take floor(phases) - vmov q2.f32, #1.0 @ Load 1.0 into every slot of q2 - vshl q0.U32, qBaseInts, #2 @ Shift the indexes left 2 (*4 for float addressing) - vcvt qFractions, qBaseInts @ int back to float - vadd q0.U32, q0.U32, qTableBase @ Find memory addresses - - vmov r4, r5, d0 @ Move two indexes to ARM registers - vmov r6, r7, d1 @ Move two more indexes to ARM registers - vsub qFractions, qPhases, qFractions @ fraction = phase - floor(phase) - - vldr.64 d0, [r4] @ Load two consecutive floats at each location - vldr.64 d1, [r5] @ These hold the previous and following samples in the table - vldr.64 d2, [r6] @ TODO: check whether these work at 4-byte alignment - vldr.64 d3, [r7] - - @ Format at this point: - @ Osc0(before) Osc0(after) Osc1(before) Osc1(after) Osc2(before) Osc2(after) Osc3(before) Osc3(after) - @ We want: - @ Osc0(before) Osc1(before) Osc2(before) Osc3(before) Osc0(after) Osc1(after) Osc2(after) Osc3(after) - - vuzp.32 q0, q1 @ Now q0 contains before, q1 contains after - vsub q2.f32, q2.f32, qFractions @ q2 = 1.0 - fraction - vmul q1.f32, q1.f32, qFractions @ q1 = fraction * after - vmul q0.f32, q0.f32, q2.f32 @ q0 = (1.0 - fraction) * before - - vadd qPhases, qPhases, qFreqs @ Update phases - vadd qFreqs, qFreqs, qFreqDs @ Update frequencies - - vadd q0.f32, q0.f32, q1.f32 @ Add two interpolated components to get the final sample - vdup q2.u32, r3 @ Put lookup table size into each element of q2 - vcvt qBaseInts, qPhases @ Take floor of new phases - vmul q0.f32, q0.f32, qAmps @ Multiply samples by current amplitude - - vld1 dSample, [r1] @ Load the current stereo samples - vpadd d2.f32, d0.f32, d1.f32 @ Pairwise accumulate q0 (output sample) into d2 - - vand q2, q2, qBaseInts @ Logical AND of new phase int leaves 1 bit set only if phase >= table size - vpadd d3.f32, d2.f32, d2.f32 @ Pairwise accumulate d2 into d0 --> d0[0] and d0[1] both hold total of 4 oscillators - vadd qAmps, qAmps, qAmpDs @ Update amplitudes - vcvt q0.f32, q2.u32 @ Convert int back to float after AND operation - - vadd dSample, dSample, d3.f32 @ Add oscillator outputs to each channel - - subs r0, r0, #1 @ numFrames-- - vsub qPhases, qPhases, q0.f32 @ Keep phases in table range - vst1 dSample, [r1]! @ Store back in buffer and increment by 8 - - it gt - bgt oscbank_sample_loop @ Loop if numFrames > 0 - - @ --- end inner loop --- - pop {r0-r1,r4-r8} @ Restore registers: restores audioOut and numFrames, among others - - vst1 {dPhases_0, dPhases_1}, [r4]! @ Store phases back to array - vst1 {dFreqs_0, dFreqs_1}, [r5]! @ Store frequencies back to array - vst1 {dAmps_0, dAmps_1}, [r6]! @ Store amplitudes back to array - @ No need to update r7, r8 - - subs r2, r2, #4 @ numPartials -= 4 - it gt - bgt oscbank_oscillator_loop @ Loop if numPartials > 0 - - pop {r4-r11} - bx lr
--- a/examples/oscillator_bank/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <Bela.h> - -using namespace std; - -int gNumOscillators = 32; -int gWavetableLength = 1024; - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --num-oscillators [-n] oscs: Set the number of oscillators to use (default: 32)\n"; - cerr << " --wavetable [-w] length: Set the wavetable length in samples (default: 1024)\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"num-oscillators", 1, NULL, 'n'}, - {"wavetable", 1, NULL, 'w'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hn:w:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'n': - gNumOscillators = atoi(optarg); - if(gNumOscillators <= 0) { - usage(basename(argv[0])); - exit(0); - } - break; - case 'w': - gWavetableLength = atoi(optarg); - if(gWavetableLength < 4) - gWavetableLength = 4; - if(gWavetableLength > 16384) - gWavetableLength = 16384; - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, 0) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - if(settings.verbose) { - cout << "--> Using " << gNumOscillators << " oscillators and wavetable of " << gWavetableLength << " samples\n"; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/oscillator_bank/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -/** -\example 4_oscillator_bank - -Oscillator Bank ----------------------- - -These files demonstrate an oscillator bank implemented in assembly code -that is used as part of the d-box project. -*/ - -#include <Bela.h> -#include <rtdk.h> -#include <cstdlib> -#include <cmath> -#include <cstring> -#include <time.h> - -const float kMinimumFrequency = 20.0f; -const float kMaximumFrequency = 8000.0f; - -float *gWavetable; // Buffer holding the precalculated sine lookup table -float *gPhases; // Buffer holding the phase of each oscillator -float *gFrequencies; // Buffer holding the frequencies of each oscillator -float *gAmplitudes; // Buffer holding the amplitudes of each oscillator -float *gDFrequencies; // Buffer holding the derivatives of frequency -float *gDAmplitudes; // Buffer holding the derivatives of amplitude - -float gAudioSampleRate; -int gSampleCount; // Sample counter for indicating when to update frequencies -float gNewMinFrequency; -float gNewMaxFrequency; - -// Task for handling the update of the frequencies using the matrix -AuxiliaryTask gFrequencyUpdateTask; - -// These settings are carried over from main.cpp -// Setting global variables is an alternative approach -// to passing a structure to userData in setup() - -extern int gNumOscillators; -extern int gWavetableLength; - -void recalculate_frequencies(); - -extern "C" { - // Function prototype for ARM assembly implementation of oscillator bank - void oscillator_bank_neon(int numAudioFrames, float *audioOut, - int activePartialNum, int lookupTableSize, - float *phases, float *frequencies, float *amplitudes, - float *freqDerivatives, float *ampDerivatives, - float *lookupTable); -} - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. -bool setup(BelaContext *context, void *userData) -{ - srandom(time(NULL)); - - if(context->audioChannels != 2) { - rt_printf("Error: this example needs stereo audio enabled\n"); - return false; - } - - // Initialise the sine wavetable - if(posix_memalign((void **)&gWavetable, 8, (gWavetableLength + 1) * sizeof(float))) { - rt_printf("Error allocating wavetable\n"); - return false; - } - for(int n = 0; n < gWavetableLength + 1; n++) - gWavetable[n] = sinf(2.0 * M_PI * (float)n / (float)gWavetableLength); - - // Allocate the other buffers - if(posix_memalign((void **)&gPhases, 16, gNumOscillators * sizeof(float))) { - rt_printf("Error allocating phase buffer\n"); - return false; - } - if(posix_memalign((void **)&gFrequencies, 16, gNumOscillators * sizeof(float))) { - rt_printf("Error allocating frequency buffer\n"); - return false; - } - if(posix_memalign((void **)&gAmplitudes, 16, gNumOscillators * sizeof(float))) { - rt_printf("Error allocating amplitude buffer\n"); - return false; - } - if(posix_memalign((void **)&gDFrequencies, 16, gNumOscillators * sizeof(float))) { - rt_printf("Error allocating frequency derivative buffer\n"); - return false; - } - if(posix_memalign((void **)&gDAmplitudes, 16, gNumOscillators * sizeof(float))) { - rt_printf("Error allocating amplitude derivative buffer\n"); - return false; - } - - // Initialise buffer contents - - float freq = kMinimumFrequency; - float increment = (kMaximumFrequency - kMinimumFrequency) / (float)gNumOscillators; - - for(int n = 0; n < gNumOscillators; n++) { - gPhases[n] = 0.0; - - if(context->analogFrames == 0) { - // Random frequencies when used without matrix - gFrequencies[n] = kMinimumFrequency + (kMaximumFrequency - kMinimumFrequency) * ((float)random() / (float)RAND_MAX); - } - else { - // Constant spread of frequencies when used with matrix - gFrequencies[n] = freq; - freq += increment; - } - - // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians - gFrequencies[n] *= (float)gWavetableLength / context->audioSampleRate; - gAmplitudes[n] = ((float)random() / (float)RAND_MAX) / (float)gNumOscillators; - gDFrequencies[n] = gDAmplitudes[n] = 0.0; - } - - increment = 0; - freq = 440.0; - - for(int n = 0; n < gNumOscillators; n++) { - // Update the frequencies to a regular spread, plus a small amount of randomness - // to avoid weird phase effects - float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; - float newFreq = freq * randScale; - - // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians - gFrequencies[n] = newFreq * (float)gWavetableLength / context->audioSampleRate; - - freq += increment; - } - - // Initialise auxiliary tasks - if((gFrequencyUpdateTask = Bela_createAuxiliaryTask(&recalculate_frequencies, 85, "bela-update-frequencies")) == 0) - return false; - - //for(int n = 0; n < gNumOscillators; n++) - // rt_printf("%f\n", gFrequencies[n]); - - gAudioSampleRate = context->audioSampleRate; - gSampleCount = 0; - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - // Initialise buffer to 0 - memset(context->audioOut, 0, 2 * context->audioFrames * sizeof(float)); - - // Render audio frames - oscillator_bank_neon(context->audioFrames, context->audioOut, - gNumOscillators, gWavetableLength, - gPhases, gFrequencies, gAmplitudes, - gDFrequencies, gDAmplitudes, - gWavetable); - - if(context->analogFrames != 0 && (gSampleCount += context->audioFrames) >= 128) { - gSampleCount = 0; - gNewMinFrequency = map(context->analogIn[0], 0, 1.0, 1000.0f, 8000.0f); - gNewMaxFrequency = map(context->analogIn[1], 0, 1.0, 1000.0f, 8000.0f); - - // Make sure max >= min - if(gNewMaxFrequency < gNewMinFrequency) { - float temp = gNewMaxFrequency; - gNewMaxFrequency = gNewMinFrequency; - gNewMinFrequency = temp; - } - - // Request that the lower-priority task run at next opportunity - //Bela_scheduleAuxiliaryTask(gFrequencyUpdateTask); - } -} - -// This is a lower-priority call to update the frequencies which will happen -// periodically when the matrix is enabled. By placing it at a lower priority, -// it has minimal effect on the audio performance but it will take longer to -// complete if the system is under heavy audio load. - -void recalculate_frequencies() -{ - float freq = gNewMinFrequency; - float increment = (gNewMaxFrequency - gNewMinFrequency) / (float)gNumOscillators; - - for(int n = 0; n < gNumOscillators; n++) { - // Update the frequencies to a regular spread, plus a small amount of randomness - // to avoid weird phase effects - float randScale = 0.99 + .02 * (float)random() / (float)RAND_MAX; - float newFreq = freq * randScale; - - // For efficiency, frequency is expressed in change in wavetable position per sample, not Hz or radians - gFrequencies[n] = newFreq * (float)gWavetableLength / gAudioSampleRate; - - freq += increment; - } -} - - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - free(gWavetable); - free(gPhases); - free(gFrequencies); - free(gAmplitudes); - free(gDFrequencies); - free(gDAmplitudes); -}
--- a/examples/pd/basicAnalogIn/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#N canvas 203 356 637 339 10; -#X obj 63 170 osc~ 440; -#X obj 63 223 dac~; -#X obj 63 191 *~; -#X text 440 95 ADC 3: Analog In 0; -#X text 34 41 Basic analog in (or 'theremin'); -#X text 34 51 ===============================; -#X text 121 105 << Use first two analog in's; -#X text 440 49 ADC routing:; -#X text 440 57 ------------; -#X text 440 105 ADC 4: Analog In 1; -#X text 440 115 ADC 5: Analog In 2; -#X text 440 125 ADC 6: Analog In 3; -#X text 440 135 ADC 7: Analog In 4; -#X text 440 145 ADC 8: Analog In 5; -#X text 440 155 ADC 9: Analog In 6; -#X text 440 165 ADC 10: Analog In 7; -#X text 440 75 ADC 1: Audio In L; -#X text 440 85 ADC 2: Audio In R; -#X obj 63 149 *~ 880; -#X obj 63 106 adc~ 3 4; -#X text 355 277 ---------------------------------; -#X text 355 267 @krighxz / BELA / heavy / 12/2015; -#X text 379 286 beaglert.cc / enzienaudio.com; -#X connect 0 0 2 0; -#X connect 2 0 1 0; -#X connect 2 0 1 1; -#X connect 18 0 0 0; -#X connect 19 0 18 0; -#X connect 19 1 2 1;
--- a/examples/pd/basicAnalogOut/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#N canvas 275 504 679 362 10; -#X text 148 124 << Use first two analog in's; -#X text 431 57 ------------; -#X text 44 51 Basic analog out; -#X text 44 61 ================; -#X text 431 95 DAC 3: Analog Out 0; -#X text 431 105 DAC 4: Analog Out 1; -#X text 431 115 DAC 5: Analog Out 2; -#X text 431 125 DAC 6: Analog Out 3; -#X text 431 145 DAC 8: Analog Out 5; -#X text 431 135 DAC 7: Analog Out 4; -#X text 431 155 DAC 9: Analog Out 6; -#X text 431 165 DAC 10: Analog Out 7; -#X text 431 85 DAC 2: Audio Out R; -#X text 431 75 DAC 1: Audio Out L; -#X obj 92 201 *~; -#X obj 92 159 *~ 10; -#X obj 92 180 osc~ 1; -#X obj 35 242 dac~ 1 2 3; -#X text 143 241 << Output to first analog out; -#X text 431 49 DAC routing:; -#X text 432 289 ---------------------------------; -#X text 432 279 @krighxz / BELA / heavy / 12/2015; -#X text 456 298 beaglert.cc / enzienaudio.com; -#X obj 92 125 adc~ 3 4; -#X connect 14 0 17 2; -#X connect 15 0 16 0; -#X connect 16 0 14 0; -#X connect 23 0 15 0; -#X connect 23 1 14 1;
--- a/examples/pd/circularBuffer/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -#N canvas 436 490 738 494 10; -#X obj 135 167 loadbang; -#X msg 135 212 1; -#X obj 183 234 / 44.1; -#X obj 135 253 metro; -#X obj 135 286 f; -#X obj 160 286 + 64; -#X obj 160 308 % 65536, f 8; -#X msg 160 329 start \$1; -#X obj 160 351 tabwrite~ circbuf; -#X obj 363 303 - 32768; -#X obj 363 325 + 65536; -#X obj 363 347 % 65536; -#X obj 342 371 +~ 0; -#X msg 381 236 0; -#X obj 342 258 phasor~; -#X obj 342 392 tabread4~ circbuf; -#X obj 341 415 dac~; -#N canvas 422 781 312 126 buf 0; -#N canvas 0 22 450 278 (subpatch) 0; -#X array circbuf 65536 float 2; -#X coords 0 1 65535 -1 256 64 1 0 0; -#X restore 23 28 graph; -#X restore 129 441 pd buf; -#X obj 32 101 osc~ 440; -#X obj 342 213 samplerate~; -#X obj 134 189 t b b b b; -#X text 30 82 audio input; -#X text 219 310 write pointer; -#X text 412 349 read pointer; -#X obj 342 282 *~ 16; -#X obj 342 236 / 16; -#X obj 183 214 f 16; -#X obj 363 189 r \$0-blocksize; -#X obj 204 186 r \$0-blocksize; -#X obj 394 259 r \$0-blocksize; -#X obj 390 123 s \$0-blocksize; -#X text 34 13 VIRTUAL CIRCULAR BUFFER; -#X text 34 23 =======================; -#X obj 390 55 loadbang; -#X msg 390 77 16; -#X text 517 454 ---------------------------------; -#X text 517 444 @krighxz / BELA / heavy / 12/2015; -#X text 541 463 beaglert.cc / enzienaudio.com; -#X text 426 78 << replace with target blocksize; -#X text 446 90 BELA default: 16; -#X text 446 102 PD default: 64; -#X connect 0 0 20 0; -#X connect 1 0 3 0; -#X connect 2 0 3 1; -#X connect 3 0 4 0; -#X connect 4 0 5 0; -#X connect 5 0 6 0; -#X connect 5 0 9 0; -#X connect 6 0 7 0; -#X connect 6 0 4 1; -#X connect 7 0 8 0; -#X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 12 1; -#X connect 12 0 15 0; -#X connect 13 0 14 1; -#X connect 14 0 24 0; -#X connect 15 0 16 0; -#X connect 15 0 16 1; -#X connect 18 0 8 0; -#X connect 19 0 25 0; -#X connect 20 0 1 0; -#X connect 20 1 26 0; -#X connect 20 2 13 0; -#X connect 20 3 19 0; -#X connect 24 0 12 0; -#X connect 25 0 14 0; -#X connect 26 0 2 0; -#X connect 27 0 25 1; -#X connect 28 0 26 1; -#X connect 29 0 24 1; -#X connect 33 0 34 0; -#X connect 34 0 30 0;
--- a/examples/pd/digital/bela_digital-help.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -#N canvas 121 46 877 628 10; -#X obj 64 94 r bela_digitalIn11; -#X obj 219 94 r bela_digitalIn12; -#X obj 386 107 adc~ 13 14; -#X text 49 64 Digital in \, message rate; -#X text 214 69 Digital in \, message rate; -#X text 394 85 Digital ins \, signal rate; -#X obj 32 283 s bela_digitalOut15; -#X text 13 309 Digital out \, message rate; -#X obj 396 593 s bela_setDigital; -#X obj 396 533 loadbang; -#X msg 431 401 in 11; -#X text 524 390 First argument is the pin direction Second argument -is the pin number Third argument is the rate \, can be "~" or "sig" -for signal-rate or "message" for message-rate. Defaults to message-rate. -; -#X msg 431 458 in 13 ~; -#X msg 432 429 in 12 message; -#X msg 517 506 disable 17; -#X obj 386 139 snapshot~; -#X obj 500 134 snapshot~; -#X obj 529 56 loadbang; -#X obj 384 181 print digitalIn13; -#X obj 500 183 print digitalIn14; -#X obj 497 105 metro 200; -#X text 525 474 To stop using a pin (e.g.: to save CPU) \, send a disable -message containing the pin number; -#X obj 224 280 dac~ 16; -#X obj 22 232 metro 500; -#X obj 32 257 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 -1; -#X obj 224 253 phasor~ 300; -#X text 160 234 Nice \, anti-aliased square wave; -#X obj 22 207 loadbang; -#X text 15 181 Blink that LED!; -#X obj 411 306 dac~ 17; -#X obj 405 248 osc~ 300; -#X obj 470 248 phasor~ 169; -#X obj 457 278 -~ 0.5; -#X text 403 210 Sum signals together for unpredictable effects; -#X obj 612 303 dac~ 18; -#X text 198 305 Digital out \, signal rate; -#X text 378 325 Digital out \, signal rate; -#X text 588 325 Digital out \, signal rate; -#X obj 608 222 adc~; -#X obj 612 249 *~ 0.5; -#X obj 612 276 +~ 0.5; -#X text 585 203 The ultimate bit-crusher; -#X msg 426 555 in 11 \, in 12 \, in 13 ~ \, in 14 ~ \, out 15 \, out -16 ~ \, out 17 ~ \, out 18 ~; -#X text 23 377 Each digital channel can be configured as either an -input or an output. Send messages to bela_setDigital to configure the -digitalPins (needed before using them). Pins settings can be modified -at will during execution. Message-rate input pins receive messages -only when the input changes. Message-rate output pins will write to -the output the most recent value you send them. Signal-rate inputs -and outputs are handled as regular audio channels. Outputs are thresholded -to 0.5 before being written to the actual output. Note that each pin -that is managed adds to the CPU usage \, so only activate the pins -you actually need.; -#X text 34 19 Digital channels are numbered 11 to 26 \, which corresponds -to Bela's 0 to 15 digital channels. They can be set to respond at message -rate or at signal rate; -#X obj 415 271 osc~ 1; -#X obj 385 157 change; -#X obj 500 158 change; -#X obj 64 116 print digitalIn11; -#X obj 219 117 print digitalIn12; -#X connect 0 0 48 0; -#X connect 1 0 49 0; -#X connect 2 0 15 0; -#X connect 2 1 16 0; -#X connect 9 0 42 0; -#X connect 10 0 8 0; -#X connect 12 0 8 0; -#X connect 13 0 8 0; -#X connect 14 0 8 0; -#X connect 15 0 46 0; -#X connect 16 0 47 0; -#X connect 17 0 20 0; -#X connect 20 0 16 0; -#X connect 20 0 15 0; -#X connect 23 0 24 0; -#X connect 24 0 6 0; -#X connect 25 0 22 0; -#X connect 27 0 23 0; -#X connect 30 0 29 0; -#X connect 31 0 32 0; -#X connect 32 0 29 0; -#X connect 38 0 39 0; -#X connect 38 1 39 0; -#X connect 39 0 40 0; -#X connect 40 0 34 0; -#X connect 42 0 8 0; -#X connect 45 0 29 0; -#X connect 46 0 18 0; -#X connect 47 0 19 0;
--- a/examples/pd/digital/digital_example.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -#N canvas 279 78 857 690 10; -#X obj 18 477 osc~ 200; -#X obj 57 522 *~; -#X obj 112 405 line~ 1; -#X msg 116 372 1 \, 0 200; -#X obj 205 472 line~ 1; -#X msg 209 439 1 \, 0 200; -#X obj 210 405 select 1; -#X obj 140 531 *~; -#X obj 484 601 s bela_setDigital; -#X obj 484 532 loadbang; -#X msg 65 445 0; -#X obj 116 332 r bela_digitalIn12; -#X obj 422 217 r bela_digitalIn14; -#X obj 422 243 s bela_digitalOut13; -#X obj 285 218 r bela_digitalIn12; -#X obj 285 243 s bela_digitalOut11; -#X obj 374 339 timer; -#X msg 404 304 bang; -#X msg 368 304 bang; -#X obj 555 184 metro 1000; -#X obj 575 304 s bela_digitalOut15; -#X obj 374 366 print sourceto12; -#X obj 488 351 timer; -#X msg 518 316 bang; -#X msg 482 316 bang; -#X obj 487 380 print sourceto14; -#X obj 663 15 r bela_digitalIn16; -#X msg 553 265 1; -#X obj 577 214 delay 500; -#X obj 480 275 select 1; -#X obj 346 268 select 1; -#X msg 584 281 0; -#X obj 634 251 select 1 0; -#X obj 80 622 dac~ 3 4; -#X obj 65 566 expr~ $v1*0.5 + 0.5; -#X obj 138 588 expr~ $v1*0.5 + 0.5; -#X obj 65 202 dac~ 11; -#X obj 114 83 osc~ 300; -#X obj 176 179 dac~ 1 3; -#X obj 34 136 adc~ 17; -#X obj 423 504 delay 3000; -#X msg 388 552 disable 12; -#X msg 484 552 out 11 ~ \, out 13 \, in 14 \, out 15 \, in 16 \, in -17 ~; -#X connect 0 0 1 0; -#X connect 0 0 7 0; -#X connect 1 0 34 0; -#X connect 2 0 1 1; -#X connect 3 0 2 0; -#X connect 4 0 7 1; -#X connect 5 0 4 0; -#X connect 6 0 5 0; -#X connect 6 0 10 0; -#X connect 7 0 35 0; -#X connect 9 0 42 0; -#X connect 9 0 40 0; -#X connect 10 0 0 1; -#X connect 11 0 3 0; -#X connect 12 0 13 0; -#X connect 12 0 29 0; -#X connect 14 0 15 0; -#X connect 14 0 30 0; -#X connect 16 0 21 0; -#X connect 17 0 16 1; -#X connect 18 0 16 0; -#X connect 19 0 27 0; -#X connect 19 0 28 0; -#X connect 22 0 25 0; -#X connect 23 0 22 1; -#X connect 24 0 22 0; -#X connect 26 0 32 0; -#X connect 27 0 20 0; -#X connect 27 0 24 0; -#X connect 27 0 18 0; -#X connect 28 0 31 0; -#X connect 29 0 23 0; -#X connect 30 0 17 0; -#X connect 31 0 20 0; -#X connect 32 0 27 0; -#X connect 32 1 31 0; -#X connect 34 0 33 0; -#X connect 35 0 33 1; -#X connect 37 0 38 0; -#X connect 37 0 38 1; -#X connect 39 0 36 0; -#X connect 40 0 41 0; -#X connect 41 0 8 0; -#X connect 42 0 8 0;
--- a/examples/pd/envelopeTrigger/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -#N canvas 646 209 359 287 10; -#X obj 28 207 dac~; -#N canvas 324 380 556 621 env 0; -#N canvas 886 1001 131 207 >~ 0; -#X obj 19 -37 -~; -#X obj 19 -58 min~; -#X obj 19 26 *~ 1e+37; -#X obj 19 5 +~ 1e-37; -#X obj 19 -16 clip~ -1e-37 0; -#X obj 19 -83 inlet~; -#X obj 62 -83 inlet~; -#X obj 19 48 outlet~; -#X connect 0 0 4 0; -#X connect 1 0 0 0; -#X connect 2 0 7 0; -#X connect 3 0 2 0; -#X connect 4 0 3 0; -#X connect 5 0 1 0; -#X connect 6 0 0 1; -#X connect 6 0 1 1; -#X restore 199 106 pd >~; -#X obj 23 173 /~ 44100; -#X obj 68 153 samplerate~; -#X obj 68 133 loadbang; -#X obj 199 128 biquad~ 0 0 -1 1 0; -#X obj 23 209 rpole~; -#X obj 23 153 sig~ 1; -#X obj 226 171 sig~ 0.5; -#N canvas 0 22 110 231 <~ 0; -#X obj 11 -41 -~; -#X obj 11 29 +~ 1e-37; -#X obj 11 8 clip~ -1e-37 0; -#X obj 11 -86 inlet~; -#X obj 55 -85 inlet~; -#X obj 11 -62 max~; -#X obj 11 -17 *~ -1; -#X obj 11 81 outlet~; -#X obj 11 50 *~ 1e+37; -#X connect 0 0 6 0; -#X connect 1 0 8 0; -#X connect 2 0 1 0; -#X connect 3 0 5 0; -#X connect 4 0 0 1; -#X connect 4 0 5 1; -#X connect 5 0 0 0; -#X connect 6 0 2 0; -#X connect 8 0 7 0; -#X restore 199 192 pd <~; -#X text 237 193 (x != x); -#X obj 23 467 *~; -#X obj 199 150 *~ -1; -#X obj 23 331 *~ 512; -#X obj 23 229 clip~ 0 1; -#X obj 23 352 tabread4~ env1; -#X obj 23 310 *~; -#X obj 199 64 abs~; -#X obj 199 43 hip~ 1; -#X obj 199 22 inlet~ excitationSignal; -#X obj 218 269 sig~ 1; -#X obj 218 292 /~; -#X obj 226 86 inlet~ threshold; -#X obj 262 229 inlet~ envDuration; -#X obj 38 445 osc~ 220; -#X obj 38 425 +~ 50; -#X obj 38 385 *~; -#X obj 38 405 *~ 1000; -#X obj 262 269 clip~ 1e-05 100000; -#X obj 23 487 outlet~; -#N canvas 0 22 450 278 (subpatch) 0; -#X array env1 512 float 3; -#A 0 0 0.0625 0.0883883 0.108253 0.125 0.139754 0.153093 0.165359 0.176777 -0.1875 0.197642 0.207289 0.216506 0.225347 0.233854 0.242061 0.25 0.257694 -0.265165 0.272431 0.279509 0.286411 0.293151 0.299739 0.306186 0.3125 -0.318689 0.32476 0.330719 0.336573 0.342327 0.347985 0.353553 0.359035 -0.364434 0.369755 0.375 0.380173 0.385276 0.390312 0.395285 0.400195 -0.405046 0.40984 0.414578 0.419263 0.423896 0.428478 0.433013 0.4375 -0.441942 0.446339 0.450694 0.455007 0.459279 0.463512 0.467707 0.471865 -0.475986 0.480072 0.484123 0.488141 0.492125 0.496078 0.5 0.503891 -0.507752 0.511585 0.515388 0.519164 0.522913 0.526634 0.53033 0.534 -0.537645 0.541266 0.544862 0.548435 0.551985 0.555512 0.559017 0.5625 -0.565962 0.569402 0.572822 0.576222 0.579601 0.582961 0.586302 0.589624 -0.592927 0.596212 0.599479 0.602728 0.60596 0.609175 0.612372 0.615554 -0.618718 0.621867 0.625 0.628117 0.631219 0.634306 0.637377 0.640434 -0.643477 0.646505 0.649519 0.652519 0.655506 0.658478 0.661438 0.664384 -0.667317 0.670238 0.673146 0.676041 0.678924 0.681795 0.684653 0.6875 -0.690335 0.693159 0.695971 0.698771 0.701561 0.704339 0.707107 0.709864 -0.71261 0.715345 0.71807 0.720785 0.72349 0.726184 0.728869 0.731544 -0.734209 0.736864 0.73951 0.742146 0.744773 0.747391 0.75 0.7526 0.75519 -0.757772 0.760345 0.76291 0.765466 0.768013 0.770552 0.773082 0.775605 -0.778119 0.780625 0.783123 0.785613 0.788095 0.790569 0.793036 0.795495 -0.797947 0.800391 0.802827 0.805256 0.807678 0.810093 0.8125 0.8149 -0.817294 0.81968 0.822059 0.824432 0.826797 0.829156 0.831508 0.833854 -0.836193 0.838525 0.840851 0.843171 0.845484 0.847791 0.850092 0.852386 -0.854675 0.856957 0.859233 0.861503 0.863767 0.866025 0.868278 0.870524 -0.872765 0.875 0.877229 0.879453 0.881671 0.883883 0.88609 0.888292 -0.890488 0.892679 0.894864 0.897044 0.899218 0.901388 0.903552 0.905711 -0.907865 0.910014 0.912157 0.914296 0.91643 0.918559 0.920682 0.922801 -0.924916 0.927025 0.929129 0.931229 0.933324 0.935414 0.9375 0.939581 -0.941657 0.943729 0.945797 0.947859 0.949918 0.951972 0.954021 0.956066 -0.958107 0.960143 0.962175 0.964203 0.966227 0.968246 0.970261 0.972272 -0.974279 0.976281 0.97828 0.980274 0.982265 0.984251 0.986233 0.988212 -0.990186 0.992157 0.994123 0.996086 0.998045 1 0.992172 0.984375 0.976609 -0.968874 0.961169 0.953495 0.945852 0.938239 0.930657 0.923106 0.915586 -0.908097 0.900638 0.89321 0.885813 0.878447 0.871111 0.863806 0.856532 -0.849289 0.842076 0.834894 0.827743 0.820623 0.813533 0.806474 0.799446 -0.792449 0.785483 0.778547 0.771642 0.764767 0.757924 0.751111 0.744329 -0.737578 0.730857 0.724168 0.717509 0.71088 0.704283 0.697716 0.69118 -0.684675 0.678201 0.671757 0.665344 0.658962 0.652611 0.64629 0.64 -0.633741 0.627513 0.621315 0.615148 0.609012 0.602907 0.596832 0.590788 -0.584775 0.578793 0.572841 0.56692 0.56103 0.555171 0.549343 0.543545 -0.537778 0.532041 0.526336 0.520661 0.515017 0.509404 0.503822 0.49827 -0.492749 0.487259 0.481799 0.476371 0.470973 0.465605 0.460269 0.454963 -0.449689 0.444444 0.439231 0.434048 0.428897 0.423775 0.418685 0.413625 -0.408597 0.403599 0.398631 0.393695 0.388789 0.383914 0.37907 0.374256 -0.369473 0.364721 0.36 0.355309 0.35065 0.346021 0.341423 0.336855 -0.332318 0.327812 0.323337 0.318893 0.314479 0.310096 0.305744 0.301423 -0.297132 0.292872 0.288643 0.284444 0.280277 0.27614 0.272034 0.267958 -0.263914 0.2599 0.255917 0.251965 0.248043 0.244152 0.240292 0.236463 -0.232664 0.228897 0.22516 0.221453 0.217778 0.214133 0.210519 0.206936 -0.203383 0.199862 0.196371 0.19291 0.189481 0.186082 0.182714 0.179377 -0.176071 0.172795 0.16955 0.166336 0.163153 0.16 0.156878 0.153787 -0.150727 0.147697 0.144698 0.14173 0.138793 0.135886 0.13301 0.130165 -0.127351 0.124567 0.121815 0.119093 0.116401 0.113741 0.111111 0.108512 -0.105944 0.103406 0.1009 0.0984237 0.0959785 0.093564 0.0911803 0.0888274 -0.0865052 0.0842138 0.0819531 0.0797232 0.077524 0.0753556 0.073218 -0.0711111 0.069035 0.0669896 0.064975 0.0629911 0.0610381 0.0591157 -0.0572241 0.0553633 0.0535332 0.0517339 0.0499654 0.0482276 0.0465206 -0.0448443 0.0431988 0.041584 0.04 0.0384467 0.0369243 0.0354325 0.0339715 -0.0325413 0.0311419 0.0297732 0.0284352 0.027128 0.0258516 0.0246059 -0.023391 0.0222068 0.0210534 0.0199308 0.0188389 0.0177778 0.0167474 -0.0157478 0.0147789 0.0138408 0.0129335 0.0120569 0.0112111 0.010396 -0.00961169 0.00885813 0.00813533 0.00744329 0.00678201 0.00615148 0.00555171 -0.0049827 0.00444444 0.00393695 0.00346021 0.00301423 0.002599 0.00221453 -0.00186082 0.00153787 0.00124567 0.000984237 0.000753556 0.000553633 -0.000384467 0.000246059 0.000138408 6.15148e-05 1.53787e-05 0; -#X coords 0 1 512 0 512 64 1 0 0; -#X restore 24 536 graph; -#X text 244 55 centre signal around zero and take abs value; -#X text 243 107 if greater than threshold output 1; -#X text 313 129 differentiator; -#X text 238 150 (generates impulse on positive trigger (0->1); -#X text 67 210 signal-rate counter; -#X text 296 193 -> resets counter by briefly setting; -#X text 314 204 rpole~ coeff to 0; -#X text 96 416 kickdrum 101 :P; -#X text 400 514 pre-generated envelope; -#X obj 262 249 *~; -#X text 127 352 << use envelope value for volume and frequency; -#X connect 0 0 4 0; -#X connect 1 0 5 0; -#X connect 2 0 1 1; -#X connect 3 0 2 0; -#X connect 4 0 11 0; -#X connect 5 0 13 0; -#X connect 6 0 1 0; -#X connect 7 0 8 1; -#X connect 8 0 5 1; -#X connect 10 0 28 0; -#X connect 11 0 8 0; -#X connect 12 0 14 0; -#X connect 13 0 15 0; -#X connect 14 0 10 0; -#X connect 14 0 25 0; -#X connect 14 0 25 1; -#X connect 15 0 12 0; -#X connect 16 0 0 0; -#X connect 17 0 16 0; -#X connect 18 0 17 0; -#X connect 19 0 20 0; -#X connect 20 0 15 1; -#X connect 21 0 0 1; -#X connect 22 0 39 0; -#X connect 22 0 39 1; -#X connect 23 0 10 1; -#X connect 24 0 23 0; -#X connect 25 0 26 0; -#X connect 26 0 24 0; -#X connect 27 0 20 1; -#X connect 39 0 27 0; -#X restore 28 174 pd env; -#X obj 79 110 adc~ 9; -#X obj 129 130 adc~ 10; -#X text 72 90 piezo input for excitation; -#X text 123 110 fader 1 sets threshold; -#X text 183 130 fader 2 sets duration; -#X text 29 17 SAMPLE-ACCURATE ENVELOPE TRIGGER; -#X text 29 27 ================================; -#X obj 28 90 adc~ 8; -#X text 141 236 ---------------------------------; -#X text 141 226 @krighxz / BELA / heavy / 12/2015; -#X text 165 245 beaglert.cc / enzienaudio.com; -#X connect 1 0 0 0; -#X connect 1 0 0 1; -#X connect 2 0 1 1; -#X connect 3 0 1 2; -#X connect 9 0 1 0;
--- a/examples/pd/hello-midi/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -#N canvas 85 58 1280 685 10; -#X obj 19 396 dac~ 1 2; -#X text 39 1 Hello world!; -#X text 37 11 ============; -#X obj 31 353 *~ 0.1; -#X text 202 448 ---------------------------------; -#X text 202 438 @krighxz / BELA / heavy / 12/2015; -#X text 226 457 beaglert.cc / enzienaudio.com; -#X obj 39 132 mtof; -#X floatatom 79 59 5 0 0 0 - - -, f 5; -#X floatatom 122 59 5 0 0 0 - - -, f 5; -#X floatatom 41 63 5 0 0 0 - - -, f 5; -#X obj 26 170 phasor~ 440; -#X text 100 363 (the harsh sound of success); -#X obj 260 83 * 20; -#X obj 261 112 + 200; -#X obj 132 85 loadbang; -#X msg 131 111 1000; -#X obj 125 166 sig~; -#X text 673 121 [pgmin]; -#X obj 218 178 * 10; -#X obj 30 250 hip~; -#X obj 26 275 hip~; -#X obj 20 302 hip~; -#X obj 19 323 hip~; -#X obj 87 192 lop~ 4; -#X obj 152 256 line; -#X obj 200 200 + 50; -#X msg 170 227 \$1 200; -#X msg 93 114 0; -#X msg 185 112 0; -#X obj 29 224 vcf~ 4; -#X obj 70 333 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 -1; -#X obj 42 92 mono; -#X obj 40 28 bela_notein 0; -#X obj 260 60 bela_ctlin 5 0; -#X obj 220 151 bela_ctlin 6 0; -#X text 537 58 [ctlin]; -#X text 332 27 [notein]; -#X text 140 29 <== the bela equivalent of ==>; -#X text 349 59 <== the bela equivalent of ==>; -#X text 483 121 <== the bela equivalent of ==>; -#X obj 405 175 print pgmin; -#X obj 408 121 bela_pgmin 0; -#X connect 3 0 0 1; -#X connect 3 0 0 0; -#X connect 7 0 11 0; -#X connect 8 0 32 1; -#X connect 10 0 32 0; -#X connect 11 0 30 0; -#X connect 13 0 14 0; -#X connect 14 0 17 0; -#X connect 15 0 16 0; -#X connect 15 0 29 0; -#X connect 15 0 28 0; -#X connect 16 0 17 0; -#X connect 17 0 24 0; -#X connect 19 0 26 0; -#X connect 20 0 21 0; -#X connect 21 0 22 0; -#X connect 22 0 23 0; -#X connect 23 0 3 0; -#X connect 24 0 30 1; -#X connect 25 0 20 1; -#X connect 25 0 21 1; -#X connect 25 0 22 1; -#X connect 25 0 23 1; -#X connect 26 0 27 0; -#X connect 27 0 25 0; -#X connect 29 0 19 0; -#X connect 30 0 20 0; -#X connect 31 0 3 1; -#X connect 32 0 7 0; -#X connect 32 1 31 0; -#X connect 33 0 10 0; -#X connect 33 1 8 0; -#X connect 33 2 9 0; -#X connect 34 0 13 0; -#X connect 35 0 19 0; -#X connect 42 0 41 0;
--- a/examples/pd/hello-midi/countTo.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -#N canvas 584 255 450 300 10; -#X obj 65 196 outlet; -#X obj 98 8 inlet; -#X text 189 49 counts from 0 to the given number -1; -#X text 214 95 inlet:N; -#X text 212 112 outlet: 0 \, 1 \, 2 \, ... \, N-1; -#X obj 143 61 f; -#X obj 100 138 spigot; -#X obj 129 89 <; -#X obj 129 113 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 -1; -#X obj 95 28 t b f b; -#X obj 92 74 + 1; -#X obj 43 73 f; -#X obj 63 104 t b f f f; -#X msg 92 53 0; -#X obj 16 144 delay 0; -#X connect 1 0 9 0; -#X connect 5 0 7 1; -#X connect 6 0 11 0; -#X connect 7 0 8 0; -#X connect 8 0 6 1; -#X connect 9 0 11 0; -#X connect 9 1 5 0; -#X connect 9 1 13 0; -#X connect 10 0 11 1; -#X connect 11 0 12 0; -#X connect 12 0 14 0; -#X connect 12 1 0 0; -#X connect 12 2 7 0; -#X connect 12 3 10 0; -#X connect 13 0 11 1; -#X connect 14 0 6 0;
--- a/examples/pd/hello-midi/maxArray.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -#N canvas 464 23 1002 583 10; -#X obj 224 202 max; -#X obj 265 200 f; -#X obj 223 229 change; -#X obj 223 251 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 --1 -1; -#X obj 223 271 f; -#X obj 259 323 f; -#X obj 187 315 f; -#X obj 268 282 t b b; -#X obj 183 364 outlet; -#X obj 269 379 outlet; -#X obj 179 17 inlet; -#X obj 225 177 tabread \$1; -#X obj 230 88 t f f b; -#X text 376 37 Finds a maximum value in an array; -#X text 531 112 \$2 arrayLength; -#X obj 292 10 inlet; -#X text 425 146 inlets:; -#X text 473 144 1 bang to find the maximum; -#X text 475 157 2 arrayLength; -#X text 407 90 creation arguments: \$1 arrayName; -#X obj 246 38 \$2; -#X obj 202 40 bang; -#X obj 230 65 f; -#X obj 224 6 loadbang; -#X text 444 216 outlets: 1 maximum value; -#X text 498 231 2 index of the maximum value; -#X msg 276 141 -1e+15; -#X obj 222 142 t f f f; -#X floatatom 158 266 5 0 0 0 - - -, f 5; -#X obj 332 302 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 --1 -1; -#X obj 288 253 select 127; -#X floatatom 301 324 5 0 0 0 - - -, f 5; -#X text 362 256 heavy does not support the second inlet of select so -I have to hard code 127 in here; -#X obj 223 110 countTo; -#X connect 0 0 1 0; -#X connect 0 0 2 0; -#X connect 0 0 6 1; -#X connect 0 0 28 0; -#X connect 1 0 0 1; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 4 0 5 1; -#X connect 4 0 31 0; -#X connect 5 0 9 0; -#X connect 6 0 8 0; -#X connect 7 0 6 0; -#X connect 7 1 5 0; -#X connect 10 0 21 0; -#X connect 11 0 0 0; -#X connect 12 0 33 0; -#X connect 12 2 26 0; -#X connect 15 0 22 1; -#X connect 20 0 22 1; -#X connect 21 0 22 0; -#X connect 22 0 12 0; -#X connect 23 0 20 0; -#X connect 26 0 0 1; -#X connect 27 0 30 0; -#X connect 27 1 11 0; -#X connect 27 2 4 1; -#X connect 30 0 7 0; -#X connect 30 0 29 0; -#X connect 33 0 27 0;
--- a/examples/pd/hello-midi/mono.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -#N canvas 69 182 1020 452 10; -#N canvas 0 23 450 278 (subpatch) 0; -#X array \$0-activeNotes 127 float 2; -#X coords 0 100 127 -1 200 140 1 0 0; -#X restore 537 25 graph; -#N canvas 89 91 450 300 resetArray 1; -#X obj 121 145 tabwrite \$0-activeNotes; -#X msg 123 115 -0.5; -#X obj 154 90 t b f; -#X msg 129 45 128; -#X obj 103 14 inlet; -#X text 212 71 countto; -#X obj 153 69 countTo; -#X connect 1 0 0 0; -#X connect 2 0 1 0; -#X connect 2 1 0 1; -#X connect 3 0 6 0; -#X connect 4 0 3 0; -#X connect 6 0 2 0; -#X restore 83 49 pd resetArray; -#X obj 83 3 loadbang; -#X obj 88 25 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 --1; -#X obj 39 188 maxArray \$0-activeNotes 128; -#X obj 183 219 f; -#X obj 39 237 >= 0; -#X floatatom 148 313 5 0 0 0 - - -, f 5; -#X obj 70 262 select 1; -#X obj 366 87 f; -#X obj 426 60 f; -#X text 334 39 note; -#X text 424 16 velocity; -#X obj 423 87 > 0; -#X obj 344 281 tabwrite \$0-activeNotes; -#X obj 330 207 f; -#X floatatom 303 178 5 0 0 0 - - -, f 5; -#X obj 265 163 f; -#X obj 304 150 + 1; -#X msg 277 130 -1; -#X msg 371 207 -0.5; -#X obj 400 116 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 -1; -#X obj 367 137 spigot; -#X obj 447 134 spigot; -#X obj 460 86 == 0; -#X obj 470 109 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 -1; -#X obj 434 163 t b f; -#X obj 337 60 inlet; -#X obj 426 32 inlet; -#X obj 148 350 outlet; -#X obj 275 89 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 --1; -#X obj 41 163 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 --1; -#X obj 363 172 t b f; -#X obj 334 240 t b f; -#X text 578 211 pass in velocity/note pairs (velocity first) and obtain -as an output the most recent note still active; -#X text 581 268 outlet 2 gate; -#X obj 330 366 outlet; -#X text 583 251 outlet 1 most recent note active (-1 otherwise); -#X text 155 329 most recent note active; -#X msg 338 338 0; -#X msg 378 339 1; -#X connect 2 0 3 0; -#X connect 3 0 1 0; -#X connect 3 0 19 0; -#X connect 4 0 6 0; -#X connect 4 1 5 1; -#X connect 5 0 7 0; -#X connect 5 0 40 0; -#X connect 6 0 8 0; -#X connect 7 0 29 0; -#X connect 8 0 5 0; -#X connect 8 1 39 0; -#X connect 9 0 22 0; -#X connect 9 0 23 0; -#X connect 10 0 13 0; -#X connect 10 0 24 0; -#X connect 13 0 21 0; -#X connect 15 0 33 0; -#X connect 16 0 15 1; -#X connect 17 0 18 0; -#X connect 18 0 16 0; -#X connect 18 0 17 1; -#X connect 19 0 17 1; -#X connect 20 0 33 0; -#X connect 21 0 22 1; -#X connect 22 0 32 0; -#X connect 23 0 26 0; -#X connect 24 0 25 0; -#X connect 25 0 23 1; -#X connect 26 0 20 0; -#X connect 26 1 14 1; -#X connect 27 0 9 0; -#X connect 28 0 10 0; -#X connect 28 0 30 0; -#X connect 30 0 17 0; -#X connect 31 0 4 0; -#X connect 32 0 15 0; -#X connect 32 1 14 1; -#X connect 33 0 31 0; -#X connect 33 1 14 0; -#X connect 39 0 36 0; -#X connect 40 0 36 0;
--- a/examples/pd/hello-world/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -#N canvas 275 573 461 212 10; -#X obj 39 143 dac~ 1 2; -#X text 35 32 Hello world!; -#X text 35 42 ============; -#X text 95 79 (the sweet sound of success); -#X obj 39 102 *~ 0.1; -#X obj 39 81 osc~ 440; -#X text 238 160 ---------------------------------; -#X text 238 150 @krighxz / BELA / heavy / 12/2015; -#X text 262 169 beaglert.cc / enzienaudio.com; -#X connect 4 0 0 1; -#X connect 4 0 0 0; -#X connect 5 0 4 0;
--- a/examples/pd/karplusStrong/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -#N canvas 440 516 715 490 10; -#X obj 38 370 dac~ 1 2; -#X text 470 442 ---------------------------------; -#X text 470 432 @krighxz / BELA / heavy / 12/2015; -#X text 494 451 beaglert.cc / enzienaudio.com; -#X text 33 22 Karplus Strong; -#X text 33 32 ==============; -#X obj 38 323 vd~ \$0-wg1; -#X obj 118 345 lop~ 1000; -#X obj 118 367 *~ 0.99; -#X obj 118 389 s~ \$0-fb1; -#X obj 38 94 adc~ 3; -#X obj 38 116 hip~ 100; -#X obj 98 176 r~ \$0-fb1; -#X obj 38 198 delwrite~ \$0-wg1 100; -#X obj 38 268 *~; -#X obj 38 290 *~ 10; -#X text 99 116 <<< centre (i.e. DC block) signal with high-pass filter -; -#X text 100 94 <<< use accelerometer \, piezo or FSR on first analog -in; -#X text 105 245 <<< use potentiometer or fader on second analog in -; -#X text 100 75 EXCITATION INPUT:; -#X text 100 225 DELAY PERIOD:; -#X text 182 365 <<< and decay here [0-0.9999]; -#X text 182 345 <<< set damping here [~100-20000]; -#N canvas 335 566 461 274 gate 0; -#N canvas 0 22 450 278 (subpatch) 0; -#X array \$0-xfer 1024 float 3; -#A 0 0 -0.808242 -0.804734 -0.801234 -0.797741 -0.794256 -0.790778 --0.787309 -0.783846 -0.780392 -0.776945 -0.773506 -0.770074 -0.76665 --0.763233 -0.759824 -0.756423 -0.75303 -0.749644 -0.746266 -0.742895 --0.739532 -0.736176 -0.732829 -0.729488 -0.726156 -0.722831 -0.719514 --0.716204 -0.712902 -0.709608 -0.706321 -0.703042 -0.69977 -0.696507 --0.69325 -0.690002 -0.686761 -0.683527 -0.680302 -0.677084 -0.673873 --0.67067 -0.667475 -0.664288 -0.661108 -0.657935 -0.654771 -0.651614 --0.648464 -0.645323 -0.642188 -0.639062 -0.635943 -0.632832 -0.629728 --0.626632 -0.623544 -0.620463 -0.61739 -0.614324 -0.611266 -0.608216 --0.605174 -0.602139 -0.599111 -0.596092 -0.59308 -0.590075 -0.587078 --0.584089 -0.581107 -0.578134 -0.575167 -0.572209 -0.569257 -0.566314 --0.563378 -0.56045 -0.55753 -0.554617 -0.551711 -0.548814 -0.545924 --0.543041 -0.540167 -0.537299 -0.53444 -0.531588 -0.528744 -0.525907 --0.523078 -0.520257 -0.517443 -0.514637 -0.511839 -0.509048 -0.506265 --0.503489 -0.500721 -0.497961 -0.495208 -0.492463 -0.489726 -0.486996 --0.484274 -0.481559 -0.478852 -0.476153 -0.473461 -0.470777 -0.468101 --0.465432 -0.462771 -0.460117 -0.457472 -0.454833 -0.452203 -0.44958 --0.446964 -0.444357 -0.441757 -0.439164 -0.436579 -0.434002 -0.431432 --0.42887 -0.426316 -0.42377 -0.42123 -0.418699 -0.416175 -0.413659 --0.41115 -0.40865 -0.406156 -0.403671 -0.401193 -0.398722 -0.396259 --0.393804 -0.391357 -0.388917 -0.386485 -0.38406 -0.381643 -0.379234 --0.376832 -0.374438 -0.372051 -0.369673 -0.367301 -0.364938 -0.362582 --0.360233 -0.357893 -0.35556 -0.353234 -0.350916 -0.348606 -0.346304 --0.344009 -0.341721 -0.339442 -0.33717 -0.334905 -0.332649 -0.330399 --0.328158 -0.325924 -0.323698 -0.321479 -0.319268 -0.317065 -0.314869 --0.312681 -0.3105 -0.308328 -0.306162 -0.304005 -0.301855 -0.299713 --0.297578 -0.295451 -0.293331 -0.291219 -0.289115 -0.287019 -0.28493 --0.282848 -0.280775 -0.278709 -0.27665 -0.2746 -0.272556 -0.270521 --0.268493 -0.266473 -0.26446 -0.262455 -0.260458 -0.258468 -0.256486 --0.254511 -0.252545 -0.250585 -0.248634 -0.24669 -0.244753 -0.242825 --0.240904 -0.23899 -0.237084 -0.235186 -0.233296 -0.231413 -0.229537 --0.22767 -0.22581 -0.223957 -0.222112 -0.220275 -0.218446 -0.216624 --0.21481 -0.213003 -0.211204 -0.209413 -0.207629 -0.205853 -0.204084 --0.202323 -0.20057 -0.198824 -0.197086 -0.195356 -0.193633 -0.191918 --0.190211 -0.188511 -0.186819 -0.185134 -0.183457 -0.181788 -0.180126 --0.178472 -0.176826 -0.175187 -0.173556 -0.171932 -0.170316 -0.168708 --0.167108 -0.165515 -0.163929 -0.162351 -0.160781 -0.159219 -0.157664 --0.156117 -0.154577 -0.153045 -0.151521 -0.150004 -0.148495 -0.146993 --0.1455 -0.144013 -0.142535 -0.141064 -0.139601 -0.138145 -0.136697 --0.135256 -0.133824 -0.132398 -0.130981 -0.129571 -0.128169 -0.126774 --0.125387 -0.124008 -0.122636 -0.121272 -0.119915 -0.118566 -0.117225 --0.115891 -0.114565 -0.113247 -0.111936 -0.110633 -0.109338 -0.10805 --0.10677 -0.105497 -0.104232 -0.102975 -0.101725 -0.100483 -0.0992487 --0.0980219 -0.0968027 -0.0955911 -0.0943872 -0.0931909 -0.0920023 -0.0908212 --0.0896478 -0.0884821 -0.0873239 -0.0861734 -0.0850305 -0.0838953 -0.0827676 --0.0816476 -0.0805353 -0.0794305 -0.0783334 -0.077244 -0.0761621 -0.0750879 --0.0740213 -0.0729623 -0.071911 -0.0708673 -0.0698312 -0.0688028 -0.067782 --0.0667688 -0.0657632 -0.0647653 -0.063775 -0.0627924 -0.0618173 -0.0608499 --0.0598901 -0.058938 -0.0579935 -0.0570566 -0.0561273 -0.0552057 -0.0542917 --0.0533853 -0.0524866 -0.0515955 -0.050712 -0.0498361 -0.0489679 -0.0481073 --0.0472543 -0.046409 -0.0455713 -0.0447412 -0.0439188 -0.0431039 -0.0422968 --0.0414972 -0.0407053 -0.039921 -0.0391443 -0.0383752 -0.0376138 -0.03686 --0.0361139 -0.0353754 -0.0346445 -0.0339212 -0.0332056 -0.0324976 -0.0317972 --0.0311044 -0.0304193 -0.0297418 -0.029072 -0.0284097 -0.0277551 -0.0271082 --0.0264688 -0.0258371 -0.025213 -0.0245966 -0.0239877 -0.0233865 -0.022793 --0.022207 -0.0216287 -0.021058 -0.020495 -0.0199396 -0.0193918 -0.0188516 --0.0183191 -0.0177942 -0.0172769 -0.0167673 -0.0162653 -0.0157709 -0.0152841 --0.014805 -0.0143335 -0.0138696 -0.0134134 -0.0129648 -0.0125238 -0.0120905 --0.0116647 -0.0112466 -0.0108362 -0.0104333 -0.0100381 -0.00965057 --0.00927063 -0.00889832 -0.00853363 -0.00817657 -0.00782715 -0.00748535 --0.00715118 -0.00682465 -0.00650574 -0.00619446 -0.00589081 -0.00559479 --0.0053064 -0.00502563 -0.0047525 -0.004487 -0.00422913 -0.00397888 --0.00373627 -0.00350128 -0.00327393 -0.0030542 -0.0028421 -0.00263763 --0.0024408 -0.00225159 -0.00207001 -0.00189606 -0.00172974 -0.00157104 --0.00141998 -0.00127655 -0.00114075 -0.00101257 -0.000892029 -0.000779114 --0.000673828 -0.000576172 -0.000486145 -0.000403747 -0.000328979 -0.000261841 --0.000202332 -0.000150452 -0.000106201 -6.95801e-05 -4.05884e-05 -1.92261e-05 --5.49316e-06 0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 --0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 -0 --0 -0 -0 -0 -0 -0 -0 -0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5.49316e-06 -1.92261e-05 4.05884e-05 6.95801e-05 0.000106201 0.000150452 0.000202332 -0.000261841 0.000328979 0.000403747 0.000486145 0.000576172 0.000673828 -0.000779114 0.000892029 0.00101257 0.00114075 0.00127655 0.00141998 -0.00157104 0.00172974 0.00189606 0.00207001 0.00225159 0.0024408 0.00263763 -0.0028421 0.0030542 0.00327393 0.00350128 0.00373627 0.00397888 0.00422913 -0.004487 0.0047525 0.00502563 0.0053064 0.00559479 0.00589081 0.00619446 -0.00650574 0.00682465 0.00715118 0.00748535 0.00782715 0.00817657 0.00853363 -0.00889832 0.00927063 0.00965057 0.0100381 0.0104333 0.0108362 0.0112466 -0.0116647 0.0120905 0.0125238 0.0129648 0.0134134 0.0138696 0.0143335 -0.014805 0.0152841 0.0157709 0.0162653 0.0167673 0.0172769 0.0177942 -0.0183191 0.0188516 0.0193918 0.0199396 0.020495 0.021058 0.0216287 -0.022207 0.022793 0.0233865 0.0239877 0.0245966 0.025213 0.0258371 -0.0264688 0.0271082 0.0277551 0.0284097 0.029072 0.0297418 0.0304193 -0.0311044 0.0317972 0.0324976 0.0332056 0.0339212 0.0346445 0.0353754 -0.0361139 0.03686 0.0376138 0.0383752 0.0391443 0.039921 0.0407053 -0.0414972 0.0422968 0.0431039 0.0439188 0.0447412 0.0455713 0.046409 -0.0472543 0.0481073 0.0489679 0.0498361 0.050712 0.0515955 0.0524866 -0.0533853 0.0542917 0.0552057 0.0561273 0.0570566 0.0579935 0.058938 -0.0598901 0.0608499 0.0618173 0.0627924 0.063775 0.0647653 0.0657632 -0.0667688 0.067782 0.0688028 0.0698312 0.0708673 0.071911 0.0729623 -0.0740213 0.0750879 0.0761621 0.077244 0.0783334 0.0794305 0.0805353 -0.0816476 0.0827676 0.0838953 0.0850305 0.0861734 0.0873239 0.0884821 -0.0896478 0.0908212 0.0920023 0.0931909 0.0943872 0.0955911 0.0968027 -0.0980219 0.0992487 0.100483 0.101725 0.102975 0.104232 0.105497 0.10677 -0.10805 0.109338 0.110633 0.111936 0.113247 0.114565 0.115891 0.117225 -0.118566 0.119915 0.121272 0.122636 0.124008 0.125387 0.126774 0.128169 -0.129571 0.130981 0.132398 0.133824 0.135256 0.136697 0.138145 0.139601 -0.141064 0.142535 0.144013 0.1455 0.146993 0.148495 0.150004 0.151521 -0.153045 0.154577 0.156117 0.157664 0.159219 0.160781 0.162351 0.163929 -0.165515 0.167108 0.168708 0.170316 0.171932 0.173556 0.175187 0.176826 -0.178472 0.180126 0.181788 0.183457 0.185134 0.186819 0.188511 0.190211 -0.191918 0.193633 0.195356 0.197086 0.198824 0.20057 0.202323 0.204084 -0.205853 0.207629 0.209413 0.211204 0.213003 0.21481 0.216624 0.218446 -0.220275 0.222112 0.223957 0.22581 0.22767 0.229537 0.231413 0.233296 -0.235186 0.237084 0.23899 0.240904 0.242825 0.244753 0.24669 0.248634 -0.250585 0.252545 0.254511 0.256486 0.258468 0.260458 0.262455 0.26446 -0.266473 0.268493 0.270521 0.272556 0.2746 0.27665 0.278709 0.280775 -0.282848 0.28493 0.287019 0.289115 0.291219 0.293331 0.295451 0.297578 -0.299713 0.301855 0.304005 0.306162 0.308328 0.3105 0.312681 0.314869 -0.317065 0.319268 0.321479 0.323698 0.325924 0.328158 0.330399 0.332649 -0.334905 0.33717 0.339442 0.341721 0.344009 0.346304 0.348606 0.350916 -0.353234 0.35556 0.357893 0.360233 0.362582 0.364938 0.367301 0.369673 -0.372051 0.374438 0.376832 0.379234 0.381643 0.38406 0.386485 0.388917 -0.391357 0.393804 0.396259 0.398722 0.401193 0.403671 0.406156 0.40865 -0.41115 0.413659 0.416175 0.418699 0.42123 0.42377 0.426316 0.42887 -0.431432 0.434002 0.436579 0.439164 0.441757 0.444357 0.446964 0.44958 -0.452203 0.454833 0.457472 0.460117 0.462771 0.465432 0.468101 0.470777 -0.473461 0.476153 0.478852 0.481559 0.484274 0.486996 0.489726 0.492463 -0.495208 0.497961 0.500721 0.503489 0.506265 0.509048 0.511839 0.514637 -0.517443 0.520257 0.523078 0.525907 0.528744 0.531588 0.53444 0.537299 -0.540167 0.543041 0.545924 0.548814 0.551711 0.554617 0.55753 0.56045 -0.563378 0.566314 0.569257 0.572209 0.575167 0.578134 0.581107 0.584089 -0.587078 0.590075 0.59308 0.596092 0.599111 0.602139 0.605174 0.608216 -0.611266 0.614324 0.61739 0.620463 0.623544 0.626632 0.629728 0.632832 -0.635943 0.639062 0.642188 0.645323 0.648464 0.651614 0.654771 0.657935 -0.661108 0.664288 0.667475 0.67067 0.673873 0.677084 0.680302 0.683527 -0.686761 0.690002 0.69325 0.696507 0.69977 0.703042 0.706321 0.709608 -0.712902 0.716204 0.719514 0.722831; -#A 1000 0.726156 0.729488 0.732829 0.736176 0.739532 0.742895 0.746266 -0.749644 0.75303 0.756423 0.759824 0.763233 0.76665 0.770074 0.773506 -0.776945 0.780392 0.783846 0.787309 0.790778 0.794256 0.797741 0.801234 -0.804734; -#X coords 0 1 1023 -1 200 200 1 0 0; -#X restore 230 34 graph; -#X obj 25 27 inlet~; -#X obj 25 49 clip~ -1 1; -#X obj 25 71 *~ 512; -#X obj 25 93 +~ 512; -#X obj 25 115 tabread4~ \$0-xfer; -#X obj 25 137 outlet~; -#N canvas 0 22 334 332 generate-xfer 0; -#X obj 8 290 tabwrite \$0-xfer; -#X obj 8 109 / 1024; -#X obj 8 129 * 2; -#X obj 8 149 - 1; -#X obj 8 169 moses 0; -#X obj 8 191 + 0.1; -#X obj 8 213 clip -1 0; -#X obj 68 191 - 0.1; -#X obj 68 213 clip 0 1; -#X obj 101 16 inlet threshold; -#X obj 101 78 count 1024; -#X obj 128 58 s \$0-thresh; -#X obj 95 169 r \$0-thresh; -#X obj 101 38 t b f; -#X obj 68 236 *; -#X obj 8 236 *; -#X obj 8 258 * -1; -#X text 140 203 <<< deadzone; -#X text 140 253 <<< smooth by taking exponent; -#X connect 1 0 2 0; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 4 0 5 0; -#X connect 4 1 7 0; -#X connect 5 0 6 0; -#X connect 6 0 15 0; -#X connect 6 0 15 1; -#X connect 7 0 8 0; -#X connect 8 0 14 0; -#X connect 8 0 14 1; -#X connect 9 0 13 0; -#X connect 10 0 0 1; -#X connect 10 0 1 0; -#X connect 12 0 5 1; -#X connect 12 0 7 1; -#X connect 13 0 10 0; -#X connect 13 1 11 0; -#X connect 14 0 0 0; -#X connect 15 0 16 0; -#X connect 16 0 0 0; -#X restore 26 217 pd generate-xfer; -#X text 58 196 <<< threshold; -#X obj 26 173 loadbang; -#X msg 26 195 0.1; -#X connect 1 0 2 0; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 4 0 5 0; -#X connect 5 0 6 0; -#X connect 9 0 10 0; -#X connect 10 0 7 0; -#X restore 38 137 pd gate; -#X obj 38 246 adc~ 10; -#X text 98 137 <<< thresholding to remove any consistent noise in the -excitation signal; -#X connect 6 0 7 0; -#X connect 6 0 0 0; -#X connect 6 0 0 1; -#X connect 7 0 8 0; -#X connect 8 0 9 0; -#X connect 10 0 11 0; -#X connect 11 0 23 0; -#X connect 12 0 13 0; -#X connect 14 0 15 0; -#X connect 15 0 6 0; -#X connect 23 0 13 0; -#X connect 24 0 14 0; -#X connect 24 0 14 1;
--- a/examples/pd/karplusStrong/count.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#N canvas 592 177 306 227 10; -#X obj 32 111 f; -#X obj 57 111 + 1; -#X obj 57 151 sel 0; -#X obj 57 171 del 1e-36; -#X obj 57 131 > 1023; -#X msg 32 90 0; -#X obj 19 171 - 1; -#X obj 19 193 outlet; -#X obj 90 87 \$1; -#X obj 90 109 - 1; -#X obj 90 66 loadbang; -#X obj 32 48 inlet; -#X obj 32 69 t b; -#X text 33 14 temporary replacement for [until] object; -#X text 67 195 outputs index (0->[N-1]); -#X connect 0 0 1 0; -#X connect 1 0 0 1; -#X connect 1 0 4 0; -#X connect 1 0 6 0; -#X connect 2 0 3 0; -#X connect 3 0 0 0; -#X connect 4 0 2 0; -#X connect 5 0 0 0; -#X connect 6 0 7 0; -#X connect 8 0 9 0; -#X connect 9 0 4 1; -#X connect 10 0 8 0; -#X connect 11 0 12 0; -#X connect 12 0 5 0;
--- a/examples/pd/rubberDuckie/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,247 +0,0 @@ -#N canvas 275 573 442 207 10; -#X obj 39 149 dac~ 1 2; -#X text 218 143 ---------------------------------; -#X text 218 133 @krighxz / BELA / heavy / 12/2015; -#X text 242 152 beaglert.cc / enzienaudio.com; -#X text 35 32 Rubber Duckie; -#X text 35 42 =============; -#N canvas 325 86 823 605 duckie 0; -#X obj 186 510 *~; -#X obj 306 517 *~; -#X obj 372 468 noise~; -#X obj 372 492 bp~ 3000 10; -#X obj 366 162 abs~; -#X obj 509 158 sig~ 0; -#X obj 467 371 +~; -#X obj 411 210 -~ 0.55; -#X obj 411 231 /~ 0.2; -#X obj 411 252 clip~ 0 1; -#X obj 411 282 *~; -#X obj 411 308 *~ 1000; -#X obj 366 334 +~; -#X obj 366 308 +~ 800; -#X obj 186 536 *~ 0.2; -#X obj 366 282 *~ 800; -#N canvas 568 775 135 226 <~ 0; -#X obj 20 -43 -~; -#X obj 20 27 +~ 1e-37; -#X obj 20 6 clip~ -1e-37 0; -#X obj 20 -88 inlet~; -#X obj 64 -87 inlet~; -#X obj 20 -64 max~; -#X obj 20 -19 *~ -1; -#X obj 20 79 outlet~; -#X obj 20 48 *~ 1e+37; -#X connect 0 0 6 0; -#X connect 1 0 8 0; -#X connect 2 0 1 0; -#X connect 3 0 5 0; -#X connect 4 0 0 1; -#X connect 4 0 5 1; -#X connect 5 0 0 0; -#X connect 6 0 2 0; -#X connect 8 0 7 0; -#X restore 186 367 pd <~ 0; -#N canvas 568 775 135 226 <~ 0; -#X obj 20 -43 -~; -#X obj 20 27 +~ 1e-37; -#X obj 20 6 clip~ -1e-37 0; -#X obj 20 -88 inlet~; -#X obj 64 -87 inlet~; -#X obj 20 -64 max~; -#X obj 20 -19 *~ -1; -#X obj 20 79 outlet~; -#X obj 20 48 *~ 1e+37; -#X connect 0 0 6 0; -#X connect 1 0 8 0; -#X connect 2 0 1 0; -#X connect 3 0 5 0; -#X connect 4 0 0 1; -#X connect 4 0 5 1; -#X connect 5 0 0 0; -#X connect 6 0 2 0; -#X connect 8 0 7 0; -#X restore 482 181 pd <~; -#X obj 186 428 *~; -#X obj 225 345 sig~ 1; -#X obj 186 394 lop~ 10; -#X text 524 393 << band-limited pulse; -#X text 10 367 reed stops when overblown >>; -#X obj 186 460 *~; -#X obj 186 480 *~; -#X text 25 470 exp amplitude response >>; -#X text 537 238 << detune frequency on change of direction; -#X obj 482 236 *~ -300; -#X obj 306 485 *~; -#X obj 306 449 *~ 0.1; -#X text 448 493 << noise simulates non-oscillating airflow when overblown -; -#X obj 186 561 outlet~; -#N canvas 58 1286 407 525 pulse 0; -#X obj 83 340 *~; -#X obj 83 366 *~; -#X obj 31 366 sig~ 1; -#X obj 52 419 /~; -#X obj 67 393 +~; -#X text 116 366 X^2; -#X text 97 396 1+X^2; -#X text 84 421 1/(1+X^2); -#X obj 83 317 osc~; -#X obj 167 320 clip~ 0 999999; -#X obj 52 483 outlet~; -#X text 271 218 << tweak all this; -#X text 25 14 based on F04.waveshaping.pulse.pd; -#X obj 83 84 /~ 2; -#X obj 167 148 -~; -#X obj 167 170 /~ 127; -#X obj 52 452 hip~ 5; -#X obj 167 202 *~; -#X obj 167 232 *~; -#X obj 167 262 *~; -#X obj 167 294 *~ 1000; -#X obj 118 125 sig~ 139; -#X obj 83 58 inlet~; -#N canvas 331 1377 215 174 _ftom 0; -#X obj -482 -776 tabread4~ _ftom; -#X obj -482 -818 /~ 10000; -#X obj -482 -797 *~ 256; -#N canvas 0 23 450 278 (subpatch) 0; -#X array _ftom 256 float 3; -#A 0 0 27.0762 39.0762 46.0958 51.0762 54.9394 58.0958 60.7645 63.0762 -65.1153 66.9394 68.5894 70.0958 71.4815 72.7645 73.9589 75.0762 76.1258 -77.1153 78.0514 78.9394 79.784 80.5894 81.359 82.0958 82.8025 83.4815 -84.1349 84.7645 85.372 85.9589 86.5266 87.0762 87.609 88.1258 88.6276 -89.1153 89.5897 90.0514 90.5011 90.9394 91.3669 91.784 92.1914 92.5894 -92.9785 93.359 93.7313 94.0958 94.4528 94.8025 95.1453 95.4815 95.8113 -96.1349 96.4525 96.7645 97.0709 97.372 97.6679 97.9589 98.2451 98.5266 -98.8036 99.0762 99.3446 99.609 99.8693 100.126 100.379 100.628 100.873 -101.115 101.354 101.59 101.822 102.051 102.278 102.501 102.722 102.939 -103.154 103.367 103.577 103.784 103.989 104.191 104.392 104.589 104.785 -104.978 105.17 105.359 105.546 105.731 105.914 106.096 106.275 106.453 -106.629 106.803 106.975 107.145 107.314 107.482 107.647 107.811 107.974 -108.135 108.294 108.453 108.609 108.764 108.918 109.071 109.222 109.372 -109.521 109.668 109.814 109.959 110.103 110.245 110.386 110.527 110.666 -110.804 110.94 111.076 111.211 111.345 111.477 111.609 111.74 111.869 -111.998 112.126 112.253 112.379 112.504 112.628 112.751 112.873 112.995 -113.115 113.235 113.354 113.472 113.59 113.706 113.822 113.937 114.051 -114.165 114.278 114.39 114.501 114.612 114.722 114.831 114.939 115.047 -115.154 115.261 115.367 115.472 115.577 115.681 115.784 115.887 115.989 -116.09 116.191 116.292 116.392 116.491 116.589 116.688 116.785 116.882 -116.978 117.074 117.17 117.265 117.359 117.453 117.546 117.639 117.731 -117.823 117.915 118.005 118.096 118.186 118.275 118.364 118.453 118.541 -118.629 118.716 118.803 118.889 118.975 119.06 119.145 119.23 119.314 -119.398 119.482 119.565 119.647 119.729 119.811 119.893 119.974 120.055 -120.135 120.215 120.294 120.374 120.453 120.531 120.609 120.687 120.764 -120.842 120.918 120.995 121.071 121.147 121.222 121.297 121.372 121.446 -121.521 121.594 121.668 121.741 121.814 121.887 121.959 122.031 122.103 -122.174 122.245 122.316 122.386 122.457 122.527 122.596 122.666 122.735 -122.804 122.872 122.94 123.008; -#X coords 0 127 256 -12 50 50 1 0 0; -#X restore -546 -793 graph; -#X obj -482 -838 clip~ 0 10000; -#X obj -482 -858 inlet~; -#X obj -482 -755 outlet~; -#X text -567 -722 shoddy temp replacement for ftom~; -#X connect 0 0 6 0; -#X connect 1 0 2 0; -#X connect 2 0 0 0; -#X connect 4 0 1 0; -#X connect 5 0 4 0; -#X restore 182 125 pd _ftom; -#X connect 0 0 1 0; -#X connect 0 0 1 1; -#X connect 1 0 4 1; -#X connect 2 0 3 0; -#X connect 2 0 4 0; -#X connect 3 0 16 0; -#X connect 4 0 3 1; -#X connect 8 0 0 0; -#X connect 9 0 0 1; -#X connect 13 0 8 0; -#X connect 13 0 23 0; -#X connect 14 0 15 0; -#X connect 15 0 17 0; -#X connect 15 0 17 1; -#X connect 16 0 10 0; -#X connect 17 0 18 0; -#X connect 17 0 18 1; -#X connect 18 0 19 0; -#X connect 18 0 19 1; -#X connect 19 0 20 0; -#X connect 20 0 9 0; -#X connect 21 0 14 0; -#X connect 22 0 13 0; -#X connect 23 0 14 1; -#X restore 467 394 pd pulse; -#X obj 366 105 inlet~; -#X text 295 104 airflow >>; -#X text 218 118 ('squeeze pressure'); -#X text 13 20 Sound model of a rubber duckie toy; -#X text 14 51 Hint: use the differential of a continuous signal as -input for a realistic response; -#X text 13 29 ==================================; -#X obj 366 133 lop~ 0.5; -#X text 423 132 << airflow resistance; -#X connect 0 0 14 0; -#X connect 1 0 14 0; -#X connect 2 0 3 0; -#X connect 3 0 1 1; -#X connect 4 0 7 0; -#X connect 4 0 15 0; -#X connect 4 0 29 0; -#X connect 4 0 18 1; -#X connect 4 0 16 0; -#X connect 5 0 17 1; -#X connect 6 0 32 0; -#X connect 7 0 8 0; -#X connect 8 0 9 0; -#X connect 9 0 10 0; -#X connect 9 0 10 1; -#X connect 10 0 11 0; -#X connect 11 0 12 1; -#X connect 12 0 6 0; -#X connect 13 0 12 0; -#X connect 14 0 31 0; -#X connect 15 0 13 0; -#X connect 16 0 20 0; -#X connect 17 0 27 0; -#X connect 18 0 23 0; -#X connect 18 0 23 1; -#X connect 19 0 16 1; -#X connect 20 0 18 0; -#X connect 23 0 24 1; -#X connect 23 0 24 0; -#X connect 24 0 0 0; -#X connect 27 0 6 1; -#X connect 28 0 1 0; -#X connect 29 0 28 1; -#X connect 29 0 28 0; -#X connect 32 0 0 1; -#X connect 33 0 39 0; -#X connect 39 0 4 0; -#X connect 39 0 17 0; -#X restore 39 127 pd duckie; -#X obj 39 77 adc~ 10; -#N canvas 0 22 504 229 differential 0; -#X obj 27 80 rzero~ 1; -#X obj 72 57 sig~ 1; -#X obj 27 152 *~ 44100; -#X obj 72 131 samplerate~; -#X obj 72 110 loadbang; -#X obj 27 25 inlet~; -#X obj 27 190 outlet~; -#X text 84 83 y[n] = x[n] - x[n-1]; -#X text 121 57 <<< heavy currently requires signal input to set coefficient -; -#X text 91 151 <<< multiply by samplerate to get velocity; -#X connect 0 0 2 0; -#X connect 1 0 0 1; -#X connect 2 0 6 0; -#X connect 3 0 2 1; -#X connect 4 0 3 0; -#X connect 5 0 0 0; -#X restore 39 101 pd differential; -#X connect 6 0 0 0; -#X connect 6 0 0 1; -#X connect 7 0 8 0; -#X connect 8 0 6 0;
--- a/examples/pd/samphold/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -#N canvas 275 504 414 247 10; -#X obj 55 212 dac~ 1 2; -#X obj 55 171 *~ 0.1; -#X obj 55 150 osc~ 440; -#X obj 55 61 noise~; -#X obj 55 128 samphold~; -#X text 51 21 ==================; -#X text 51 11 Sample and hold FM; -#X obj 55 85 lop~ 1; -#X obj 122 107 phasor~ 880; -#X obj 55 107 *~ 1e+06; -#X text 193 199 ---------------------------------; -#X text 193 189 @krighxz / BELA / heavy / 12/2015; -#X text 217 208 beaglert.cc / enzienaudio.com; -#X connect 1 0 0 1; -#X connect 1 0 0 0; -#X connect 2 0 1 0; -#X connect 3 0 7 0; -#X connect 4 0 2 0; -#X connect 7 0 9 0; -#X connect 8 0 4 1; -#X connect 9 0 4 0;
--- a/examples/pd/simple-fm/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -#N canvas 275 573 409 282 10; -#X obj 37 230 dac~ 1 2; -#X text 175 222 ---------------------------------; -#X obj 37 102 *~ 1000; -#X obj 37 199 *~ 0.1; -#X obj 37 79 adc~ 3; -#X obj 65 125 adc~ 4; -#X obj 94 147 adc~ 5; -#N canvas 81 574 322 252 FMvoice 1; -#X obj 20 174 +~; -#X obj 93 116 osc~; -#X obj 93 157 *~; -#X obj 93 76 *~; -#X obj 158 98 *~; -#X obj 20 225 outlet~; -#X obj 20 200 osc~; -#X obj 20 39 inlet~ freq; -#X obj 108 39 inlet~ harmRatio~; -#X obj 173 69 inlet~ modIndex~; -#X connect 0 0 6 0; -#X connect 1 0 2 0; -#X connect 2 0 0 1; -#X connect 3 0 4 0; -#X connect 3 0 1 0; -#X connect 4 0 2 1; -#X connect 6 0 5 0; -#X connect 7 0 3 0; -#X connect 7 0 0 0; -#X connect 8 0 3 1; -#X connect 9 0 4 1; -#X restore 37 169 pd FMvoice; -#X text 33 22 Simple FM; -#X text 33 32 =========; -#X text 175 212 @krighxz / BELA / heavy / 12/2015; -#X text 199 231 beaglert.cc / enzienaudio.com; -#X connect 2 0 7 0; -#X connect 3 0 0 1; -#X connect 3 0 0 0; -#X connect 4 0 2 0; -#X connect 5 0 7 1; -#X connect 6 0 7 2; -#X connect 7 0 3 0;
--- a/examples/pd/tableScrubbing/_main.pd Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -#N canvas 503 319 861 473 10; -#N canvas 0 22 450 278 (subpatch) 0; -#X array exampleTable 65238 float 2; -#X coords 0 1 65238 -1 200 140 1 0 0; -#X restore 21 213 graph; -#X obj 243 329 adc~ 1 2 3; -#X obj 300 426 dac~; -#X text 317 264 <<< delete this object before compiling!; -#X obj 300 392 tabread4~ exampleTable; -#X msg 243 218 read -resize rt.wav exampleTable; -#X obj 300 350 lop~ 1; -#X obj 300 371 *~ 65238; -#X obj 243 266 soundfiler; -#X text 489 229 right-click array -> properties -> toggle "save contents" -; -#X text 463 216 <<< after loading a file:; -#X text 17 23 Load sample into table and scrub using analog input; -#X text 17 33 ===================================================; -#X text 362 351 <<< avoid zipper noise; -#X text 362 371 <<< length of sample; -#X text 317 328 <<< analog input 0 (range 0-1); -#X text 631 419 ---------------------------------; -#X text 631 409 @krighxz / BELA / heavy / 12/2015; -#X text 655 428 beaglert.cc / enzienaudio.com; -#X text 30 61 N.B. the patch cannot be bigger than 512kb in size \; -only use this for *very small soundfiles*; -#X text 29 99 You can modify the render.cpp file to load samples into -tables using the Heavy API: https://enzienaudio.com/docs/c.html#api-hv-table -; -#X connect 1 2 6 0; -#X connect 4 0 2 0; -#X connect 4 0 2 1; -#X connect 5 0 8 0; -#X connect 6 0 7 0; -#X connect 7 0 4 0;
--- a/examples/samples/SampleData.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* - * SampleData.h - * - * Created on: Nov 5, 2014 - * Author: Victor Zappi - */ - -#ifndef SAMPLEDATA_H_ -#define SAMPLEDATA_H_ - -// User defined structure to pass between main and rendere complex data retrieved from file -struct SampleData { - float *samples; // Samples in file - int sampleLen; // Total nume of samples -}; - - - -#endif /* SAMPLEDATA_H_ */
--- a/examples/samples/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: Andrew McPherson and Victor Zappi - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <string> -#include <getopt.h> -#include <sndfile.h> // to load audio files - -#include <Bela.h> -#include "SampleData.h" - -using namespace std; - -// Load samples from file -int initFile(string file, SampleData *smp)//float *& smp) -{ - SNDFILE *sndfile ; - SF_INFO sfinfo ; - - if (!(sndfile = sf_open (file.c_str(), SFM_READ, &sfinfo))) { - cout << "Couldn't open file " << file << endl; - return 1; - } - - int numChan = sfinfo.channels; - if(numChan != 1) - { - cout << "Error: " << file << " is not a mono file" << endl; - return 1; - } - - smp->sampleLen = sfinfo.frames * numChan; - smp->samples = new float[smp->sampleLen]; - if(smp == NULL){ - cout << "Could not allocate buffer" << endl; - return 1; - } - - int subformat = sfinfo.format & SF_FORMAT_SUBMASK; - int readcount = sf_read_float(sndfile, smp->samples, smp->sampleLen); - - // Pad with zeros in case we couldn't read whole file - for(int k = readcount; k <smp->sampleLen; k++) - smp->samples[k] = 0; - - if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { - double scale ; - int m ; - - sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; - if (scale < 1e-10) - scale = 1.0 ; - else - scale = 32700.0 / scale ; - cout << "File samples scale = " << scale << endl; - - for (m = 0; m < smp->sampleLen; m++) - smp->samples[m] *= scale; - } - - sf_close(sndfile); - - return 0; -} - - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - //rt_task_delete ((RT_TASK *) &gTriggerSamplesTask); - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --file [-f] filename: Name of the file to load (default is \"sample.wav\")\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - string fileName; // Name of the sample to load - - SampleData sampleData; // User define structure to pass data retrieved from file to render function - sampleData.samples = 0; - sampleData.sampleLen = -1; - - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"file", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'h': - usage(basename(argv[0])); - exit(0); - case 'f': - fileName = string((char *)optarg); - break; - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - if(fileName.empty()){ - fileName = "samples/sample.wav"; - } - - if(settings.verbose) { - cout << "Loading file " << fileName << endl; - } - - // Load file - if(initFile(fileName, &sampleData) != 0) - { - cout << "Error: unable to load samples " << endl; - return -1; - } - - if(settings.verbose) - cout << "File contains " << sampleData.sampleLen << " samples" << endl; - - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, &sampleData) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // All done! - return 0; -}
--- a/examples/samples/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/* - * - * Andrew McPherson and Victor Zappi - * Queen Mary, University of London - */ - -/** -\example 4_audio_samples - -Playback WAV files ------------------- - -This sketch shows how to playback audio samples from a buffer. - -An audio file is loaded into a buffer `SampleData` as `gSampleData`. This is -accessed with a read pointer that is incremented at audio rate within the render -function: `out += gSampleData.samples[gReadPtr++]`. - -Note that the read pointer is stopped from incrementing past the length of the -`gSampleData`. This is achieved by comparing the read pointer value against the -sample length which we can access as follows: `gSampleData.sampleLen`. - -The sample is triggered by keyboard input: (a) starts sample playback, (s) -stops sample playback. The triggering is treated as a lower priority task than -the audio. You can see this at the bottom of the render function: -`Bela_scheduleAuxiliaryTask(gTriggerSamplesTask)`; -*/ - -#include <Bela.h> -#include <cmath> -#include "SampleData.h" - -SampleData gSampleData; // User defined structure to get complex data from main -int gReadPtr; // Position of last read sample from file - -// Task for handling the update of the frequencies using the matrix -AuxiliaryTask gTriggerSamplesTask; - -bool initialise_trigger(); -void trigger_samples(); - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - - // Retrieve a parameter passed in from the initAudio() call - gSampleData = *(SampleData *)userData; - - gReadPtr = -1; - - // Initialise auxiliary tasks - if(!initialise_trigger()) - return false; - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - float out = 0; - - // If triggered... - if(gReadPtr != -1) - out += gSampleData.samples[gReadPtr++]; // ...read each sample... - - if(gReadPtr >= gSampleData.sampleLen) - gReadPtr = -1; - - for(unsigned int channel = 0; channel < context->audioChannels; channel++) - context->audioOut[n * context->audioChannels + channel] = out; // ...and put it in both left and right channel - } - - // Request that the lower-priority task run at next opportunity - Bela_scheduleAuxiliaryTask(gTriggerSamplesTask); -} - -// Initialise the auxiliary task -// and print info - -bool initialise_trigger() -{ - if((gTriggerSamplesTask = Bela_createAuxiliaryTask(&trigger_samples, 50, "bela-trigger-samples")) == 0) - return false; - - rt_printf("Press 'a' to trigger sample, 's' to stop\n"); - rt_printf("Press 'q' to quit\n"); - - return true; -} - -// This is a lower-priority call to periodically read keyboard input -// and trigger samples. By placing it at a lower priority, -// it has minimal effect on the audio performance but it will take longer to -// complete if the system is under heavy audio load. - -void trigger_samples() -{ - // This is not a real-time task! - // Cos getchar is a system call, not handled by Xenomai. - // This task will be automatically down graded. - - char keyStroke = '.'; - - keyStroke = getchar(); - while(getchar()!='\n'); // to read the first stroke - - switch (keyStroke) - { - case 'a': - gReadPtr = 0; - break; - case 's': - gReadPtr = -1; - break; - case 'q': - gShouldStop = true; - break; - default: - break; - } -} - - - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - delete[] gSampleData.samples; -}
--- a/examples/scope_analogue/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/** -\example 3_scope_analog - -Connecting potentiometers -------------------------- - -This example reads from analogue inputs 0 and 1 via `analogReadFrame()` and -generates a sine wave with amplitude and frequency determined by their values. -It's best to connect a 10K potentiometer to each of these analog inputs. Far -left and far right pins of the pot go to 3.3V and GND, the middle should be -connected to the analog in pins. - -The sine wave is then plotted on the oscilloscope. Click the Open Scope button to -view the results. As you turn the potentiometers you will see the amplitude and -frequency of the sine wave change. - -This project also shows as example of `map()` which allows you to re-scale a number -from one range to another. Note that `map()` does not constrain your variable -within the upper and lower limits. If you want to do this use the `constrain()` -function. -*/ - -#include <Bela.h> -#include <cmath> -#include <Scope.h> - -Scope scope; - -float gInverseSampleRate; -float gPhase; - -bool setup(BelaContext *context, void *userData) -{ - - // setup the scope with 3 channels at the audio sample rate - scope.setup(3, context->audioSampleRate); - - gInverseSampleRate = 1.0 / context->audioSampleRate; - gPhase = 0.0; - - return true; -} - -void render(BelaContext *context, void *userData) -{ - - for(unsigned int n = 0; n < context->audioFrames; n++) { - - // read analogIn channels 0 and 1 - float in1 = analogRead(context, n, 0); - float in2 = analogRead(context, n, 1); - - // map in1 to amplitude and in2 to frequency - float amplitude = in1 * 0.8f; - float frequency = map(in2, 0, 1, 100, 1000); - - // generate a sine wave with the amplitude and frequency - float out = amplitude * sinf(gPhase); - gPhase += 2.0 * M_PI * frequency * gInverseSampleRate; - if(gPhase > 2.0 * M_PI) - gPhase -= 2.0 * M_PI; - - // log the sine wave and sensor values on the scope - scope.log(out, in1, in2); - - // pass the sine wave to the audio outputs - for(unsigned int channel = 0; channel < context->audioChannels; channel++) - context->audioOut[n * context->audioChannels + channel] = out; - - } -} - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/scope_basic/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - - */ - -/** -\example 1_scope_basic - -Oscilloscope in-browser ------------------------ - -This example demonstrates the scope feature of the IDE. - -The scope is instantiated at the top of the file via `Scope scope;` - -In `setup()` we define how many channels the scope should have and the sample -rate that it should run at via `scope.setup(3, context->audioSampleRate)`. - -In `render()` we choose what the scope log via `scope.log(out, out2, out3)`. -In this example the scope is logging three sine waves with different phases. To see -the output click on the <b>Open Scope</b> button. - -An additional option is to set the trigger of the oscilloscope from within `render()`. -In this example we are triggering the scope when oscillator 1 becomes less than -oscillator 2 via `scope.trigger()`. Note that this functionality only takes effect -when the triggering mode is set to custom in the scope UI. -*/ - -#include <Bela.h> -#include <Scope.h> -#include <cmath> - -// set the frequency of the oscillators -float gFrequency = 110.0; -float gPhase; -float gInverseSampleRate; - -// instantiate the scope -Scope scope; - -bool setup(BelaContext *context, void *userData) -{ - // tell the scope how many channels and the sample rate - scope.setup(3, context->audioSampleRate); - - gPhase = 0; - gInverseSampleRate = 1.0f/context->audioSampleRate; - - return true; -} - -float lastOut = 0.0; -float lastOut2 = 0.0; -void render(BelaContext *context, void *userData) -{ - // iterate over the audio frames and create three oscillators, seperated in phase by PI/2 - for (unsigned int n=0; n<context->audioFrames; n++){ - float out = 0.8f * sinf(gPhase); - float out2 = 0.8f * sinf(gPhase - M_PI/2); - float out3 = 0.8f * sinf(gPhase + M_PI/2); - gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; - if(gPhase > 2.0 * M_PI) - gPhase -= 2.0 * M_PI; - - // log the three oscillators to the scope - scope.log(out, out2, out3); - - // optional - tell the scope to trigger when oscillator 1 becomes less than oscillator 2 - // note this has no effect unless trigger mode is set to custom in the scope UI - if (lastOut >= lastOut2 && out < out2){ - scope.trigger(); - } - - lastOut = out; - lastOut2 = out2; - } -} - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/stepper/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - - -#include <Bela.h> - -const int kStepLengthSlow = 1000; -const int kStepLengthFast = 500; - -int gStepLengthSamples = kStepLengthSlow; - -const int gPinA1 = P8_27; -const int gPinA2 = P8_28; -const int gPinB1 = P8_29; -const int gPinB2 = P8_30; -const int gPinServo = P9_16; - -int gStepCounter = 0; -int gPhase = 0; - -int gServoCounter = 0; - - -enum { - kStateMoveRight1 = 0, - kStateMoveLeft1, - kStateMoveRight2, - kStateMoveLeft2, - kStateMoveRight3, - kStateMoveLeft3, - kStateSpin, - kStateMax -}; - -int gState = 0; -int gStateCounter = 0; - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - // This project makes the assumption that the audio and digital - // sample rates are the same. But check it to be sure! - if(context->audioFrames != context->digitalFrames) { - rt_printf("Error: this project needs the audio and digital sample rates to be the same.\n"); - return false; - } - - pinMode(context, 0, gPinA1, OUTPUT); - pinMode(context, 0, gPinA2, OUTPUT); - pinMode(context, 0, gPinB1, OUTPUT); - pinMode(context, 0, gPinB2, OUTPUT); - pinMode(context, 0, gPinServo, OUTPUT); - - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - if(gPhase == 0 || gPhase == 1) { - digitalWriteOnce(context, n, gPinB1, HIGH); - digitalWriteOnce(context, n, gPinB2, LOW); - } - else { - digitalWriteOnce(context, n, gPinB1, LOW); - digitalWriteOnce(context, n, gPinB2, HIGH); - } - - if(gPhase == 1 || gPhase == 2) { - digitalWriteOnce(context, n, gPinA1, HIGH); - digitalWriteOnce(context, n, gPinA2, LOW); - } - else { - digitalWriteOnce(context, n, gPinA1, LOW); - digitalWriteOnce(context, n, gPinA2, HIGH); - } - - if(--gServoCounter > 0) - digitalWriteOnce(context, n, gPinServo, HIGH); - else - digitalWriteOnce(context, n, gPinServo, LOW); - - if(++gStepCounter >= gStepLengthSamples) { - gStateCounter++; - - switch(gState) { - case kStateMoveRight1: - case kStateMoveRight2: - case kStateMoveRight3: - gPhase = (gPhase + 1) & 3; - break; - case kStateMoveLeft1: - case kStateMoveLeft2: - case kStateMoveLeft3: - gPhase = (gPhase + 3) & 3; - break; - case kStateSpin: - gPhase = (gPhase + 1) & 3; - break; - } - - if(gState == kStateSpin) { - if(gStateCounter >= 48) { - gStateCounter = 0; - gState = 0; - gStepLengthSamples = kStepLengthSlow; - } - } - else { - if(gStateCounter >= 16) { - gStateCounter = 0; - gState++; - if(gState & 1) - gServoCounter = 120; - else - gServoCounter = 80; - if(gState == kStateSpin) - gStepLengthSamples = kStepLengthFast; - } - } - - gStepCounter = 0; - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - -}
--- a/examples/tank_wars/game.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,339 +0,0 @@ -/* - * game.cpp - * - * Created on: Nov 10, 2014 - * Author: parallels - */ - -#include <cmath> -#include <cstdlib> -#include "vector_graphics.h" -#include <Utilities.h> - -// Virtual screen size -int screenWidth, screenHeight; - -// Basic information on the terrain and the tanks -float *groundLevel; // Y coordinate of the ground for each X coordinate -float tank1X, tank1Y, tank2X, tank2Y; // Positions of the two tanks -float tankRadius = 20; // Radius of the tanks -float cannonLength = 40; // How long the cannon on each tank extends -float gravity = 0.05; // Strength of gravity - -// Current state of the game -int playerHasWon = 0; // 1 if player 1 wins, 2 if player 2 wins, 0 if game in progress -bool player1Turn = true; // true if it's player 1's turn; false otherwise -float tank1CannonAngle = M_PI/2; -float tank2CannonAngle = M_PI/2; // Direction the tank cannons are pointing -float tank1CannonStrength = 3; -float tank2CannonStrength = 3; // Strength of intended projectile launch - -// Location of the projectile -bool projectileInMotion = false; -float projectilePositionX, projectilePositionY; -float projectileVelocityX, projectileVelocityY; - -// Infor needed for sound rendering -bool collisionJustOccurred = false; -bool tankHitJustOccurred = false; - -// Useful utility function for generating random floating-point values -float randomFloat(float low, float hi) -{ - float r = (float)random() / (float)RAND_MAX; - return map(r, 0, 1, low, hi); -} - -// Restart the game, without reallocating memory -void restartGame() -{ - float player1Height = screenHeight * 3/4; // randomFloat(screenHeight/2, screenHeight-5); - float player2Height = screenHeight - 5; // randomFloat(screenHeight/2, screenHeight-5); - for(int i = 0; i < screenWidth * 0.2; i++) { - groundLevel[i] = player1Height; - } - for(int i = screenWidth * 0.2; i < screenWidth * 0.8; i++) { - groundLevel[i] = player1Height + (player2Height - player1Height) * (i - screenWidth*0.2)/(screenWidth*0.6); - } - for(int i = screenWidth * 0.8; i < screenWidth; i++) { - groundLevel[i] = player2Height; - } - - // Set the location of the two tanks so they rest on the ground at opposite sides - tank1X = screenWidth * 0.1; - tank1Y = player1Height; - tank2X = screenWidth * 0.9; - tank2Y = player2Height; - - playerHasWon = 0; - projectileInMotion = false; -} - -// Initialise the game -void setupGame(int width, int height) -{ - // Set the screen size - screenWidth = width; - screenHeight = height; - - // Initialize the ground level - groundLevel = new float[screenWidth]; - - restartGame(); -} - -// Advance the turn to the next player -void nextPlayersTurn() { - player1Turn = !player1Turn; -} - - -// Move forward one frame on the game physics -void nextGameFrame() -{ - if(!projectileInMotion) - return; - - // Update position of projectile - projectilePositionX += projectileVelocityX; - projectilePositionY += projectileVelocityY; - projectileVelocityY += gravity; - - // Check collision with tanks first: a collision with tank 1 means player 2 wins and vice-versa - if((tank1X - projectilePositionX)*(tank1X - projectilePositionX) + - (tank1Y - projectilePositionY)*(tank1Y - projectilePositionY) - <= tankRadius * tankRadius) - { - projectileInMotion = false; - collisionJustOccurred = false; - tankHitJustOccurred = true; - playerHasWon = 2; - } - else if((tank2X - projectilePositionX)*(tank2X - projectilePositionX) + - (tank2Y - projectilePositionY)*(tank2Y - projectilePositionY) - <= tankRadius * tankRadius) - { - projectileInMotion = false; - collisionJustOccurred = false; - tankHitJustOccurred = true; - playerHasWon = 1; - } - else if(projectilePositionX < 0 || projectilePositionX >= screenWidth) { - // Check collision whether projectile has exited the screen to the left or right - projectileInMotion = false; - collisionJustOccurred = true; - nextPlayersTurn(); - } - else if(projectilePositionY >= groundLevel[(int)floorf(projectilePositionX)]) { - // Check for projectile collision with ground - projectileInMotion = false; - collisionJustOccurred = true; - nextPlayersTurn(); - } -} - -// Updates for game state -void setTank1CannonAngle(float angle) -{ - tank1CannonAngle = angle; -} - -void setTank2CannonAngle(float angle) -{ - tank2CannonAngle = angle; -} - -void setTank1CannonStrength(float strength) -{ - tank1CannonStrength = strength; -} - -void setTank2CannonStrength(float strength) -{ - tank2CannonStrength = strength; -} - -// FIRE! -void fireProjectile() -{ - // Can't fire while projectile is already moving, or if someone has won - if(projectileInMotion) - return; - if(playerHasWon != 0) - return; - - if(player1Turn) { - projectilePositionX = tank1X + cannonLength * cosf(tank1CannonAngle); - projectilePositionY = tank1Y - cannonLength * sinf(tank1CannonAngle); - projectileVelocityX = tank1CannonStrength * cosf(tank1CannonAngle); - projectileVelocityY = -tank1CannonStrength * sinf(tank1CannonAngle); - } - else { - projectilePositionX = tank2X + cannonLength * cosf(tank2CannonAngle); - projectilePositionY = tank2Y - cannonLength * sinf(tank2CannonAngle); - projectileVelocityX = tank2CannonStrength * cosf(tank2CannonAngle); - projectileVelocityY = -tank2CannonStrength * sinf(tank2CannonAngle); - } - - // GO! - projectileInMotion = true; -} - -// Game state queries -bool gameStatusPlayer1Turn() -{ - return player1Turn; -} - -bool gameStatusProjectileInMotion() -{ - return projectileInMotion; -} - -int gameStatusWinner() -{ - return playerHasWon; -} - -bool gameStatusCollisionOccurred() -{ - if(collisionJustOccurred) { - collisionJustOccurred = false; - return true; - } - return false; -} - -bool gameStatusTankHitOccurred() -{ - if(tankHitJustOccurred) { - tankHitJustOccurred = false; - return true; - } - return false; -} - - -float gameStatusProjectileHeight() -{ - return projectilePositionY / (float)screenHeight; -} - -// Clean up any allocated memory for the game -void cleanupGame() -{ - delete groundLevel; -} - -// Drawing routines. Arguments are (interleaved) buffer to render -// into, the available size, and the target for how many samples -// to use (actual usage might vary slightly). Regardless of -// lengthTarget, never use more than bufferSize samples. - -int drawGround(float *buffer, int bufferSize, int framesTarget) -{ - int length; - - // Calculate total length of ground line, to arrive at a speed calculation - float totalLineLength = 0.4f*screenWidth - + sqrtf(0.36f*screenWidth*screenWidth - + (tank2Y-tank1Y)*(tank2Y-tank1Y)); - - // Speed is calculated in pixels per frame - float speed = totalLineLength / (float)framesTarget; - - // Draw three lines: platforms for tanks and the connecting line. - // Eventually, render a more complex ground from the array. - length = renderLine(0, tank1Y, screenWidth * 0.2, tank1Y, - speed, buffer, bufferSize); - length += renderLine(screenWidth * 0.2, tank1Y, screenWidth * 0.8, tank2Y, - speed, &buffer[length], bufferSize - length); - length += renderLine(screenWidth * 0.8, tank2Y, screenWidth, tank2Y, - speed, &buffer[length], bufferSize - length); - - return length; -} - -int drawTanks(float *buffer, int bufferSize, int framesTarget) -{ - int length = 0; - - // Calculate total length of tank lines, to arrive at a speed calculation - float totalLineLength = 2.0*M_PI*tankRadius + 2.0*(cannonLength - tankRadius); - - // Speed is calculated in pixels per frame - float speed = totalLineLength / (float)framesTarget; - - if(playerHasWon != 2) { - // Tank 1 body = semicircle + line - length += renderArc(tank1X, tank1Y, tankRadius, M_PI, 2.0 * M_PI, - speed, buffer, bufferSize); - length += renderLine(tank1X + tankRadius, tank1Y, - tank1X - tankRadius, tank1Y, - speed, &buffer[length], bufferSize - length); - // Tank 1 cannon (line depending on angle) - length += renderLine(tank1X + tankRadius * cosf(tank1CannonAngle), - tank1Y - tankRadius * sinf(tank1CannonAngle), - tank1X + cannonLength * cosf(tank1CannonAngle), - tank1Y - cannonLength * sinf(tank1CannonAngle), - speed, &buffer[length], bufferSize - length); - } - - if(playerHasWon != 1) { - // Same idea for tank 2 - length += renderArc(tank2X, tank2Y, tankRadius, M_PI, 2.0 * M_PI, - speed, &buffer[length], bufferSize - length); - length += renderLine(tank2X + tankRadius, tank2Y, - tank2X - tankRadius, tank2Y, - speed, &buffer[length], bufferSize - length); - length += renderLine(tank2X + tankRadius * cosf(tank2CannonAngle), - tank2Y - tankRadius * sinf(tank2CannonAngle), - tank2X + cannonLength * cosf(tank2CannonAngle), - tank2Y - cannonLength * sinf(tank2CannonAngle), - speed, &buffer[length], bufferSize - length); - } - - return length; -} - -int drawProjectile(float *buffer, int bufferSize, int framesTarget) -{ - if(!projectileInMotion) - return 0; - - // Draw a point for a specified number of frames (each containing X and Y) - // Return the number of items used in the buffer, which will be twice - // the number of frames unless the buffer is full - - if(bufferSize/2 < framesTarget) { - renderPoint(projectilePositionX, projectilePositionY, buffer, bufferSize/2); - return bufferSize; - } - else { - renderPoint(projectilePositionX, projectilePositionY, buffer, framesTarget); - return framesTarget*2; - } -} - -// Main drawing routine entry point -int drawGame(float *buffer, int bufferSize) -{ - int length; - - // Based on buffer size, come up with speeds for each of the elements - // 50% of time to ground; 30% to the tanks and 20% to the projectile - // Give a margin of 25% beyond so we don't run out of buffer space - // if things take longer to draw than we guess they will - const float amountToUse = 0.375; // 0.75/2 because two samples per frame - const float groundFraction = 0.5 * amountToUse; - const float tankFraction = 0.3 * amountToUse; - const float projectileFraction = 0.2 * amountToUse; - - length = drawGround(buffer, bufferSize, bufferSize * groundFraction); - length += drawTanks(&buffer[length], bufferSize - length, - bufferSize * tankFraction); - length += drawProjectile(&buffer[length], bufferSize - length, - bufferSize * projectileFraction); - - return length; -}
--- a/examples/tank_wars/game.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * game.h - * - * Created on: Nov 10, 2014 - * Author: parallels - */ - -#ifndef GAME_H_ -#define GAME_H_ - -// Initialisation -void setupGame(int width, int height); -void restartGame(); - -// Update physics -void nextGameFrame(); - -// State updaters -void setTank1CannonAngle(float angle); -void setTank2CannonAngle(float angle); -void setTank1CannonStrength(float strength); -void setTank2CannonStrength(float strength); -void fireProjectile(); - -// State queries -bool gameStatusPlayer1Turn(); -bool gameStatusProjectileInMotion(); -int gameStatusWinner(); -bool gameStatusCollisionOccurred(); -bool gameStatusTankHitOccurred(); -float gameStatusProjectileHeight(); - -// Render screen; returns length of buffer used -int drawGame(float *buffer, int bufferSize); - -// Cleanup and memory release -void cleanupGame(); - -#endif /* GAME_H_ */
--- a/examples/tank_wars/main.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* - * main.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -#include <iostream> -#include <cstdlib> -#include <libgen.h> -#include <signal.h> -#include <getopt.h> -#include <sndfile.h> -#include <Bela.h> - -extern int gScreenFramesPerSecond; - -float *gMusicBuffer = 0; -int gMusicBufferLength = 0; -float *gSoundBoomBuffer = 0; -int gSoundBoomBufferLength = 0; -float *gSoundHitBuffer = 0; -int gSoundHitBufferLength = 0; - - -using namespace std; - -// Load a sound sample from file -int loadSoundFile(const string& path, float **buffer, int *bufferLength) -{ - SNDFILE *sndfile ; - SF_INFO sfinfo ; - - if (!(sndfile = sf_open (path.c_str(), SFM_READ, &sfinfo))) { - cout << "Couldn't open file " << path << endl; - return 1; - } - - int numChan = sfinfo.channels; - if(numChan != 1) - { - cout << "Error: " << path << " is not a mono file" << endl; - return 1; - } - - *bufferLength = sfinfo.frames * numChan; - *buffer = new float[*bufferLength]; - if(*buffer == 0){ - cout << "Could not allocate buffer" << endl; - return 1; - } - - int subformat = sfinfo.format & SF_FORMAT_SUBMASK; - int readcount = sf_read_float(sndfile, *buffer, *bufferLength); - - // Pad with zeros in case we couldn't read whole file - for(int k = readcount; k < *bufferLength; k++) - (*buffer)[k] = 0; - - sf_close(sndfile); - return 0; -} - -// Handle Ctrl-C by requesting that the audio rendering stop -void interrupt_handler(int var) -{ - gShouldStop = true; -} - -// Print usage information -void usage(const char * processName) -{ - cerr << "Usage: " << processName << " [options]" << endl; - - Bela_usage(); - - cerr << " --fps [-f] value: Set target frames per second\n"; - cerr << " --help [-h]: Print this menu\n"; -} - -int main(int argc, char *argv[]) -{ - BelaInitSettings settings; // Standard audio settings - string musicFileName = "music.wav"; - string soundBoomFileName = "boom.wav"; - string soundHitFileName = "hit.wav"; - - struct option customOptions[] = - { - {"help", 0, NULL, 'h'}, - {"fps", 1, NULL, 'f'}, - {NULL, 0, NULL, 0} - }; - - // Set default settings - Bela_defaultSettings(&settings); - - // Parse command-line arguments - while (1) { - int c; - if ((c = Bela_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0) - break; - switch (c) { - case 'f': - gScreenFramesPerSecond = atoi(optarg); - if(gScreenFramesPerSecond < 1) - gScreenFramesPerSecond = 1; - if(gScreenFramesPerSecond > 100) - gScreenFramesPerSecond = 100; - break; - case 'h': - usage(basename(argv[0])); - exit(0); - case '?': - default: - usage(basename(argv[0])); - exit(1); - } - } - - // Load the sound files - if(loadSoundFile(musicFileName, &gMusicBuffer, &gMusicBufferLength) != 0) { - cout << "Warning: unable to load sound file " << musicFileName << endl; - } - if(loadSoundFile(soundBoomFileName, &gSoundBoomBuffer, &gSoundBoomBufferLength) != 0) { - cout << "Warning: unable to load sound file " << soundBoomFileName << endl; - } - if(loadSoundFile(soundHitFileName, &gSoundHitBuffer, &gSoundHitBufferLength) != 0) { - cout << "Warning: unable to load sound file " << soundHitFileName << endl; - } - - // Initialise the PRU audio device - if(Bela_initAudio(&settings, 0) != 0) { - cout << "Error: unable to initialise audio" << endl; - return -1; - } - - // Start the audio device running - if(Bela_startAudio()) { - cout << "Error: unable to start real-time audio" << endl; - return -1; - } - - // Set up interrupt handler to catch Control-C and SIGTERM - signal(SIGINT, interrupt_handler); - signal(SIGTERM, interrupt_handler); - - // Run until told to stop - while(!gShouldStop) { - usleep(100000); - } - - // Stop the audio device - Bela_stopAudio(); - - // Clean up any resources allocated for audio - Bela_cleanupAudio(); - - // Release sound files - if(gMusicBuffer != 0) - free(gMusicBuffer); - if(gSoundBoomBuffer != 0) - free(gSoundBoomBuffer); - if(gSoundHitBuffer != 0) - free(gSoundHitBuffer); - - // All done! - return 0; -}
--- a/examples/tank_wars/render.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,337 +0,0 @@ -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - - -#include <Bela.h> -#include "game.h" -#include <rtdk.h> -#include <cmath> -#include <cstdlib> -#include <time.h> - -int gAudioFramesPerMatrixFrame = 2; // Ratio in audio to matrix sample rate - -int gInputTank1Angle = 0; // Inputs for the cannon angles -int gInputTank2Angle = 1; -int gInputLauncher = 2; // Input for launcher FSR - -int gOutputX = 0; // Outputs for the scope -int gOutputY = 1; -int gOutputPlayer1LED = 2; -int gOutputPlayer2LED = 3; - -int gGameFramesPerSecond = 60; // How often the physics are updated -int gGameFrameInterval; // ...and in frames -int gSamplesUntilNextFrame; // Counter until next update -int gSamplesSinceFinish = 0; // How long since somebody won? -bool gGameShouldRestart = false;// Whether we need to reinitiliase the game - -// Counter for overall number of samples that have elapsed -unsigned int gSampleCounter = 0; - -// 1st-order filter and peak detector for launcher input -float gLauncherLastSample = 0; -float gLauncherFilterPole = 0.8; -float gLauncherPeakValue = 0; -float gLauncherPeakFilterPole = 0.999; -float gLauncherNoiseThreshold = 0.01; -float gLauncherMinimumPeak = 0.1; -bool gLauncherTriggered = false; - -// Screen update rate; affects buffer size. Actual contents of buffer -// may be smaller than this -int gScreenWidth = 512; -int gScreenHeight = 512; -int gScreenFramesPerSecond = 25; - -// Double buffer for rendering screen. Each is an interleaved buffer -// of XY data. -float *gScreenBuffer1, *gScreenBuffer2; -float *gScreenBufferWrite, *gScreenBufferRead; -int gScreenBufferMaxLength; // What is the total buffer allocated? -int gScreenBufferReadLength; // How long is the read buffer? -int gScreenBufferWriteLength; // How long is the write (next) buffer? -int gScreenBufferReadPointer; // Where are we in the read buffer now? -int gScreenBufferNextUpdateLocation; // When should we render the next buffer? -bool gScreenNextBufferReady; // Is the next buffer ready to go? - -// Auxiliary (low-priority) task for updating the screen -AuxiliaryTask gScreenUpdateTask; - -// Buffers for music and sound effects -extern float *gMusicBuffer; -extern int gMusicBufferLength; -extern float *gSoundBoomBuffer; -extern int gSoundBoomBufferLength; -extern float *gSoundHitBuffer; -extern int gSoundHitBufferLength; - -// Current state for sound and music -int gMusicBufferPointer = 0; // 0 means start of buffer... -int gSoundBoomBufferPointer = -1; // -1 means don't play... -int gSoundHitBufferPointer = -1; -float gSoundProjectileOscillatorPhase = 0; -float gSoundProjectileOscillatorGain = 0.2; -float gOscillatorPhaseScaler = 0; - -void screen_update(); - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -bool setup(BelaContext *context, void *userData) -{ - srandom(time(NULL)); - - // Verify we are running with matrix enabled - if(context->analogFrames == 0 || context->analogChannels < 4) { - rt_printf("Error: this example needs the matrix enabled with at least 4 channels\n"); - return false; - } - - // Initialise audio variables - gAudioFramesPerMatrixFrame = context->audioFrames / context->analogFrames; - gOscillatorPhaseScaler = 2.0 * M_PI / context->audioSampleRate; - - // Initialise the screen buffers - gScreenBufferMaxLength = 2 * context->analogSampleRate / gScreenFramesPerSecond; - gScreenBuffer1 = new float[gScreenBufferMaxLength]; - gScreenBuffer2 = new float[gScreenBufferMaxLength]; - if(gScreenBuffer1 == 0 || gScreenBuffer2 == 0) { - rt_printf("Error initialising screen buffers\n"); - return false; - } - - gScreenBufferRead = gScreenBuffer1; - gScreenBufferWrite = gScreenBuffer2; - gScreenBufferReadLength = gScreenBufferWriteLength = 0; - gScreenBufferReadPointer = 0; - gScreenBufferNextUpdateLocation = 0; - gScreenNextBufferReady = false; - - // Initialise the game - setupGame(gScreenWidth, gScreenHeight); - gGameFrameInterval = context->analogSampleRate / gGameFramesPerSecond; - gSamplesUntilNextFrame = gGameFrameInterval; - - // Initialise auxiliary tasks - if((gScreenUpdateTask = Bela_createAuxiliaryTask(&screen_update, 90, - "bela-screen-update")) == 0) - return false; - - return true; -} - -// Swap buffers on the screen -void swap_buffers() -{ - if(gScreenBufferRead == gScreenBuffer1) { - gScreenBufferRead = gScreenBuffer2; - gScreenBufferWrite = gScreenBuffer1; - } - else { - gScreenBufferRead = gScreenBuffer1; - gScreenBufferWrite = gScreenBuffer2; - } - - gScreenBufferReadLength = gScreenBufferWriteLength; - gScreenBufferReadPointer = 0; - - // Schedule next update for 3/4 of the way through the buffer - gScreenBufferNextUpdateLocation = gScreenBufferReadLength * 0.75; - gScreenNextBufferReady = false; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - int audioIndex = 0; - - for(unsigned int n = 0; n < context->analogFrames; n++) { - for(int k = 0; k < gAudioFramesPerMatrixFrame; k++) { - // Render music and sound - float audioSample = 0; - - // Music plays in a loop - if(gMusicBuffer != 0 && gMusicBufferPointer >= 0) { - audioSample += gMusicBuffer[gMusicBufferPointer++]; - if(gMusicBufferPointer >= gMusicBufferLength) - gMusicBufferPointer = 0; - } - - // Sound effect plays until finished, then stops - if(gSoundBoomBuffer != 0 && gSoundBoomBufferPointer >= 0) { - audioSample += gSoundBoomBuffer[gSoundBoomBufferPointer++]; - if(gSoundBoomBufferPointer >= gSoundBoomBufferLength) - gSoundBoomBufferPointer = -1; - } - - if(gSoundHitBuffer != 0 && gSoundHitBufferPointer >= 0) { - audioSample += gSoundHitBuffer[gSoundHitBufferPointer++]; - if(gSoundHitBufferPointer >= gSoundHitBufferLength) - gSoundHitBufferPointer = -1; - } - - // Oscillator plays to indicate projectile height - if(gameStatusProjectileInMotion()) { - audioSample += gSoundProjectileOscillatorGain * sinf(gSoundProjectileOscillatorPhase); - - gSoundProjectileOscillatorPhase += gOscillatorPhaseScaler * constrain(map(gameStatusProjectileHeight(), - 1.0, 0, 300, 2000), 200, 6000); - if(gSoundProjectileOscillatorPhase > 2.0 * M_PI) - gSoundProjectileOscillatorPhase -= 2.0 * M_PI; - } - - context->audioOut[2*audioIndex] = context->audioOut[2*audioIndex + 1] = audioSample; - audioIndex++; - } - - // First-order lowpass filter to remove noise on launch FSR - float rawSample = analogRead(context, n, gInputLauncher); - float launchSample = gLauncherFilterPole * gLauncherLastSample + - (1.0f - gLauncherFilterPole) * rawSample; - gLauncherLastSample = launchSample; - - // Peak-detect on launch signal - if(launchSample >= gLauncherPeakValue) { - gLauncherPeakValue = launchSample; - gLauncherTriggered = false; - } - else { - if(gLauncherPeakValue - launchSample > gLauncherNoiseThreshold && !gLauncherTriggered) { - // Detected a peak; is it big enough overall? - if(gLauncherPeakValue >= gLauncherMinimumPeak) { - gLauncherTriggered = true; - // Peak detected-- fire!! - // Set both cannon strengths but only one will - // fire depending on whose turn it is - float strength = map(gLauncherPeakValue, - gLauncherMinimumPeak, 1.0, - 0.5f, 10.0f); - setTank1CannonStrength(strength); - setTank2CannonStrength(strength); - fireProjectile(); - } - } - - gLauncherPeakValue *= gLauncherPeakFilterPole; - } - - if(--gSamplesUntilNextFrame <= 0) { - // Update game physics and cannon angles - gSamplesUntilNextFrame = gGameFrameInterval; - - setTank1CannonAngle(map(analogRead(context, n, gInputTank1Angle), - 0, 1.0, M_PI, 0)); - setTank2CannonAngle(map(analogRead(context, n, gInputTank2Angle), - 0, 1.0, M_PI, 0)); - nextGameFrame(); - - // Check for collision and start sound accordingly - if(gameStatusCollisionOccurred()) { - gSoundBoomBufferPointer = 0; - } - - if(gameStatusTankHitOccurred()) { - gSoundHitBufferPointer = 0; - } - } - - if(gScreenBufferReadPointer >= gScreenBufferReadLength - 1 - && gScreenNextBufferReady) { - // Got to the end; swap buffers - swap_buffers(); - } - - // Push current screen buffer to the matrix output - if(gScreenBufferReadPointer < gScreenBufferReadLength - 1) { - float x = gScreenBufferRead[gScreenBufferReadPointer++]; - float y = gScreenBufferRead[gScreenBufferReadPointer++]; - - // Rescale screen coordinates to matrix ranges; invert the Y - // coordinate to go from normal screen coordinates to scope coordinates - analogWriteOnce(context, n, gOutputX, constrain(map(x, 0, gScreenWidth, 0, 1.0), 0, 1.0)); - analogWriteOnce(context, n, gOutputY, constrain(map(y, 0, gScreenHeight, 1.0, 0), 0, 1.0)); - } - else { - // Still not ready! Write 0 until something happens - analogWriteOnce(context, n, gOutputX, 0); - analogWriteOnce(context, n, gOutputY, 0); - } - - if(gameStatusWinner() != 0) { - // Blink one LED to show who won - // Blink both LEDs when projectile is in motion - float val = (gSampleCounter % 4000 > 2000) ? 1.0 : 0; - analogWriteOnce(context, n, gOutputPlayer1LED, gameStatusWinner() == 1 ? val : 0); - analogWriteOnce(context, n, gOutputPlayer2LED, gameStatusWinner() == 2 ? val : 0); - - // After 5 seconds, restart the game - gSamplesSinceFinish++; - if(gSamplesSinceFinish > 22050*5) - gGameShouldRestart = true; - } - else if(gameStatusProjectileInMotion()) { - // Blink both LEDs when projectile is in motion - float val = (gSampleCounter % 2000 > 1000) ? 1.0 : 0; - analogWriteOnce(context, n, gOutputPlayer1LED, val); - analogWriteOnce(context, n, gOutputPlayer2LED, val); - } - else if(gameStatusPlayer1Turn()) { - analogWriteOnce(context, n, gOutputPlayer1LED, 1.0); - analogWriteOnce(context, n, gOutputPlayer2LED, 0); - } - else { - analogWriteOnce(context, n, gOutputPlayer2LED, 1.0); - analogWriteOnce(context, n, gOutputPlayer1LED, 0); - } - - // Check if we have reached the point where we should next update - if(gScreenBufferReadPointer >= gScreenBufferNextUpdateLocation && - !gScreenNextBufferReady) { - // Update the screen at lower priority than the audio thread - Bela_scheduleAuxiliaryTask(gScreenUpdateTask); - } - - gSampleCounter++; - } -} - -void screen_update() -{ - // If we should restart, reinitialise the game - if(gGameShouldRestart) { - restartGame(); - gGameShouldRestart = false; - gSamplesSinceFinish = 0; - } - - // Render the game based on the current state - gScreenBufferWriteLength = drawGame(gScreenBufferWrite, gScreenBufferMaxLength); - - // Flag it as ready to go - gScreenNextBufferReady = true; -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ - // Clean up the game state - cleanupGame(); -}
--- a/examples/tank_wars/vector_graphics.cpp Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * vector_graphics.cpp - * - * Created on: Nov 10, 2014 - * Author: parallels - */ - -#include <cmath> - -// Draw a line between two points at a specified rate in -// pixels per buffer sample. Indicate maximum available space. -// Returns space used -int renderLine(float x1, float y1, float x2, float y2, float speed, - float *buffer, int maxLength) { - // Figure out length of line and therefore how many samples - // are needed to represent it based on the speed (rounded to nearest int) - float totalLineLength = sqrtf((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); - int samplesNeeded = floorf(totalLineLength / speed + 0.5); - - // Now render into the buffer - int length = 0; - float scaleFactor = 1.0f / samplesNeeded; - for(int n = 0; n < samplesNeeded; n++) { - if(length >= maxLength - 1) - return length; - // X coordinate - *buffer++ = x1 + (float)n * scaleFactor * (x2 - x1); - // Y coordinate - *buffer++ = y1 + (float)n * scaleFactor * (y2 - y1); - length += 2; - } - - return length; -} - -// Draw an arc around a centre point at a specified rate of pixels -// per buffer sample. Indicate maximum available space. -// Returns space used -int renderArc(float x, float y, float radius, float thetaMin, float thetaMax, - float speed, float *buffer, int maxLength) { - // Figure out circumference of arc and therefore how many samples - // are needed to represent it based on the speed (rounded to nearest int) - float circumference = (thetaMax - thetaMin) * radius; - int samplesNeeded = floorf(circumference / speed + 0.5); - - // Now render into the buffer - int length = 0; - float scaleFactor = 1.0f / samplesNeeded; - for(int n = 0; n < samplesNeeded; n++) { - if(length >= maxLength - 1) - return length; - // Get current angle - float theta = thetaMin + (float)n * scaleFactor * (thetaMax - thetaMin); - - // Convert polar to cartesian coordinates - *buffer++ = x + radius * cosf(theta); - *buffer++ = y + radius * sinf(theta); - - length += 2; - } - - return length; -} - -// Draw a single point for a specified number of frames -void renderPoint(float x, float y, float *buffer, float length) { - while(length > 0) { - *buffer++ = x; - *buffer++ = y; - length--; - } -}
--- a/examples/tank_wars/vector_graphics.h Mon Jun 20 15:10:12 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -/* - * vector_graphics.h - * - * Created on: Nov 10, 2014 - * Author: parallels - */ - -#ifndef VECTOR_GRAPHICS_H_ -#define VECTOR_GRAPHICS_H_ - -int renderLine(float x1, float y1, float x2, float y2, float speed, - float *buffer, int maxLength); -int renderArc(float x, float y, float radius, float thetaMin, float thetaMax, - float speed, float *buffer, int maxLength); -void renderPoint(float x, float y, float *buffer, float length); - - -#endif /* VECTOR_GRAPHICS_H_ */
--- a/scripts/build_project.sh Mon Jun 20 15:10:12 2016 +0100 +++ b/scripts/build_project.sh Mon Jun 20 16:20:38 2016 +0100 @@ -5,6 +5,19 @@ # The source files in this directory are copied to the board and compiled. # set defaults unless variables are already set +<<<<<<< mine +[ -z "$BBB_ADDRESS" ] && BBB_ADDRESS="root@192.168.7.2" +[ -z "$BBB_BELA_HOME" ] && BBB_BELA_HOME="~/Bela/" +[ -z "$BBB_SCREEN_NAME" ] && BBB_SCREEN_NAME="Bela" +[ -z "$RUN_PROJECT" ] && RUN_PROJECT=1 +[ -z "$COMMAND_ARGS" ] && COMMAND_ARGS= +[ -z "$RUN_IN_FOREGROUND" ] && RUN_IN_FOREGROUND=1 +[ -z "$RUN_WITHOUT_SCREEN" ] && RUN_WITHOUT_SCREEN=0 +[ -z "$BBB_PROJECT_HOME" ] && BBB_PROJECT_HOME="${BBB_BELA_HOME}/projects/" +[ -z "$BBB_DEFAULT_PROJECT_NAME" ] && BBB_DEFAULT_PROJECT_NAME="scriptUploadedProject" +[ -z "$BBB_PROJECT_NAME" ] && BBB_PROJECT_NAME=$BBB_DEFAULT_PROJECT_NAME +======= +>>>>>>> theirs SCRIPTDIR=$(dirname "$0") [ -z $SCRIPTDIR ] && SCRIPTDIR="./" || SCRIPTDIR=$SCRIPTDIR/