Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 3 1 2 3 LastLast
Results 1 to 25 of 53

Thread: Audio Lib Manicken design tool

  1. #1
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28

    Audio Lib Manicken design tool

    Hi,
    First of all: oh wow, what a super tool:
    https://manicken.github.io/#
    I hadn't yet the time to use it, just loaded the synth example, but it seems clear to me that there is much work done here and that it will be very useful.

    There is only one caveat that might be good to know for others also: I couldn't get it to work in Firefox.
    Then I tried Chromium: no problem.

    I am looking forward to experiment with it...

  2. #2
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Thanks

    It did work on firefox
    but after I did some implementation
    using Web Serial API
    I forgot to add checks against "Web Serial API" availability

    It's now fixed, and the tool now works on all browsers that I know off.

    Internet Explorer don't work (and I don't know why, but the official tool do)

    If you want to play with the (in development) new OSC system
    then it's Chrome,Edge or Opera that supports Web Serial API

  3. #3
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    Thank you! Effectively I get it to work in Firefox now :-)

    However as I am new to all this, it is not easy to get started. The Examples are fine, but complex.
    Is there a source of information on getting started, or are there simpler examples anywhere?

    As a simple example I tried to make a Fourier synthesis with 4 oscillators, and a mixer.

    The first questions I have are:

    - How do I define a waveform as array? (I suppose it is not enough to define it in the name as e.g. wave[4]) ?

    - Do I have to do something extra to include the special elements like mixer with n inputs to my Arduino IDE or code?

  4. #4
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Quote Originally Posted by Jean-ClaudeF View Post
    - How do I define a waveform as array? (I suppose it is not enough to define it in the name as e.g. wave[4]) ?
    Yes that is exactly how you define a array, it's not harder than that (but you can't have different size arrays in the same tab/class/workspace)

    Quote Originally Posted by Jean-ClaudeF View Post
    - Do I have to do something extra to include the special elements like mixer with n inputs to my Arduino IDE or code?
    here is the most simple example
    copy that URL and paste it into the tool @ import-json

    https://raw.githubusercontent.com/ma...mpleSynth.json

    the mixer n code is included into that and if you do a export
    Class-based to Zip
    and then extract that into your sketch folder
    you are ready to go

    and in the "sketchname".ino
    have the following

    Code:
    #include "synth.h"
    
    Synth synth;
    
    setup () {
    
    synth.begin();
    
    }
    In the voice tab you can see the structure of that
    the Out object can be found in the special category
    there is also a In object
    these (In & Out) objects are only virtual placeholder objects,
    they are replaced by simple audio connections when a export is made

    notice the audio connections made are "outside" of the "Voice" class and are created and connected in the "Synth" class

    simple example (inside synth class, outside Voice class)
    AudioMixer<8> mixer; // mixer is in Synth class namespace
    AudioConnection(voices[0].mixer, 0, mixer, 0); // voices[0].mixer here mixer is in the Voice class namespace so they can have the same name



    How it works:
    When a new tab is created there will also be a new object available in the tabs category (@left panel is the categories)
    At first the object contains no inputs or outputs
    They are in the special category as In and Out
    they can be named whatever you like
    but when used the order "top to bottom" is important

    Click image for larger version. 

Name:	IOorder.png 
Views:	16 
Size:	26.6 KB 
ID:	27042

    Also notice there is currently no way of locking a "inside" Out to a "outside" Out pin
    so for example if you move the OutB object above OutC then the "outside" order will change as well.

    Hope that all will describe how it all works.
    Please feel free to ask more specific questions if something is unclear.

  5. #5
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    Thanks for the quick answer!
    I have succeeded in
    - creating a wave array (sine)
    - getting the mixer to work, though not exactly the way you described.

    I have extracted the mixer code, put it into a tab in the Arduino IDE and coded my Fourier example like this:

    Code:
    #include <Audio.h>
    #include "themixer.h"
    
    AudioSynthWaveform               wave[4];        //xy=650,325
    AudioMixer<4>                    mixer;    //xy=815,325
    AudioOutputI2S                   i2s1;           //xy=940,330
    
    
    AudioConnection          patchCord1(wave[4], 0, mixer, 0);
    AudioConnection          patchCord2(mixer, 0, i2s1, 0);
    AudioConnection          patchCord3(mixer, 0, i2s1, 1);
    
    AudioControlSGTL5000     sgtl5000_1;     //xy=815,405
    
    AudioConnection  *patchCord[10]; 
    
    
    void setup() {
        AudioMemory(10);
        sgtl5000_1.enable();
        sgtl5000_1.volume(0.9);
    
        
        for(int i=0; i<=3; i++){
            patchCord[i] = new AudioConnection(wave[i], 0, mixer, i);
            wave[i].begin(WAVEFORM_SINE);  
            wave[i].frequency((i+1) * 440);
            wave[i].amplitude(0.3);
        }      
    
    }
    
    void loop() {
      
    }
    If I understand well, this is not exactly as it was meant to be done.

    From the original Audio GUI I'm used to do only the declarations of the audio objects in the GUI and then write the code in the IDE.

    Your aim seems to be to do EVERYTHING in the GUI and then export it to the IDE.
    So I should rework my example and put the code into function blocks in the GUI? Is that how it should be done?

    ------

    Two more questions:
    - Could the mixer code be somehow embedded in the GUI, so that you wouldn't have to manually add it? (or put into a lib)
    - Once the mixer is defined in the GUI with for example 4 inputs, is this a fixed number or can it be changed in the IDE? I tried to edit the code for more harmonics but that didn't work.

  6. #6
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Ok of what I understand this is what you want

    Click image for larger version. 

