Controlling a sawtooth with the keyboard
This is a video on controlling a sawtooth with the computer keyboard in Max. This project will have three components: the oscillator (a sawtooth wave), the keyboard control implementation, and an amplitude envelope. For the oscillator, we can use the saw~ object. And since we probably want to control the volume, we'll use live.gain~, while setting it for one channel, and the orientation to horizontal. As with most DSP projects, we might need and ezdac~ too! For the keyboard control implementation, we will rely on the key object. The key object sends out an ASCII code of the Key pressed. So, if I lock the patch, and start pushing keys on my keyboard, you'll see the ASCII code. For our implementation we'll use the row of keys from A to J, and some of the keys from the row above, to serve as our keyboard control. Now, we can note down these numbers on a piece of paper but, since we are in Max (and you are eager to improve your programming skills), I'm going to use Max objects. I'm going to use zl.group, and connect it to a "t l l" (trigger list list), which will send the list to a message - that will hold our results -, and back to zl.group. This will receive its values from a "t b i" (trigger bang integer) which will send the integer and bang the zl.group. Also, let's add here a "zlclear" message so that we can clear our memory before we begin. I'm going to press the A key, W, S, E, D, F, T, G, Y, H, U, J, and also K. After this, we can delete the patch cord, for we already have what we need. Let's copy the content of the message box and paste in on a select object. Now, I could create message boxes to do whatever I need to do after each of these options is triggered, but I'm going to use a more clever way to do this. I'm going to use the funnel object. I set the argument to 13, because we have 13 options. Then, I need to connect each option to the inlets. The way funnel works is that it sends out a list composed of the inlet number where it has received a message, and the message itself. It works something like this. So, what we want is this first part of the message. We can retrieve just that using a "$1" message. Since we are doing this, we probably want to have the A key to be sending out number "60", as in MIDI note number 60. For that, since we are starting in 0 up to until 11 - or 12, with the K key -, we can use the + object, and write as "+ 60". Now, since we are doing all this, we might as well implement a way to change the octave. Let's use the Z and X key, which is 122 and 120. Let's add those two options to the select object. And we will rely on incdec object, which will increase a number and decrease a number. This object receives the "inc" message and the "dec" messages, that we can connect to the options on the select object. In turn, we will connect these message boxes to the incdec object. The way it works is that it sends out a number like this: when I press the Z key it will low the number, and when I press the X key it will increase the number. Again, because we are dealing with octaves, we need to multiply that number by 12. And that will serve as an offset; so we can use another + object to combine the "+ 60" and "* 12" objects. Now, this is a MIDI note number and the saw~ object is expecting frequency. Fortunately, there is an object to help us solve this problem - the mtof object. Let's give it a try. Cool! Let's build the amplitude envelope section now. We will use the function object and set the domain to 1000 - as in 1000 milliseconds for the duration of our envelope -, and the line~ object. Fortunately the second outlet of the function object sends out a message already formatted for the line object. And since we want this to interact with the saw~ signal, we need to insert a *~ object here. There is one last thing: when we send a number to the mtof, that will change the frequency, we need to trigger the function (which we also need to draw, by the way). The way this function is triggered is by receiving a bang. So, we can use between the last + object and the mtof object a "t i b" (trigger integer bang), so that when we send out an integer here, we can also trigger the function at the same time. Alright, that should work. And there you go!