Build a MIDI controller with the Arduino, Firmata and Pure Data
Time to start contributing some knowledge back to the wonderful world that is the internet; today, a step by step nice and easy tutorial on getting started to building your own MIDI controllers with the arduino.
When researching for my ableton controller project, I didn’t find much out there about using firmata on an arduino to send data to software. The standard approach just seemed to be create the code in the arduino language, upload it to your board and hack one of those MIDI to USB cables as a bodge job way of getting the MIDI out of the arduino.
So why firmata and pure data? Well the whole idea of firmata is that you flash it to your arduino, and it throws out serial about whats going on with the arduino inputs and outputs, then you decide how the software treats the readings coming in and going out.
Theory out the way, lets build some controllers. You’ll need a few things…
HARDWARE:
An arduino and something to wire into it (for this i’ll be using a pot)
A USB cable for your arduino
SOFTWARE:
Arduino – http://arduino.cc/en/Main/Software
Pure Data – http://puredata.info/downloads
Firmata – http://at.or.at/hans/pd/objects.html#pduino
Something to patch your new controller into; like Reason or Ableton Live
- SETTING UP FIRMATA AND PURE DATA
Install Pure Data and create a folder to store all your patches somewhere. Unzip Firmata and add the files ‘arduino.pd’, ‘arduino-test.pd’ and ‘arduino-help.pd’ to your new Pure Data folder. The ‘arduino.pd’ file is the object that we use in PD for opening up communication with your arduino and routing it to PD. Done? Awesome, your software is almost set up.
- FLASHING FIRMATA TO YOUR ARDUINO
Install the latest version of arduino and open it up. Connect your arduino with the USB cable to your laptop (i’m using a macbook for this by the way). In the example patches, open up “Standard Firmata”, select your board (im using an arduino mega), and your serial port (look for tty.usbserial for use with a USB cable). Then compile and hit the upload button and your arduino is now ready to use firmata and communicate with Pure Data!
- WIRING UP A POT
Potentiometers are cool, and theres a great arduino tutorial of how to wire one up here: http://www.arduino.cc/en/Tutorial/Potentiometer
Basically, all you need to know is that there are three pins; your two outer pins govern voltage flow across the pot, meaning one has to be 5V and the other has to be ground. It doesn’t matter which, but your 5v pin is going to be where your pot reads maximum, so convention dictates this should be the right hand pin. The center pin needs to be connected to an analog in on the arduino and will read the value of the pot as it sweeps from ground (0v) to 5v.
All wired up? Plug it into your laptop and open Pure Data, we’re ready to get things talking.
- SETTING UP OUR PATCH
Open the example “arduino-test.pd” Pure Data patch you copied over earlier. It should look like this one…
The test patch has everything we need to open a connection and enable pins. Firstly, lets delete a bunch of stuff and make our window a bit bigger. Hit Command + E to enter edit mode in Pure Data.
Ok a quick explaination; the key component here is the ‘arduino’ object. This is being drawn from the file you copied in earlier, and is what communicated with your arduino. Here we can do everything to control the arduino from opening a connection, to receiving data.
The large grid allows us to set the mode of each pin on the arduino. Remember pins 0 and 1 are reserved for Rx and Tx. I’m using analog pin 4 for this demo, so I’ve set my pin mode for pin 4 to ‘analog’.
Now we can plug our arduino in and get a reading from the potentiometer.
- ARDUINO INTO PURE DATA
With your arduino plugged in, hit command and E to bring us out of edit mode. In our patch, click on ‘Devices’ above the arduino object and open up the pure data terminal. (That other thing that loads with PD that has all the scary code in)
The “Devices” message connected to the arduino object pings your computer to find what devices are connected and on what serial ports. Since we’re using a USB cable to connect our arduino, we’re looking for something with ‘usbserial’ in it, in this case; port 2.
Select the relevent port in the green box at the top (remember the first box is ‘0’, second is ‘1’ and so forth) and hit ‘Open’ to establish a connection. Check the terminal to see if the connection was sucessful.
Now lets check we’re getting something in. Create a number box (Command + 3) and connect it to the relevent pin on the ‘Route analog’ box at the bottom. In this case, pin 4.
One more thing; if you’re not getting any readings in, you’ll need to click on ‘pd old analog/digital controls’ and enable your pins here too. What I tend to do in my patches is just not include the large grid but make my own ‘old pd’ controls custom to what i’m enabling/disabling to save space.
Here’s what the ‘old analog/digital controls’ subpatch looks like (pin 4 enabled)…
Come out of edit mode and check that you’ve got readings. If so congratulations! If not, troubleshoot, start with making sure your usb connection is opened, make sure all the correct pins are enabled (remember you’re counting from 0 not 1 on most of these buttons in PD, it’s just the way computers work).
- SCALING READINGS TO MIDI
So we’ve got a reading and chances are it’s to 3 decimal places between 0 to 1. No problem, create a new object (Command + 1) and type “autoscale 0 127”. This allows us to scale the input to a min and max value, in this case 0 to 127 of MIDI. Next, lets get things looking nice, create a new object and type “knob”. Connect this AFTER the autoscale object. (the knob is default set to read inputs from 0 to 127. Then create another number to display the scaled MIDI data coming out, and finally a new object and type “ctlout 1”.
It should look something like this…
The second box should be outputing values from 0 – 127 now, and the knob giving a visual representation of your potentiometer.
Now lets patch it into ableton…
- PURE DATA TO ABLETON LIVE
Firstly, you’ll need to set up your macs IAC driver if you’ve not done this. Basically you’ll need to go into Audio/MIDI preferences and enable your IAC driver. Then create a new input and output. One for input to DAW and one for output from DAW. Google around for a tutorial on this, its really simple, a 30 second job.
After you’ve set up your IAC driver, go back to PD and go to preferences > MIDI Settings, and connect your IAC driver.
Open ableton and go to its MIDI preferences. Create a device listing for your IAC driver and enable its ins and outs into ableton like so…
And thats it! Create an instrument and try to assign something! I’ve got it controlling the brightness of a bass sound here.
Shout out for Facu who requested this tutorial. Hopefully it’ll help some of you looking to get into this stuff and start building things but with no idea where to start.
Problem loading libraries (iemguts)
Eighteen-year-old Shen Qiang says he soon thereafter began winning Canadian contests, and came in Canada in 2004. He will be a proud representative of the Canadian Olympic team this summer. While he didn't immigrate explicitly to further his table tennis career (he came with his family, who live in Toronto), he's happy with Table Tennis Canada's sports app, and is looking forward to the autumn opening of this new 24-hour training centre in Ottawa, so that he can work harder on his sport. Produced in northeast China, Shen first picked up a paddle at nine. He quit college to proceed to Harbin, a town 300 kilometers away, to train full-time and represent the province of Heilongjiang and had left home. The contest in China was extremely intense, '' he states. https://ok.ru/group/53953306755154/ The athletes trained five days a week, six hours a day; they were paid to train fulltime and compete, he says. "In China, it is very competitive because in the event you do not make results then you will be removed from the team, and if you don't have table tennis without a school, there is no future for you."
markovGenerator: A music generator based on Markov chains with variable length
Edit: There is a general [markov] abstraction now at https://forum.pdpatchrepo.info/topic/12147/midi-into-seq-and-markov-chains/45
This is one of the early projects by @Jona and me. Happy to finally release it.
markovGenerator
Generates music from learned material using Markov chains. It is polyphonic, plays endlessly and supports Markov chains with variable length.
markovGenerator.zip (updated)
Usage:
- Record midi notes or load midi files
- Make Markov system
- Play
-
Record midi notes or load midi files
Until you reset the memory, each new recording will be added to the memory. The recorded material is seen as a loop, so that the last note is followed by the the first note, for endless play. markovGenerator handles recording midi and loading midi files differently: When you record midi, it will record notes according to the midi clock every sixth midi tick. This is defined in the counter in [pd midiclock]. So that way, breaks are being recorded and the rhythm is preserved. When loading midi files, no breaks are being recorded, the notes are just recorded in order, so the rhythm will be lost. In any case, simultaneous notes will be recorded as chords, so polyphony is preserved. -
Make Markov system
Set markovOrder to specify the length of the Markov chain. The higher the order, the more musical information will be kept, the lower the order, the more random it gets. You can use soundFilter and channelFilter to only use notes of the specified sound or channel. This is especially useful when working with midi files. Note that if there are no notes of the specified sound or channel, the Markov system will be empty and nothing will be played. Set the filters to zero to disable them. If you change the settings for the Markov system, click makeMarkov again for them to take effect. You can make new Markov systems with different settings out of the same recorded material over and over again, even when playing. If you record additional notes, click makeMarkov again to incorporate them into the Markov system. -
Play
While playing, you can change the note length, sound and midi out channel. Set soundOut and channelOut to zero to use the sound and channel information of the original material. Playing starts with the Markov chain of the last recorded notes, so the first note might be played first.
Use the markovAll section on the right to control all Markov channels at once. Here you can also set tempo, swing and midiSync, and you can save the project or load previous projects.
Have fun!
If it does not play, make sure that
- you recorded some notes,
- you hit the makeMarkov button,
- soundFilter and channelFilter are not set to values where there are no notes. Try setting the filters to zero and hit makeMarkov again.
About the Markov system:
You can see the Markov system of each Markov channel in [text define $0markov]. Notes are stored as symbols, where the values are joined by "?". A note might look like 42?69?35?10 (pitch?velocity?sound?channel). Chords are joined by "=". A chord of two notes might look like 40?113?35?10=42?49?35?10. Notes and chords are joined to Markov chains by "-". The velocity values are not included in the chains. Sound and midi channel values are only included, if soundFilter or channelFilter are off, respectively. Markov chains of order three may look like 42?35?10-36?35?10=42?35?10-60?35?2 with filters off and simply like 42-37-40 with both filters active, only using the pitch value.
Requires Pd 0.47.1 with the libraries cyclone, zexy and list-abs.
Pure Data noob
Ok...... So I have been meaning to do this for a very long time......
I don't think it is the perfect "show_me_dollars" and so I will change it from time to time.
3rd attempt.........
show_me_dollars.zip
Here is a really terrifying screenshot, but I have also tried to explain it in words.
In many ways I think words ( below the screenshot) are easier to understand.
David.
Dollar $ variables in Pure Data patches.
A dollar variable is a thing that can be given a new value.
The new value can be a float or a symbol.
- If the Dollar variable is in an [object] box
A Pd patch can be saved and used inside another patch. We then call it an abstraction.... and it is just like a programming sub-routine.
If you want to use it many times then you have a problem, that they are all the same, so if you put an object [receive woof] they will all receive any message that you send with [send woof].
That might well be what you want to do.
But what if you want to send the message to only one of them?
You can give it an [inlet], but your patch will get messy, and what if your patch needs to make its own mind up about which abstraction it wants to send the message to, maybe depending on which midi note it received?
The solution is to give the abstraction arguments... some parameters that define it and make it different to the other copies.
For example [my_abstraction]
Let’s give it some arguments [my_abstraction 5 9 woof]
Inside the abstraction, as it is created (you open its parent patch) the dollar variables will be replaced. Wherever you see $1 written IN AN OBJECT it has been replaced by the number 5.
Number 5 because 5 is the first argument and has actually replaced the $1. You still see $1, but if you bang a [$1] object it will output 5.
[f $2] will output 9
[symbol $3] will output woof
So if you have an object [receive $1-$3] then it has now become [receive 5-woof]
And if you want to send it a message from outside, from another patch or abstraction, you will need to use [send 5-woof]
Every Pd patch, which remember includes your abstractions, also has a secret number. The number is unique and greater than 1000. As Pd opens each patch it gives it the number, increased by one from the last number it gave.
That number will replace $0 as the patch is created. You can find out what the number is by banging a [$0] object and connecting its output to a number box, or [print] object.
$0 can be used in any object as part of the name or the address, which means that a message cannot escape from the abstraction. A sub-patch like [pd my-subpatch] will be given the same number.
But from outside your abstraction you don’t know what it will be when the patch is created, so it is not useful. (A lie, you can find out, but as it can change every time you open your patch it is not worth the bother).
Use it to send messages within your patch [send $0-reset] to [receive $0-reset] for example, because the message is absolutely unique to its window, so you know it cannot interfere with other abstractions.
Use it also for objects like [delwrite~ $0-buffer 100] or for an array name [array $0-array] so that in each abstraction they have a different name and you will not have problems with their being "multiply defined"...... as each name can only exist once in your patch.
- If the Dollar $ variable is in a [message( box
Dollar $ variables are also replaced, but not as the patch is created (drawn by Pd as you open it).
Dollar zero $0 has no meaning in a message box. It will produce a zero if the message is banged, but that is it.
It is a mistake, a patching error, to put a $0 in a message box.
$1 $2 $3 $4 etc. in a message box are replaced by incoming atoms (individual floats or symbols or whatever) when they arrive. $1 will be replaced by the first atom in the list, $2 the second etc.
So if you have a message box [$1 $2 $3( ..... and you send into it a list [3 48 lala( .....then it will output 3 48 lala
That is not really very useful.
But it is actually very powerful.
Make a list in a message box........ [33 12 wav(
And bang it into a message box [open my-track$2-$1.$3( and you will get the output.........
open my-track12-33.wav
Which could be just the message that you want to send to [soundfiler]
P.S. If the first item in the incoming list is a symbol then it will be dropped causing errors.
You can fix that by making the message a list by passing it through the object [list].
Unfortunately only messages starting with a float are automatically recognised as lists.
C74 and my definitive Return2Pd
Again C74 shits on your users, as he makes enough with Pluggo.
Arbitrary changes and are not consulted frequently, but a change of license which means C74 owns everything that is created in Gen development tool, it really is a gesture of usury only expect from a corporation like Microsoft.
Many users have been developing in Gen since leaving, and read attentively the license before investing money, time and other resources to learn and develop.
/****************************************
Copyright (c) 2012 Cycling ’74
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*****************************************************/
/**********************************
Cycling ’74 License for Max-Generated Code for Export
Copyright (c) 2016 Cycling ’74
The code that Max generates automatically and that end users are capable of exporting and using, and any
associated documentation files (the "Software") is a work of authorship for which Cycling ’74 is the author
and owner for copyright purposes. A license is hereby granted, free of charge, to any person obtaining a
copy of the Software ("Licensee") to use, copy, modify, merge, publish, and distribute copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The Software is licensed to Licensee only for non-commercial use. Users who wish to make commercial use of the
Software must contact the copyright owner to determine if a license for commercial use is available, and the
terms and conditions for same, which may include fees or royalties. For commercial use, please send inquiries
to licensing (at) cycling74.com. The determination of whether a use is commercial use or non-commercial use is based
upon the use, not the user. The Software may be used by individuals, institutions, governments, corporations, or
other business whether for-profit or non-profit so long as the use itself is not a commercialization of the
materials or a use that generates or is intended to generate income, revenue, sales or profit.
The above copyright notice and this license shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*****************************************************/
Anyway
My return to Pd...
Ewolverine 4 U
New version 7 (currently testing)
- added automatic loosening of minimum fitness limit for the case that a population of sounds gets stuck in a local maximum in the fitness landscape (really nerdy jabbering, but trust me, it's useful ^^)
- added automatic "jumping" out of local maximums after a certain number of fruitless climbing-trials
EWOLVERINE v.7 by Henry Dalcke.pd
plans:
• bugfix: prevent a newly audible sound from being selected after manually stopping the target drive
• simulated annealing in target drive mode: span "temperature" value onto fitnesslandscape and decrease step length (modwheel) and probability value in the splice-pattern-generator the closer the fitness gets to optimal fitness value
• interactive mode: automatic narrowing of the range of generated parameter values around a mean value that's derived from the repeated selection of similar values of individual parameters throughout the generations (increases the number of similar sounds per generation that are located around a certain coordinate in parameter space; increases the likelihood of the generation of the desired sound in a smaller amount of time)
• stop-condition for automatic stopping of target drive
• make default settings for modwheel-position, splice-pattern-generator's probability, anti-stuck and allowed minimum fitness value in target drive adjustable from GUI
• adjustable MIDI output message blocker (useful for instruments with a fixed MIDI implementation, for instance: If you want to breed a bass drum in a drum synth with multiple instruments, you may not want to ruin the parameter adjustments of the snare drum meanwhile you're selecting for good bass drums)
• storage for self-created splicer patterns (maybe in connection to the MIDI output message blocker)
• low-value-weighted probability for the generation of MIDI-CC-values in new populations; switchable per MIDI-CC either manually or randomly (increases the probability for the generation of short attack and decay values in synth's envelopes)
• bigger populations for each sound-set: 4 more random sounds per set (A/B) to select from
• discontinuous MIDI messaging interrupted by assignment switching CC events (special build for FM-Heaven) - low priority
• possibility to interpolate between new random population's sounds to smoothly re-direct the modwheel-morphing path while morphing
• selection-history recorder that one can use to re-load the selected sounds of each past generation
• a visualizer that generates a "tree of life" from directions (keys C,D,E,F) and steplengths (modwheel) of formerly selected individuals and their respective distances to their parent sounds
how does [list drip] actually work?
it's a recursive thing: I'll walk through part of an example:
say the list has 5 elements.
The list comes in, and goes into the open spigot.
so at this point the [t a a a a] is sending a list of 5 elements. the following is what happens to the right [list-split] at this moment:
the first 2 elements of the list are sent back to the upper trigger, and go back into the spigot, where they are split again into lists of length 1. element 1 goes back into the upper trigger and out of the outlet, and then the second does as well.
All of this happens before the list of 5 elements is even sent to the left [list split], because of the trigger. A similar thing occurs:
the last 3 elements of the 5-element list are sent to the upper trigger and into the open spigot, and then the first element of that is split off and sent out the outlet. Then the last 2 elements are sent through the spigot and split, and are sent out in order.
The crucial thing to understand is the recursive nature; it has to do with the depth-first message passing in pd.
The first half of the list is split off before the second half, and sent to be split in half again before the second half of the original list is even processed. So it goes the first half of the first half of the first half, etc. until the first element is sent to the outlet. Then it goes back up the "stack" to the second halves of the lists that it missed in doing the first half every time (this happens because of the triggers). So after the first element is sent, the second element is sent. After that, elements 3 and 4 (in a list since they weren't even processed to be split yet) are split and sent out in order. then elements 5-8, which are still in a list, are sent back and processed in the same manner.
Hopefully that's somewhat clear..
(rambling extra stuff:)
From a "computer science" perspective, you could say that you process the first half and put the second half on a "stack" , and then go into the first half, split it in half, put the second half on the "stack", etc. And then after the 1st element is put out, repeat that process for each thing on the top of the stack until you end up with 1 element:
in "pseudocode" (with a datatype "list" and an assumed stack):
function splitlist (list inlist) {
list firsthalf;
list secondhalf;
if length(inlist) == 1 then {
output(inlist); -- pass the element
if stack exists then {
secondhalf = popstack(); -- get the next thing on the stack
splitlist(secondhalf); -- call the function recursively
}
} else {
firsthalf, secondhalf = split(inlist); -- split the list, pass to variables
pushstack(second half); --- push the second half onto the stack
splitlist(firsthalf); -- call the function recursively
}
}
I think that in reality most of this is taken care of in the computer's call stack, though not completely sure on how the memory for the lists is dealt with
Midi to hz, and hz to midi formulas
@dangrondang wrote:
The circles we calculated the orbits to be proved each to be slightly short of a true, pure circle, thus returning the satellites to the ground. Pi more precisely can be evaluated to 3.1446055, and not the perpetuation of imperfection, and the maintenance of ignorance still taught today.
Sorry to be blunt, but what you are stating is awfully incorrect and the way you proclaim to know this "hidden truth" is really awufully ignorant. So you are stating that there is a mistake on the 3rd decimal digit of pi... It so happens that this decimal place was precisely calculated centuries ago, and the result still (obviously) stands today. There are tons of different approaches on how to get correct digits of pi, such as by using certain convergence series as mentioned by @seb-harmonik.ar. One can manually calculate the 3rd digit of pi using these type of series, and this result has been known for more than a millennium (in the year 480, the value known was 3.1415926, which is way more precise than what you state. By the early 18th century, we knew 100 digits of pi, none of which have been "corrected" later on. See: https://en.wikipedia.org/wiki/Chronology_of_computation_of_π). There is no way that in the 1960's pi had to be defined as 3.1446... instead of 3.1415..., that is just pure ignorance and witchery.
But reading about your number on the internet, I found that this 3.1446055 appears in several articles about satellites, pyramids and all that "dark hidden world that nobody tells you about open your eyes sheep people controlled by the illuminati" kind of talk, but not a single time in a serious mathematical or physics website/journal/wiki. Sorry but the world is not a dark place controlled by people with magic powers trying to keep you in the shadows... simply do not use random blogs as source of information.
The assumption of equal temperament proves a repetitious vexation, denotes ignorance, apathy, laziness, and/or unfamiliarity with the math of music. Worse, this assumption proves far too common among engineers / mathematicians / scientists / software programmers. Which then deprives us musicians of useable tools, and the stupidity of the need for MIDI tuning standard / scala / etc, is the vacuum such engenders.
As for the "stupidity" of using a tempered system, that is just as stupid as using a non-tempered one: it is simply a convention, upon which we built centuries of music. Western music has been based on it for long time (although contemporary composers, myself included, often choose to use micro-intervals), and the decision to create MIDI around this is as logical as it gets when you think what they were aiming at. Or should we have went through all sorts of trouble to incorporate all crazy stuff in the MIDI protocol (which is an Western creation), such as the possibility of having Indian micro-tonal scales? But wait, then what about gamelan scales? No wait, what about <insert ethnomusic genre here> scales?
From a practical point of view, you can still use MIDI cents, and you can also directly use frequencies if you want to precisely define the pitch of a sound. You can compose music in 12-tones, 27-tones or 193-tones if you wish to. The tools are here, and Pd allows you to do whatever you want with them (I myself have composed works using Pd and MIDI that deals with microtones and microtonal glissandi in real-time).
I hope you won't get personally offended with my message, but I can't really read this type of statement, which tries to propagate pseudo-scientific kind of stuff, without writing a strong reply.
Best,
Gilberto
Better sounding guitar distortion ... beyond \[clip~\] and \[tanh~\]
Hi there,
thank you for your feedback !
@mod said:
wow, nice to finally see this!
why are highs contrary to what you'd expect? at a low sample rate, the highs are folded back into low frequencies, but when you upsample, the highs are preserved as true highs. i think it works just how it should. The upsampled version is certainly much clearer and brighter to my ears. Particularly with a high distortion level.
That makes sense. The upsampling workaround officially wins (I'll try x16)! I think I focus too much on highs, as I tend to find this disto patch rather 'acid'; the original sample sounds much darker than the distorted sound. I don't owe the actual pedal so I only rely on my 'feeling', which is far from reliable Of course it's logical to add highs with such a nonlinearity, and lows are filtered several times.
Anyway I still find the heavily distorted sounds have a strong 'schh schh schh component' in the highs, and I can't remember having heard that as strong in actual analogic effects. Would you agree with that? Of course I know this is a rather basic 'physically-informed' design, and that analog will always sound better
@mod said:
actually, this patch really demonstrates the effect of aliasing. if you turn the tone knob down as far as it will go, and also turn the distortion down to zero, and turn aliasing off, you can clearly hear the rustling noise caused caused by those wrapping frequencies.
turn aliasing back on again, and the noise is gone.
Very strange, when I do what you say, the upsampled version sounds like the 'not upsampled one', with a 'sch sch' noise added !
@Maelstorm said:
@nau said:
The BJT gains are bound to my 'signal amplitude policy' : input file or audio source and output should never clip. These gains can be seen as follows : the first one (before the clipper) adjust 'how early' distortion occurs, and the second one gives the distorted signal a boost in order to give similar subjective level than dry signal.
The values were found empirically.This might be where I have the biggest issue, though the article doesn't make it so clear, either. [...] the DS-1 isn't a baby's distortion pedal.
[...] Also, you don't need to calculate the boost into the filter coefficients. That's only useful for plotting. You can just use [*~] before or after the filter do accomplish it.
I understand all these arguments. I'll modify the patch. At the beginning I was using this kind of reasoning, but as the 'nominal input level' is -20dbu (http://www.bossus.com/gear/productdetails.php?ProductId=127&ParentId=254#), and the dbu definition I found seemed difficult to bind to 'our' db, I just dared to make the basic (36db-20db=16db~6.3 times in amplitude) operation... not far from the 6 in my patch Not very scientific, though.
Anyway I understood another reason why my 'subjective hearing' failed: feedind my patch with a 0db normalised sample maximizes input level, and the result will always be 'over the top' compared to non-active guitar pickups with a volume knob not always pushed to max. In other words, if I look at demos on youtube the result heard will be less distorted than my patch's. Anyway this can always be seen as an additional parameter for a 'parametric DS1 deluxe edition patch'
@Maelstorm said:
As mod said, it's not so much more highs as less lows, and those lows are a result of aliasing. To my ears, the upsampled version sounds less muddy. (By the way, in your upsampled portion, you have a different argument for the second [DS1-bjt_stage~]. Making them equal makes the difference even less noticeable, and draws more attention to the mud than the highs.)
Ok, upsampling wins !
@Maelstorm said:
Yes, there is a difference, but it's not a Matlab thing. It's the choice of the logarithmic scaling in the x-axis. The article uses powers-of-ten as equal distances. Mine uses [mtof] for the scaling, so that a semitone, octave, or whatever musical interval is the same distance. Also, I made an adjustment so that everything between 0 and about 20 Hz (at 44.1k) gets squashed in the leftmost 10% of the graph. If I didn't to that, then about half the plot would be taken up with frequencies below the audible range.
Ok, perfect ! Everything's cool now.
@Maelstorm said:
(commenting peaking after ToneStage)
This has nothing to do with your tone stage. It's because of the passband ripple in the Chebychev filters. The IEM Chebychev filters have a 1 dB ripple, though I don't actually know if that means +/- 1 dB or +/- .5 dB. Either way, it's creating a boost at some frequencies, and pushing the output down by 1 dB should keep it below [-1, 1]. This could also be contributing to the highs, as the ripple is typically more pronounced near the cutoff frequency.
Mmh, I thought the same, but then I decided to check the plots taken out of the 'not upsampling' part, and the peaking is still there ! The Chebyshev filters can be the source, then ...
@Maelstorm said:
The output from [tanh~] will never clip, so as long as you make up for the ripple and don't boost the second BJT stage, you should be fine.
[...]
Just one more thing to add for now, and that is you're doing too much in the upsampled portion. The only thing that needs to be in there is the non-linear function ([tanh~]) and the anti-aliasing filters. Everything else is linear and doesn't benefit from upsampling, so it's just creating more computational load.
Of course I precisely want to get rid of this peaking to be able to fully rely on [tanh~] to 'master' my output gain. I'll try the FIR instead of cheby (as proposed by acreil) some day. (I don't even know yet how they work and how I'll have to implement it).
I left the 'full upsampled chain' in this patch only to see if someone would have commented it, and we totally agree. But this 'playing the noob' attitude of mine is a rather raw 'fishing method' for getting stimulating information ... sorry this lead you to lay down the whole picture BUT nothing wasted, as your final 'delicate' -1db cut surprises me and I'll use it (when I'll get rid of peaking) and moreover, as you are reminding me that you use a 18000 cutoff freq, I'll give a look again at it, just trying to find a good criterion to pick one
Thank you everybody,
See you,
Nau
P.S. : sorry for those very long sentences ... not very clear
Polyphonic voice management using \[poly\]
Keeping track of note-ons and note-offs for a polyphonic synth can be a pain. Luckily, the [poly] object can be used to take care of that for you. However, the nuts and bolts of how to use it may not be immediately obvious, particularly given its sparse help patch. Hopefully this tutorial will clarify its usefulness. It will probably be easier to follow along with this explanation if you open the attached patch. I'll try to be thorough, which hopefully won't actually make it more confusing!
To start, [poly] accepts a MIDI-style message of note number and velocity in its left and right inlets, respectively...
[notein]
| \
[poly 4]
...or as a list in it left inlet.
[60 100(
|
[poly 4]
The first argument is the maximum number of voices (or note-ons) that [poly] will keep track of. When [poly] receives a new note-on, it will assign it a voice number and output the voice number, note number, and velocity out its outlets. When [poly] gets a note-off, it will automatically match it with its corresponding note-on and pass it out with the same voice number.
By [pack]ing the outputs, you can use [route] to send the note number and velocity to the specified voice. For those of you not familiar, [route] will take a list, match the first element of the list to one of its arguments, and send the rest of the list through the outlet that goes with that argument. So, if you have [route 1 2 3], and you send it a list where the first element is 2, then it will pass the rest of the list to the second outlet because 2 is the second argument here. It's basically a way of assigning "tags" to messages and making sure they go where they are assigned. If there is no match, it sends the whole list out the last outlet (which we won't be using here).
[poly 4]
| \ \
[pack f f f] <-- create list of voice number, note, and velocity
|
[route 1 2 3 4] <-- send note and velocity to the outlet corresponding to voice number
At each outlet of [route] (except the last) there should be a voice subpatch or abstraction that can be triggered on and off using note-on and note-off messages, respectively. In most cases, you'll want each voice to be exact copies of each other. (See the attached for this. It's not very ASCII art friendly.)
The last thing I'll mention is the second argument to [poly]. This argument is to activate voice-stealing: 1 turns voice-stealing on, 0 or no argument turns it off. This determines how [poly] behaves when the maximum number of voices has been exceeded. With voice-stealing activated, once [poly] goes over its voice limit, it will first send a note-off for the oldest voice it has stored, thus freeing up a voice, then it will pass the new note-on. If it is off, new note-ons are simply ignored and don't get passed through.
And that's it. It's really just a few objects, and it's all you need to get polyphony going.
[notein]
| \
| \
[poly 4 1]
| \ \
[pack f f f]
|
[route 1 2 3 4]
| | | |
( voices )