Name:	onlyArray.png 
Views:	22 
Size:	6.3 KB 
ID:	27043

    it generates the following code (if the tab is named Synth)

    Code:
    class Synth
    {
    public:
        AudioSynthWaveform         wave[4];
        AudioMixer4                      mixer4;
        AudioOutputI2S                 i2s;
        AudioControlSGTL5000       sgtl5000;
        AudioConnection                *patchCord[6]; // total patchCordCount:6 including array typed ones.
    
        Main() { // constructor (this is called when class-object is created)
            int pci = 0; // used only for adding new patchcords
    
    
            patchCord[pci++] = new AudioConnection(mixer4, 0, i2s, 0);
            patchCord[pci++] = new AudioConnection(mixer4, 0, i2s, 1);
            for (int i = 0; i < 4; i++) {
                patchCord[pci++] = new AudioConnection(wave[i], 0, mixer4, i);
            }
            
        }
        // this function just makes cleaner looking main code
        void begin() { // begin, init or what name you prefer
            AudioMemory(10);
            sgtl5000_1.enable();
            sgtl5000_1.volume(0.9);
    
            for(int i=0; i < 4; i++){
                wave[i].begin(WAVEFORM_SINE);  
                wave[i].frequency((i+1) * 440);
                wave[i].amplitude(0.3);
            }
        }
    };
    then in your sketch main file

    Code:
    #include <Audio.h>
    #include "Synth.h"
    
    Synth synth;
    
    setup() 
    {
         // either do some coding inside the Tool++ and just call the functions here
         synth.begin();
    
    
         // or if you want you can also do the init stuff "external" here
        AudioMemory(10);
        synth.sgtl5000_1.enable();
        synth.sgtl5000_1.volume(0.9);
    
        for(int i=0; i < 4; i++){
            synth.wave[i].begin(WAVEFORM_SINE);  
            synth.wave[i].frequency((i+1) * 440);
            synth.wave[i].amplitude(0.3);
        }
    }
    
    loop()
    {
    
    }

  7. #7
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    Ok of what I understand this is what you want
    Exactly (but with TheMixer), and I'm doing this not for any practical purpose, but only as an exercise to learn how to use Audio object arrays.

    Ok, now I understand that the class name comes from the tab name, fine.

    What confuses me is the doubling of code in the first code piece and the second one:
    Code:
    AudioMemory(10);
            sgtl5000_1.enable();
            sgtl5000_1.volume(0.9);
    
            for(int i=0; i < 4; i++){
                wave[i].begin(WAVEFORM_SINE);  
                wave[i].frequency((i+1) * 440);
                wave[i].amplitude(0.3);
            }
    I would expect that if you define the begin function with the for loop in the class definition it would be enough to do
    Code:
    synth.begin();
    in the setup().
    Or did you want to show me different possibilities of doing it in one code segment?

  8. #8
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    I tried something different now. Wanted to build an 8 input mixer out of 3 standard ones:
    Click image for larger version. 

Name:	mixer.png 
Views:	15 
Size:	43.2 KB 
ID:	27052
    However the export is not successful, see error message.
    I thought I could build new objects by using the virtual in / out.
    What error did I make?

  9. #9
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Quote Originally Posted by Jean-ClaudeF View Post
    Or did you want to show me different possibilities of doing it in one code segment?
    Yes I wanted to show different possibilities.

    Quote Originally Posted by Jean-ClaudeF View Post
    However the export is not successful, see error message.
    I thought I could build new objects by using the virtual in / out.
    What error did I make?
    If you get that message then you have no i2s USB and similar I/O
    in your design.

    What export method did you use?

    for example
    Simple export
    do create the same structure as the official tool

    and the class based variants use a class hierarchy

    The virtual I/O are only supported in the class export modes.

  10. #10
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Here is a minimalistic example how it should/could look like

    The "Voice" tab
    Click image for larger version. 

Name:	Tab_Voice.png 
Views:	15 
Size:	13.7 KB 
ID:	27058

    The "Main" tab
    Click image for larger version. 

Name:	Tab_Main.png 
Views:	15 
Size:	15.3 KB 
ID:	27057

    here the main tab contains at least one type of IO node
    it's the same as the official tool
    there the system don't work without the IO nodes

  11. #11
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    and you cannot design a 8 input mixer like that

    it would look more like this
    Click image for larger version. 

Name:	Tab_MixerX8.png 
Views:	14 
Size:	21.1 KB 
ID:	27059

    And also you cannot use that with arrays
    like this
    Click image for larger version. 

Name:	Tab_MixerX8_use.png 
Views:	16 
Size:	11.9 KB 
ID:	27060

    as the resulting code look like this when using that mixer "outside"

    Code:
    for (int i = 0; i < 8; i++) {
         patchCord[pci++] = new AudioConnection(voice[i].mixer4, 0, mixerx8.mixer1_4, i); // here it's only using the first mixer and also 'i' gonna kind of overflow the amount of inputs the standard mixer has
    }
    but you can use it like this

    Click image for larger version. 

Name:	Tab_MixerX8_use_alternative.png 
Views:	15 
Size:	13.6 KB 
ID:	27061

    which generates the following code
    Code:
    for (int i = 0; i < 4; i++) {
        patchCord[pci++] = new AudioConnection(voices_A[i].mixer4, 0, mixerx8.mixer1_4, i);
        patchCord[pci++] = new AudioConnection(voices_B[i].mixer4, 0, mixerx8.mixer5_8, i);
    }
    here you can see that voices_A uses mixer1_4 (port0-3)
    and voices_B uses mixer5_8 (port0-3)

    I would however recommend to use the n mixer for situations like this as you can expand it up to the limits of the lib which is 255 inputs.

  12. #12
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    and you cannot design a 8 input mixer like that
    That's what I just noticed!
    I have tried and edited the code afterwards like this to get the 8 input mixer:

    Code:
    class Mixer_8 
    {
    public:
        AudioMixer4                      mixer4_1;
        AudioMixer4                      mixer4_2;
        AudioMixer4                      mixer;
        AudioOutputI2S                   i2s;
        AudioConnection                  *patchCord[4]; // total patchCordCount:4 including array typed ones.
    
        Mixer_8() { // constructor (this is called when class-object is created)
            int pci = 0; // used only for adding new patchcords
    
    
            patchCord[pci++] = new AudioConnection(mixer4_1, 0, mixer, 0);
            patchCord[pci++] = new AudioConnection(mixer4_2, 0, mixer, 1);
            patchCord[pci++] = new AudioConnection(mixer, 0, i2s, 0);
            patchCord[pci++] = new AudioConnection(mixer, 0, i2s, 1);
            
        }
    };
    //-------------------------------------------------------------------------------------
    class Osc_8 
    {
    public:
        AudioSynthWaveform               waveform[8];
        Mixer_8                          mixer_8;
        AudioConnection                  *patchCord[64]; // total patchCordCount:64 including array typed ones.
    
        Osc_8() { // constructor (this is called when class-object is created)
            int pci = 0; // used only for adding new patchcords
    
    
            for (int i = 0; i < 8; i++) {
               if(i<4){
                    patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_1, i);
                    }
               else{
                    patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_2, i-4);     
               }
                /*   Code generated by the tool:       
                patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_1, i);
                patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_1, i);
                patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_1, i);
                patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_1, i);
                patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_2, i);
                patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_2, i);
                patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_2, i);
                patchCord[pci++] = new AudioConnection(waveform[i], 0, mixer_8.mixer4_2, i);
                */
            }
            
        }
    };
    ----------------

    I would however recommend to use the n mixer
    Wouldn't it be a good idea for the Tool to automatically integrate the "theMixer.h" function into the diagram when you put a mixer on the drawing?

  13. #13
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    The other question I have is: what exactly is the tool for?
    I see that I have just scraped on the surface, but you use it for big things.

    It looks a bit like a nicer version of PureData.
    However for me it is not clear how this should work, as there is a controller I program with a fix firmware, and there is a kind of GUI that is used to control the instrument on the Teensy?

  14. #14
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Quote Originally Posted by Jean-ClaudeF View Post
    Wouldn't it be a good idea for the Tool to automatically integrate the "theMixer.h" function into the diagram when you put a mixer on the drawing?
    have done that now it's available as a special object in the mixer category
    just drag n drop
    (no automatically drop yet)


    Quote Originally Posted by Jean-ClaudeF View Post
    The other question I have is: what exactly is the tool for?
    At the beginning it was to simplify big hierarchy designs
    and to simplify the usage of arrays

    then it grow to do much more

    the Control GUI part of the Tool is to make it simpler to test designs without wiring a lot of pots and creating additional hardware to control the
    design.

    Yes it's like pure data but easier and you have everything in one place.

  15. #15
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    About the mixer code
    I think I will have it export the mixer code automatically when having a such mixer present in the design, that will solve it for every design. I will do that after the 9th January.

  16. #16
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    The planned vacation is cancelled (for the moment).

    So I have now made some changes to the tool

    Now it autogenerates mixer code for every mixer variant that you use.
    (only available for export to class variants)


    This is just how the C++ template mixer works
    but using the C++ template mixer had some issues,
    * it did sometimes not include the static functions used by the mixer
    * to make it work a standard AudioMixer4 had to be used somewhere in the design.

    But now it generates standard non "C++ template" code, that force inclusion of the static methods.

    Best result is to use the export to class based zip
    as it generates the cleanest code.

  17. #17
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    Sorry for your vacation!

    Fine that you integrated the mixer code.
    Fine also that the zip file generated contains the code as separate files (-> separate tabs in the IDE. That makes the code much more readable)

    I am still experimenting with simple examples and I have not wholly understood everything (what makes it not more easy is that I am not used to program in C++. But that way I am learning this too.)

    I have taken your example (left : Main, right: Voice):
    Click image for larger version. 

Name:	Voice.png 
Views:	15 
Size:	22.3 KB 
ID:	27077Click image for larger version. 

Name:	Main.png 
Views:	15 
Size:	17.1 KB 
ID:	27078
    The begin function contains this:
    Code:
    waveform.begin(WAVEFORM_SINE);
        waveform.frequency(440);
        waveform.amplitude(0.5);
        
        waveformMod.begin(WAVEFORM_SINE);
        waveformMod.frequency(660);
        waveformMod.amplitude(0.5);
    The generated code didn't work, I saw no begin funtion, only the code that it should contain, and I had to put this code manually into the Voice class to make it work:
    Code:
    class Voice 
    {
    public:
        AudioSynthWaveformModulated      waveformMod;
        AudioSynthWaveform               waveform;
        AudioMixer4                      mixer4;
        AudioConnection                  *patchCord[2]; // total patchCordCount:2 including array typed ones.
    
        Voice() { // constructor (this is called when class-object is created)
            int pci = 0; // used only for adding new patchcords
    
    
            patchCord[pci++] = new AudioConnection(waveformMod, 0, mixer4, 1);
            patchCord[pci++] = new AudioConnection(waveform, 0, mixer4, 0);
    
        waveform.begin(WAVEFORM_SINE);
        waveform.frequency(440);
        waveform.amplitude(0.5);
        
        waveformMod.begin(WAVEFORM_SINE);
        waveformMod.frequency(660);
        waveformMod.amplitude(0.5);
        }
    };
    What have I done wrong?

  18. #18
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    the begin function must also contain the "function declaration"

    void begin() {
    ...code here
    }

    like this:
    Code:
    void begin() {
        waveform.begin(WAVEFORM_SINE);
        waveform.frequency(440);
        waveform.amplitude(0.5);
        
        waveformMod.begin(WAVEFORM_SINE);
        waveformMod.frequency(660);
        waveformMod.amplitude(0.5);
    }
    there is a snippet in the autocomplete functionality
    if you begin to write be
    and if you select the first one in the list
    Click image for larger version. 

Name:	beginSnippet.png 
Views:	13 
Size:	9.9 KB 
ID:	27082

    the following will automatically appear
    Code:
    void begin()
    {
        
    }
    note. the code "block" object can contain multiple functions with different names
    also it can contain global variable definitions (but the vars object should be used for that to clarify the generated code)

    note. the autocomplete don't yet work for variables that is declared inside such objects
    I will take a look at it now

    Code:
    void begin()
    {
    
    }
    void begin(uint_8 someparam)
    {
        // do some stuff with someparam here
    }
    uint8_t somevar = 0;
    void init()
    {
    
    }
    you can also check the Tool++ thread for other updates
    https://forum.pjrc.com/threads/65740...gn-Tool-update

  19. #19
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    I have tryed another one that should do a simple Fourier synthesis:
    Tab Fourier:
    Click image for larger version. 

Name:	Fourier.png 
Views:	18 
Size:	12.3 KB 
ID:	27086
    with begin function:
    Code:
    void begin(){
        for (int i=0; i<4; i++){
                 wave[i].begin(WAVEFORM_SINE);
                 wave[i].frequency((i+1)*440);
                 wave[i].amplitude(0.5);
            }
    }
    and Main tab
    Click image for larger version. 

Name:	Main.png 
Views:	17 
Size:	12.4 KB 
ID:	27087
    with begin function:
    Code:
    void begin(){
        AudioMemory(10);
        sgtl5000.enable();
        sgtl.volume(0.9);
    }
    Then I want to have a tab test.ino that should be the main Arduino tab in the IDE. How do I do that?
    (Supposed I want to do every coding in your tool)
    If I am right this tab should also contain the variable declaration and code
    Code:
    #include "Main.h"
    AudioControlSGTL5000 sgtl5000;
    Main main;
    main.begin();
    Maybe the problem is that I am not used to thinking in C++ [I love Python !]

    I tried several things but didn't succeed in getting this example to work.

  20. #20
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    just a little note
    in your Tab Fourier begin function
    you have written
    for (int i=0; i<4; i++){

    should it not be 8 instead of 4?


    To define the main tab
    just double-click that tab
    and check the isMain checkbox
    like this:

    Click image for larger version. 

Name:	SetMainFile.png 
Views:	13 
Size:	17.4 KB 
ID:	27090

    then you can select how the name + extension should be like
    main is just plain main.ino/main.cpp

    "Tab Name" uses the name from the tab
    "Project Name" uses the name from right panel "settings tab"-Arduino-"Project Name"

    in this main tab no AudioObjects are included in the exported code
    here is my example of my main tab
    Click image for larger version. 

Name:	MainFileExample.png 
Views:	18 
Size:	18.6 KB 
ID:	27091

    here is the json for that (don't forget the trailing ])
    copy that and use json import (DON'T FORGET to uncheck replace flow checkbox)

    you can also select this text and drag drop it into the design
    Code:
    [{"id":"main.cpp_includeDef1","type":"IncludeDef","name":"<MIDI.h>","comment":"","x":410,"y":20,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_Synth1","type":"Synth","name":"synth","x":410,"y":70,"z":"14f24e29.494642","bgColor":"#CCFFCC","wires":[]},{"id":"main.cpp_vars1","type":"Variables","name":"global variables & function forward declarations","comment":"const int ledPin = 13;\r\nint ledState = LOW;             // ledState used to set the LED\r\nunsigned long previousMillis = 0;        // will store last time LED was updated\r\nunsigned long currentMillis = 0;\r\nunsigned long currentInterval = 0;\r\nunsigned long ledBlinkOnInterval = 100;\r\nunsigned long ledBlinkOffInterval = 2000;\r\n\r\n#define btnInEnablePin 9\r\n#define btnSustainPin 23\r\n#define btnSostenutoPin 22\r\n#define btnSoftPedalPin 21\r\nuint8_t btnSustain = 0;\r\nuint8_t btnSostenuto = 0;\r\nuint8_t btnSoftPedal = 0;\r\nuint8_t btnSustainWasPressed = 0;\r\nuint8_t btnSostenutoWasPressed = 0;\r\nuint8_t btnSoftPedalWasPressed = 0;\r\n\r\n#define btnNextInstrumentPin 20\r\nuint8_t btnNextInstrument = 0;\r\nuint8_t btnNextInstrumentWasPressed = 0;\r\n\r\n#define KEYBOARD_NOTE_SHIFT_CORRECTION 21//-12\r\n\r\nvoid uartMidi_NoteOn(byte channel, byte note, byte velocity);\r\nvoid uartMidi_NoteOff(byte channel, byte note, byte velocity);\r\nvoid uartMidi_ControlChange(byte channel, byte control, byte value);\r\nvoid uartMidi_PitchBend(byte channel, int value);\r\n\r\nvoid usbMidi_NoteOn(byte channel, byte note, byte velocity);\r\nvoid usbMidi_NoteOff(byte channel, byte note, byte velocity);\r\nvoid usbMidi_ControlChange(byte channel, byte control, byte value);\r\nvoid usbMidi_PitchBend(byte channel, int value);\r\n\r\nvoid blinkLedTask(void);\r\nvoid btnInputProcessTask(void);\r\n\r\n","x":410,"y":120,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_vars2","type":"Variables","name":"MIDI_CREATE_INSTANCE","comment":"MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);","x":410,"y":170,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code2","type":"Function","name":"setup() function","comment":"\r\n// Arduino setup() function\r\nvoid setup()\r\n{\r\n  AudioMemory(96);\r\n\r\n  MIDI.begin();\r\n  MIDI.setHandleNoteOn(uartMidi_NoteOn);\r\n  MIDI.setHandleNoteOff(uartMidi_NoteOff);\r\n  MIDI.setHandleControlChange(uartMidi_ControlChange);\r\n  MIDI.setHandlePitchBend(uartMidi_PitchBend);\r\n\r\n  usbMIDI.setHandleNoteOn(usbMidi_NoteOn);\r\n  usbMIDI.setHandleNoteOff(usbMidi_NoteOff);\r\n  usbMIDI.setHandleControlChange(usbMidi_ControlChange);\r\n  usbMIDI.setHandlePitchChange(usbMidi_PitchBend);\r\n\r\n  synth.begin();\r\n\r\n  pinMode(btnSustainPin, INPUT);\r\n  pinMode(btnSostenutoPin, INPUT);\r\n  pinMode(btnSoftPedalPin, INPUT);\r\n  pinMode(btnNextInstrumentPin, INPUT);\r\n\r\n  pinMode(btnInEnablePin, OUTPUT);\r\n  digitalWrite(btnInEnablePin, LOW);\r\n\r\n  pinMode(ledPin, OUTPUT);\r\n  digitalWrite(ledPin, LOW);\r\n\r\n  btnSustainWasPressed = 0;\r\n  btnSoftPedalWasPressed = 0;\r\n  btnSostenutoWasPressed = 0;\r\n  btnNextInstrumentWasPressed = 0;\r\n  \r\n}\r\n","x":410,"y":220,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code3","type":"Function","name":"loop() function","comment":"\r\n// Arduino loop() function\r\nvoid loop()\r\n{\r\n    usbMIDI.read();\r\n    MIDI.read();\r\n\r\n    btnInputProcessTask();\r\n    \r\n    blinkLedTask();\r\n}","x":410,"y":270,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code4","type":"Function","name":"uartMidi handler functions","comment":"\r\n// uartMidi handler functions\r\nvoid uartMidi_NoteOn(byte channel, byte note, byte velocity) {\r\n    note += KEYBOARD_NOTE_SHIFT_CORRECTION;\r\n    velocity = 127 - velocity;\r\n    synth.noteOn(note, velocity);\r\n    usbMIDI.sendNoteOn(note, velocity, channel, 0);\r\n}\r\n\r\nvoid uartMidi_NoteOff(byte channel, byte note, byte velocity) {\r\n    note += KEYBOARD_NOTE_SHIFT_CORRECTION;\r\n    velocity = 127 - velocity;\r\n    synth.noteOff(note);\r\n    usbMIDI.sendNoteOff(note, velocity, channel, 0);\r\n}\r\n\r\nvoid uartMidi_ControlChange(byte channel, byte control, byte value) {\r\n    usbMIDI.sendControlChange(control, value, channel, 0x00);\r\n}\r\n\r\nvoid uartMidi_PitchBend(byte channel, int value) {\r\n    usbMIDI.sendPitchBend(value, channel, 0x00);\r\n}","x":410,"y":320,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code5","type":"Function","name":"usbMidi handler functions","comment":"\r\n// usbMidi handler functions\r\nvoid usbMidi_NoteOn(byte channel, byte note, byte velocity) {\r\n    synth.noteOn(note, velocity);\r\n}\r\n\r\nvoid usbMidi_NoteOff(byte channel, byte note, byte velocity) {\r\n    synth.noteOff(note);    \r\n}\r\n\r\nvoid usbMidi_PitchBend(byte channel, int value) {\r\n  \r\n}\r\n\r\nvoid usbMidi_ControlChange(byte channel, byte control, byte value) {\r\n    switch (control) { // cases 20-31,102-119 is undefined in midi spec\r\n        case 64:\r\n          if (value == 0)\r\n            synth.deactivateSustain();\r\n          else if (value == 127)\r\n            synth.activateSustain();\r\n          break;\r\n        case 0:\r\n          synth.set_InstrumentByIndex(value);\r\n          break;\r\n        case 20: // OSC A waveform select\r\n          synth.set_OSC_A_waveform(value);\r\n          break;\r\n        case 21: // OSC B waveform select\r\n          synth.set_OSC_B_waveform(value);\r\n          break;\r\n        case 22: // OSC C waveform select\r\n          synth.set_OSC_C_waveform(value);\r\n          break;\r\n\r\n        case 23:\r\n          synth.set_OSC_A_pulseWidth(value);\r\n          break;\r\n        case 24:\r\n          synth.set_OSC_B_pulseWidth(value);\r\n          break;\r\n        case 25:\r\n          synth.set_OSC_C_pulseWidth(value);\r\n          break;\r\n\r\n        case 26:\r\n          synth.set_OSC_A_phase(value);\r\n          break;\r\n        case 27:\r\n          synth.set_OSC_B_phase(value);\r\n          break;\r\n        case 28:\r\n          synth.set_OSC_C_phase(value);\r\n          break;\r\n\r\n        case 29:\r\n          synth.set_OSC_A_amplitude(value);\r\n          break;\r\n        case 30:\r\n          synth.set_OSC_B_amplitude(value);\r\n          break;\r\n        case 31:\r\n          synth.set_OSC_C_amplitude(value);\r\n          break;\r\n        case 32: //(\"LSB for Control 0 (Bank Select)\" @ midi spec.)\r\n          synth.set_OSC_D_amplitude(value);\r\n          break;\r\n\r\n        case 33: \r\n          synth.set_mixVoices_gains(value);\r\n          break;\r\n        \r\n        case 100:\r\n          synth.set_envelope_delay(value);\r\n          break;\r\n        case 101:\r\n          synth.set_envelope_attack(value);\r\n          break;\r\n        case 102:\r\n          synth.set_envelope_hold(value);\r\n          break;\r\n        case 103:\r\n          synth.set_envelope_decay(value);\r\n          break;\r\n        case 104:\r\n          synth.set_envelope_sustain(value);\r\n          break;\r\n        case 105:\r\n          synth.set_envelope_release(value);\r\n          break;\r\n                 \r\n        case 108:\r\n          synth.set_OSC_A_freqMult(value);\r\n          break;\r\n        case 109:\r\n          synth.set_OSC_B_freqMult(value);\r\n          break;\r\n        case 110:\r\n          synth.set_OSC_C_freqMult(value);\r\n          break;\r\n\r\n        case 115: // set wavetable as primary (Piano mode)\r\n          synth.SetWaveTable_As_Primary();\r\n          break;\r\n        case 116:\r\n          synth.SetWaveForm_As_Primary();\r\n          break;\r\n          \r\n        case 117: // EEPROM read settings\r\n          synth.EEPROM_ReadSettings();\r\n          break;\r\n        case 118: // EEPROM save settings\r\n          synth.EEPROM_SaveSettings();\r\n          break;\r\n\r\n        case 119: // get all values\r\n          synth.sendAllSettings();\r\n        break;\r\n    }\r\n}","x":410,"y":370,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code6","type":"Function","name":"btnInputProcessTask() function","comment":"\r\n// btnInputProcessTask() function\r\nvoid btnInputProcessTask(void)\r\n{\r\n  btnSustain = digitalRead(btnSustainPin);\r\n  btnSostenuto = digitalRead(btnSostenutoPin);\r\n  btnSoftPedal = digitalRead(btnSoftPedalPin);\r\n  btnNextInstrument = digitalRead(btnNextInstrumentPin);\r\n\r\n    // Sustain pedal\r\n    if ((btnSustain == LOW) && (btnSustainWasPressed == 0))\r\n    {\r\n        btnSustainWasPressed = 1;\r\n        usbMIDI.sendControlChange(0x40, 0x7F, 0x00);\r\n        synth.activateSustain();\r\n\r\n        uint16_t memory_used = AudioMemoryUsageMax();\r\n        uint16_t cpu_used = AudioProcessorUsageMax();\r\n        uint8_t data[11];\r\n        data[0] = 0x30 + memory_used/10000;\r\n        data[1] = 0x30 + memory_used%10000/1000;\r\n        data[2] = 0x30 + memory_used%10000%1000/100;\r\n        data[3] = 0x30 + memory_used%10000%1000%100/10;\r\n        data[4] = 0x30 + memory_used%10000%1000%100%10;\r\n        data[5] = ':';\r\n        data[6] = 0x30 + cpu_used/10000;\r\n        data[7] = 0x30 + cpu_used%10000/1000;\r\n        data[8] = 0x30 + cpu_used%10000%1000/100;\r\n        data[9] = 0x30 + cpu_used%10000%1000%100/10;\r\n        data[10] = 0x30 + cpu_used%10000%1000%100%10;\r\n        usbMIDI.sendSysEx(11, data);\r\n    }\r\n    else if ((btnSustain == HIGH) && (btnSustainWasPressed == 1))\r\n    {\r\n        btnSustainWasPressed = 0;\r\n        usbMIDI.sendControlChange(0x40, 0x00, 0x00);\r\n        synth.deactivateSustain();\r\n    }\r\n    // Sostenuto Pedal\r\n    if ((btnSostenuto == LOW) && (btnSostenutoWasPressed == 0))\r\n    {\r\n        btnSostenutoWasPressed = 1;\r\n        usbMIDI.sendControlChange(0x42, 0x7F, 0x00);\r\n    }\r\n    else if ((btnSostenuto == HIGH) && (btnSostenutoWasPressed == 1))\r\n    {\r\n        btnSostenutoWasPressed = 0;\r\n        usbMIDI.sendControlChange(0x42, 0x00, 0x00);\r\n    }\r\n    // Soft Pedal\r\n    if ((btnSoftPedal == LOW) && (btnSoftPedalWasPressed == 0))\r\n    {\r\n        btnSoftPedalWasPressed = 1;\r\n        usbMIDI.sendControlChange(0x43, 0x7F, 0x00);\r\n    }\r\n    else if ((btnSoftPedal == HIGH) && (btnSoftPedalWasPressed == 1))\r\n    {\r\n        btnSoftPedalWasPressed = 0;\r\n        usbMIDI.sendControlChange(0x43, 0x00, 0x00);\r\n    }\r\n    // Next Instrument button\r\n    if ((btnNextInstrument == LOW) && (btnNextInstrumentWasPressed == 0))\r\n    {\r\n        btnNextInstrumentWasPressed = 1;\r\n        if (synth.currentWTinstrument == (InstrumentCount - 1)) synth.currentWTinstrument = 0;\r\n        else synth.currentWTinstrument++;\r\n        synth.set_InstrumentByIndex(synth.currentWTinstrument);\r\n        usbMIDI.sendControlChange(0, synth.currentWTinstrument, 0x00);\r\n    }\r\n    else if ((btnNextInstrument == HIGH) && (btnNextInstrumentWasPressed == 1))\r\n    {\r\n        btnNextInstrumentWasPressed = 0;\r\n    }\r\n}","x":410,"y":410,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code1","type":"Function","name":"blinkLedTask() function","comment":"\r\n// blinkLedTask() function\r\nvoid blinkLedTask(void)\r\n{\r\n    currentMillis = millis();\r\n    currentInterval = currentMillis - previousMillis;\r\n    \r\n    if (ledState == LOW)\r\n    {\r\n        if (currentInterval > ledBlinkOffInterval)\r\n        {\r\n            previousMillis = currentMillis;\r\n            ledState = HIGH;\r\n            digitalWrite(ledPin, HIGH);\r\n        }\r\n    }\r\n    else\r\n    {\r\n        if (currentInterval > ledBlinkOnInterval)\r\n        {\r\n            previousMillis = currentMillis;\r\n            ledState = LOW;\r\n            digitalWrite(ledPin, LOW);\r\n        }\r\n    }\r\n}","x":410,"y":470,"z":"14f24e29.494642","bgColor":"#DDFFBB","wires":[]}
    ]

  21. #21
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    in your Tab Fourier begin function
    you have written
    for (int i=0; i<4; i++){

    should it not be 8 instead of 4?
    I tried different values to see if it worked. What was very strange: I got the same output (maybe with 8 additions, I didn't count) for any value there.

    you can select how the name + extension should be like...
    main is just plain main.ino/main.cpp
    Oh, fine! I didn't see that.

    I would really like to use the Tool in the way that I do all the programming in the GUI, that is really nice!
    (If only I succeeded with a small example).

  22. #22
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    OK, now I succeeded in realising a blinking sketch:
    Code:
    {"version":1,"settings":{"arduino":{"Board":{"Platform":"","Board":"","Options":""}},"BiDirDataWebSocketBridge":{},"workspaces":{},"sidebar":{},"palette":{},"editor":{},"devTest":{},"IndexedDBfiles":{"testFileNames":"testFile.txt"},"NodeDefGenerator":{},"NodeDefManager":{},"NodeHelpManager":{},"OSC":{}},"workspaces":[{"type":"tab","id":"Main","label":"blink","inputs":0,"outputs":0,"export":true,"isMain":true,"mainNameType":"tabName","mainNameExt":".ino","generateCppDestructor":false,"extraClassDeclarations":"","settings":{},"nodes":[{"id":"blink_i2s1","type":"AudioOutputI2S","name":"i2s","comment":"","x":410,"y":55,"z":"Main","bgColor":"#E6E0F8","wires":[]},{"id":"main.cpp_vars1","type":"Variables","name":"global variables & function forward declarations","comment":"const int ledPin = 13;\nint ledState = LOW;             // ledState used to set the LED\nunsigned long previousMillis = 0;        // will store last time LED was updated\nunsigned long currentMillis = 0;\nunsigned long currentInterval = 0;\nunsigned blinkInterval = 200;","x":405,"y":160,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code2","type":"Function","name":"setup() function","comment":"void setup()\r\n{\r\n  pinMode(ledPin, OUTPUT);\r\n  digitalWrite(ledPin, LOW);\r\n}\r\n","x":410,"y":220,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code3","type":"Function","name":"loop() function","comment":"void loop()\r\n{\r\n    blinkLedTask();\r\n}","x":410,"y":270,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"main.cpp_code1","type":"Function","name":"blinkLedTask() function","comment":"void blinkLedTask(void)\n{\n    currentInterval =  millis() - previousMillis;\n    if (currentInterval > blinkInterval){\n               digitalWrite(ledPin, !digitalRead(ledPin));\n               previousMillis = millis() ;\n    }\n}","x":405,"y":325,"z":"Main","bgColor":"#DDFFBB","wires":[]}]}],"nodeAddons":{}}
    Wow, what a success! :-)

    Maybe this would be good to add to your examples?

    However I had to add an i2s block, otherwise I couldn't export it
    I suppose this is a restriction due to Paul's underlying GUI?

  23. #23
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    I have started a document that could maybe become a kind of tutorial, at least for the beginning.
    You find it here:
    https://github.com/jean-claudeF/TeensySynth
    MannickenAudioTool.pdf

  24. #24
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    Just now I had a problem: could not edit function blocks anymore by double klicking on them (in Firefox and Chromium)

    That happens after importing this:
    Code:
    {"version":1,"settings":{"arduino":{"Board":{"Platform":"","Board":"","Options":""}},"BiDirDataWebSocketBridge":{},"workspaces":{},"sidebar":{},"palette":{},"editor":{},"devTest":{},"IndexedDBfiles":{"testFileNames":"testFile.txt"},"NodeDefGenerator":{},"NodeDefManager":{},"NodeHelpManager":{},"OSC":{}},"workspaces":[{"type":"tab","id":"Main","label":"helloworld_audio2","inputs":0,"outputs":0,"export":true,"isMain":true,"mainNameType":"tabName","mainNameExt":".ino","generateCppDestructor":false,"extraClassDeclarations":"","settings":{},"nodes":[{"id":"helloworld_audio2_vars1","type":"Variables","name":"declarations","comment":"const int ledPin = 13;\n#include \"MyTone.h\"\n\nTone mytone;\n","x":140,"y":55,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"helloworld_audio2_code1","type":"Function","name":"setup function","comment":"void setup()\n{\n    pinMode(ledPin, OUTPUT);\n    digitalWrite(ledPin, LOW);\n  \n    AudioMemory(10);\n    sgtl5000.enable();\n    sgtl5000.volume(0.3);\n    \n    tone.sine.frequency(440);\n}","x":295.25,"y":131.25,"z":"Main","bgColor":"#DDFFBB","wires":[]},{"id":"helloworld_audio2_code2","type":"Function","name":"code","comment":"void loop()\n{\n    digitalWrite(ledPin, 1);\n    tone.sine.amplitude(0.9);\n    delay(250);\n    digitalWrite(ledPin, 0);\n    tone.sine.amplitude(0);\n    delay(1750);\n}","x":308.25,"y":185.25,"z":"Main","bgColor":"#DDFFBB","wires":[]}]},{"type":"tab","id":"6f633541.989e4c","label":"MyTone","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"main","mainNameExt":".ino","generateCppDestructor":false,"extraClassDeclarations":"","settings":{},"nodes":[{"id":"Tone_sine1","type":"AudioSynthWaveformSine","name":"sine","comment":"","x":355,"y":155,"z":"6f633541.989e4c","bgColor":"#E6E0F8","wires":[["Tone_i2s1:0","Tone_i2s1:1"]]},{"id":"Tone_i2s1","type":"AudioOutputI2S","name":"i2s","comment":"","x":542.25,"y":155.25,"z":"6f633541.989e4c","bgColor":"#E6E0F8","wires":[]},{"id":"Tone_sgtl5000_1","type":"AudioControlSGTL5000","name":"sgtl5000","comment":"","x":561.25,"y":215.25,"z":"6f633541.989e4c","bgColor":"#E6E0F8","wires":[]}]}],"nodeAddons":{}}
    Last edited by Jean-ClaudeF; 01-03-2022 at 10:28 AM.

  25. #25
    Member
    Join Date
    Dec 2021
    Location
    Luxembourg
    Posts
    28
    Just now I had a problem: could not edit function blocks anymore by double klicking on them (in Firefox and Chromium)
    Maybe this is because I have a wrong understanding of the "vars" block??? Anyway, it happens when I put this into the vars block:
    Code:
    #include "MyTone.h"
    AudioControlSGTL5000 sgtl5000;
    const int ledPin = 13;
    MyTone mytone;
    I thought "vars" was for declaration of variables.
    I put the same code into a code block: no problem!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •