*** MUS171 #09 02 01 |
Miller: @0000 What I'm going to try to do today is push on through designing samplers -- both from the point of view of |
es: @0000 |
@0015 having them message-activated and the point of view of having them run from phasors. What happened last time -- which might be worth a quick review is: a sampler which is able to make samples with a |
es: @0015 |
@0030 desired transposition and a desired size of place in the sample that you're going to play back, driven from messages -- in such a way that you can do things like start notes. (You can regard samples to be things that |
es: @0030 |
@0045 can play notes.) |
es: @0045 |
Miller: And I just grabbed a copy of that patch. Oh, this is the patch after I edited it to put it up on the website. So this is a bit cleaner @0060 than what you saw in class. <<opening "2.01/0.sampling.envelope.Pd">> But this is pretty much where we got. The situation was this: There's a tabread4~, which is playing the sound, and the sounds |
es: @0060 |
@0075 are being turned on -- not by a phasor object .. In other words the control, the impetus of the patch isn't coming from tilde objects -- from objects that make streaming samples -- but from messages. |
es: @0075 |
And in this case, there's a metronome, which is @0090 spitting out copies of some pitch. [tone] Miller: There you go. [tone] |
es: @0090 |
Miller: All right. Let's turn that off. Oh, this is now going to be the pitch of the thing. @0105 Did you hear it? [tone] |
es: @0105 |
Miller: OK. So what's happening is, there's a metronome twice a second, a number is coming out. Oh right, number boxes: If you send a number box a bang, such as comes out of the metronome @0120 it simply outputs what the number was. So also I can also output it just by mousing on the number box itself. [tone] |
es: @0120 |
Miller: Right. And there was work to do, which I always review for you if you are curious about it. But for the moment the idea was to figure out how far you were going to go @0135 in a fixed amount of time. And so what happens to the tabread4~, is it eventually gets a message to tell it to go somewhere in a certain amount of time. |
es: @0135 |
The time is computed to be the number of seconds you want to go 100,000 @0150 samples in. <<at 44100 samples/second>>. So I just got out a calculator and found that out. There was this number <<2268>> of milliseconds. And now so if you gave it 100,000 that would mean you were playing the thing back in its own speed. |
es: @0150 |
@0165 And then also we could compute other speeds and get intervals from that. And then it got all Music 170-ish, trying to figure out what numbers to throw in there. OK. Questions about that? Student: How do you select the part of the audio to output? |
es: @0165 |
Miller: Oh. Right. @0180 I didn't say that, in fact. How do you select what part of the audio? Really, there are two messages going in -- which in fact perhaps I should print. So, let's make a print object. A regular message print object because all of this |
es: @0180 |
@0195 is being done with messages. So, yeah. Actually I'm just realizing, looking at it, that it's always starting from the beginning. So here, we say |
es: @0195 |
@0210 60. [tone] |
es: @0210 |
Miller: And what comes out is first the message 0 and then the message "slide to 100,000 (approximately) in the correct amount of time."<<2268 milliseconds>> And this is the only number in @0225 the pair of messages that will change when you ask it for a different pitch you will compute a different value of that. So, in fact I have shown you other ways of making samplers, where you could go in and select where to hit play. |
es: @0225 |
@0240 And you could easily adapt this to do that: What you could do if you want to start somewhere other than 0 you would add whatever the number is to this 0. And you would also add it to this number here. |
es: @0240 |
And then you would have a thing that had a controllable offset in the sample, right? @0255 The other thing that's potentially confusing about this is that you don't hear an entire 2.-something second long sound. When the thing happens you only hear something that lasts |
es: @0255 |
@0270 a few milliseconds. [tone] |
es: @0270 |
Miller: And that's happening because the thing is being enveloped, so the signal processing network that you see really is: this line is generating @0285 the addresses of the samples in this array here. This line here is turning the thing on and off -- well, fading it and out -- it's being used as an "envelope generator," in classical synthesizer-speak. |
es: @0285 |
@0300 So this is a thing, which starts at 0, ramps up. Oh! I should print that for you too. How about we do this? This is going to be the, what do we call that, address. |
es: @0300 |
@0315 And this is going to be the line controlling the envelope. And the envelope ... This line~ which is doing the envelope is getting messages, here, here, and there. So I should show you all |
es: @0315 |
@0330 three of those. You won't actually see the timing but you will at least see the sequence. I'll hit this again ...[tone] |
es: @0330 |
Miller: Now go look at the Pd window ... @0345 And now what you have is: -- Oh yeah, I didn't tell you but you can feed print an argument, ask it to say instead of "print:" "something:". So, the envelope generator is getting sent to 0. And then after five milliseconds |
es: @0345 |
@0360 of wait, of delay, it sets the address to 0 and the envelope generator starts ramping up. |
es: @0360 |
The reason to have that delay is so that you don't hear the address get reset to 0. So what is happening @0375 is when you give it a number it doesn't actually start playing a new sample for five milliseconds. Because it has to take care of whatever might have been happening before. Then after another ... -- oh right so |
es: @0375 |
@0390 these three things, I'm not sure why they're in that order. But at any rate these things should be roughly at the same time. |
es: @0390 |
@0405 The address should be zeroed out and then should be ramped to a 100,000. And meanwhile the envelope generator should be turned back on at whatever speed. At a speed which is controlled by whatever attack time you want. |
es: @0405 |
And then after @0420 you're ready to end the note, which is some time in the future, you turn the envelope generator back off. And the address is still ramping at that point. It certainly is in this case, because it's only in a tenth of a second in. |
es: @0420 |
@0435 But the fact that you multiply it by zero means that whatever is happening to the array, the tabread4~ is not being heard. And so the thing is effectively turned off. So again as with oscillators, if you want to turn something off, you don't actually turn the oscillator off in general. |
es: @0435 |
But the better way to do it @0450 is to cut the amplitude off by multiplying by something that you ramp to 0. And so that's happening here with this line~. And now, |
es: @0450 |
@0465 what bothers me about this, I guess it's all right ... OK. Are there questions about this. I have to take the print object out |
es: @0465 |
@0480 because I think people are OK with it. |
es: @0480 |
So there are two topics today. And they take this thing in a different directions. -- Each of which is an important direction, but this is the starting point. But they don't actually @0495 have anything to do with each other. The first one is, going back and showing how to make something similar but deriving it from the phasor~ object, in case you want to make a looping sampler that's driven from a signal. |
es: @0495 |
And the second thing to show you is a @0510 more interesting and general thing, which is how to make polyphonic stuff in general: |
es: @0510 |
That's to say, "Now I've got a nice voice of this, what would I do if I wanted to have eight of these?" And be able to play a chord or what-not -- a sequence @0525 that might be polyphonic. |
es: @0525 |
And what I want to do is, since it's simpler, is go over the phasor~ -driven thing first. And then that should be easy but then the polyphonic voice allocation could be hard. @0540 So that can come afterward. So, I can close this and move on to the next thing? ... |
es: @0540 |
This is from last week. <<opening "2.01/2.phasor.sampler.Pd">> ... @0555 OK, there are things that I haven't done here ... |
es: @0555 |
@0570 This is stolen from a patch that you saw sometime last week, I think. And this is the way of reading from a |
es: @0570 |
@0585 tabread4~ if -- instead of having a line~ generate things to feed into it (that is to say locations or addresses) -- you want to use a phasor~ to drive it. Now, line~ will go from anything to anything depending on what messages you send it, but phasor~ goes always |
es: @0585 |
@0600 from 0 to 1 -- It's just a phase generator and phase is considered in cycles. So, with phasor~ you'll then have to take it and renormalize its output to reach where it is that you want it to go. |
es: @0600 |
So here @0615 is the...let's see, we get the table now, so stupid of me to close that other one ... Oh, still there. So you don't have the... |
es: @0615 |
@0630 This is what happens when you move a patch from one directory to another that uses other files. ... The other thing that's wrong is that I made it bigger |
es: @0630 |
@0645 in order to put it on the web, now it won't fit on my screen anymore. So what I have to do is go copy this thing. |
es: @0645 |
@0660 Now, do I have the other window? |
es: @0660 |
I just wanted to @0675 get this thing to read. Actually that's OK. I'm going to get it along with this stuff which might be using. I'm going to close that and get over here |
es: @0675 |
@0690 where we're actually working and put that down, get it out of the way. All right! ... |
es: @0690 |
@0705 We're back where we were before. In fact I am going to get properties out here ... well I'm going to do that later ... so this has a bad name -- but we'll live. |
es: @0705 |
So, this now is a thing where you tell it how many per second you want, @0720 so 5 per second maybe, and then you tell it how big a sample you want it to read in that amount of time. Let's see, it's in hundreds of samples, so I'm going to ask it to read a whole second's worth. <<441 X 100 = 44,100 samples>> Oh, so this is one per second then. |
es: @0720 |
@0735 Now we listen to this:[tone] |
es: @0735 |
@0750 So this is just a looping sampler, but it's a looping sampler that doesn't have a metronome that has to generate messages to make it start up. Instead it's a looping sampler that loops just because phasor~ likes to loop. Here, again, you could wish to fix the problem |
es: @0750 |
@0765 that whenever it loops it has a discontinuity in the sound. So to emphasize that discontinuity let me make the thing go faster and have less. That would be |
es: @0765 |
@0780 882 [tone] ... Woah!? 88.2 |
es: @0780 |
Looking for a bad click. ... @0795 Can't hear the clicks in there. There is a click, but it's getting lost in the sound. Maybe if I make it shorter it'll be more obvious? |
es: @0795 |
@0810 I'm not sure. Oh -- There we go! OK, this is a bad setting because I think I put it right where it was breathing in. But if you start moving around the sample maybe ... [tone] |
es: @0810 |
@0825 I'm trying to find something that has a useful sound and has a click; I'm not succeeding. ... There we go! |
es: @0825 |
@0840 All right. OK. So there's a nice sample. This would be a nice thing to be able to have, but it would be nice to be able to have it without the clicks. The clicks, by the way ... If we go faster than 30 a second they won't sound like |
es: @0840 |
@0855 individual clicks, but they'll still be a part of the sound. |
es: @0855 |
It'll just make the sound, sound buzzy, so now we've got a nice little buzz generator. OK. @0870 So this is a useful tool, but this would be more useful perhaps if it didn't sound buzzy. That buzziness is the same issue as the fact |
es: @0870 |
@0885 that it was clicking when it was going slower. |
es: @0885 |
OK. Is it clear what I'm doing? I don't think I gave you this particular collection of window size and speed before ... But what's happening is this number here @0900 is being added to the output of the phasor that's already been ranged. So when I'm changing this value I'm changing where in the table it is. OK? |
es: @0900 |
@0915 Meanwhile, this portion of it is doing nothing but generating a ramp that is repeating at 76 times per second, so that's controlling the pitch that you hear. |
es: @0915 |
@0930 This is controlling how much of the sample you get. A wonderful thing happens when you change that now. [tone] |
es: @0930 |
That kind of stuff. OK, now @0945 I'll explain a little bit better why that sounds like that later. You can sort of explain that, although it takes a little bit of work. So let me |
es: @0945 |
@0960 go back down to a reasonable speed, perhaps 10 a second. At this point I can find the place where it makes it click. Nice. Diesel motor. |
es: @0960 |
Anyway, there's a click and now I'm going to try to get rid of it. @0975 The way you're going to get rid of it is you're going to envelope, but it's not going to be easy to envelope this using the line~ because you don't have a source of messages that will tell line~ to do its thing. |
es: @0975 |
With some work you could do it @0990 and if you really wanted to you would use the "threshold~" object to try to get a message out when this phasor~ crossed a certain threshold, but you'd have to figure out where in the phasor you'd want to start doing the thing and so on. It would be a lot of work. So less work is just to |
es: @0990 |
@1005 do the smart signal based thing. ... Yeah? Student: How does the 0 in "pack 0 50" get used to turn the volume on and off? |
es: @1005 |
Miller: Oh, thank you. Yup. This turns it on and off. So this "pack 0 50" -- this 0 @1020 is getting overwritten by 1 or 0 depending on whether I turn this thing on or off. (That relies on the fact that the toggle switch or the toggle itself outputs numbers, which are 1 or 0 |
es: @1020 |
@1035 depending on whether it's on or off.) OK. ... Yeah? Student: Have you written comments for this patch as well? |
es: @1035 |
Miller: Well, I write the comments when I put them up on the website. @1050 So it happens afterward, except that last Tuesday never got commented. But if you go looking on the website now you should be finding stuff like this. But they're telegraphic comments. |
es: @1050 |
@1065 What I'll do is I'll make a copy of this and fix it so you can see the before and after. |
es: @1065 |
@1080 Oh, you know what? This is the first of the objects I'll introduce for the day:<<Pd>> which is "Make a sub-window please." |
es: @1080 |
Actually, I've already shown you this, but I'm going to be using it again today so I'll re-introduce it. There we go. @1095 Put it here here, All right. Put it in a more decent place. And by the way, here we have a sample. OK? So now we have a sub-patch, which has the sample in it so, you don't have to look at it, right? |
es: @1095 |
@1110 Now, so what we're going to do is again, going to be to multiply the tabread4~ by something, which will make it not click. The only difference is that the multiplication |
es: @1110 |
@1125 won't be by a line~ output. It will have to be by something else. And what? |
es: @1125 |
Miller: Well, the answer is deceptively simple: So, phasor ... Phasor is going @1140 from 0 to 1 and you want it to be 0 at the beginning. And then you want to go up to some value like 1. And then you want to stay at 1 for a while, perhaps and then you want to go back down to 0. All right? |
es: @1140 |
Well you could do that algebraically in a variety of different ways. @1155 The simplest way to do it would be this: So recall that if you just ... |
es: @1155 |
Oh!-- Did I tell you about cos~? I think I threatened to tell you about this, or I didn't, did I? I should've. If I told you about cos~, @1170 it would have been first week. This is a thing which takes things from 0 to 1 and turns them into the cosine of 0 to 1. |
es: @1170 |
In fact, at this point, it would be a good thing to have another table to just look at the output. So what I'll do is put another table, @1185 an array. It's going to be... I don't know what, "scope"? |
es: @1185 |
And it needs to have ... I don't know ... some samples in it. I'll make it a tenth of a second. <<4410 samples>> @1200 Let's see. OK. Here we are. And now, for instance if I look at what the phasor's putting out... |
es: @1200 |
Miller: @1215 Let's see, OK. Put a button in it so we can see it. Phasor will be putting out 0 's until I give it a frequency. |
es: @1215 |
@1230 Let's give it a frequency of 20 and then we'll see: A sawtooth wave! -- And I made this thing be a tenth of a second long ... maybe that's a little bit not enough ... |
es: @1230 |
Since I made this thing be 20 Hertz -- 20 times per second -- there are two cycles @1245 within one-tenth of a second. It's all correct, right? So now, if I just take the cosine of that... [pause] |
es: @1245 |
Miller: I'll get that sort of thing. @1260 And that's all right, except... Oh, and its value is 1 at the beginning and end of the phasor. So when the phasor amplitude is 0 or 1, the cosine puts out 1. Right. ... Yeah? Student: It gives you the opposite of the phasor~? |
es: @1260 |
Miller: Yeah. So now what you need to do @1275 is get it to put 0 out instead of 1. So you need to put it upside down. So the way to do this is then to multiply it by -1/2 ... |
es: @1275 |
@1290 You can't actually see the fact that it got multiplied by minus a half because you don't see that these points are now the 0-points of phase. If I'd |
es: @1290 |
@1305 made it graph both the phasor~ and the cos~, you could see that. Now that we've got that we can adjust it so that it goes down to 0 instead of going down to -1/2. |
es: @1305 |
@1320 We can do that by just adding point .5 ... |
es: @1320 |
And then, tada! -- We've got a thing that @1335 starts at 0, ramps up to 1, and then ramps back down to 0. ... This takes a bit of thought to get figured out, so I should stop here and make sure everyone's with us. |
es: @1335 |
@1350 Should I try to graph the phasor, too? Why not? What we'll do is let's put another array, but I'll put it in |
es: @1350 |
@1365 the previous graph. I'll say this is going to be the same size. <<creating array "scope2" in the same graph>> |
es: @1365 |
OK, now we have two @1380 things getting shown in the same graph. Now what I'm going to do is make two "tabwrite~" 's controlled by the same button so you can see both of them simultaneously. I'm going to show you the phasor~ and |
es: @1380 |
@1395 the result. OK. So the phasor is going from 0 to 1 like this and then jumping back down to 0 and the cosine wave that I'm making is going |
es: @1395 |
@1410 through 0 when the phasor is at either end of its trajectory. |
es: @1410 |
The original cosine was not suitable because it had two flaws. One is it @1425 didn't stop at 0, it went all the way negative, and the second thing is it wasn't at its least value at the transition point of the phasor where you want the thing to be off. This hits its maximum. |
es: @1425 |
@1440 So the first step is to invert it by multiplying it by minus a half. That gives you this. Now we've got the thing hitting its minimum when the phasor |
es: @1440 |
@1455 changes phase from 1 to 0, so this is a good thing, but it's not at 0 anymore. |
es: @1455 |
It's at -1/2 . So now we're going to add 1/2 and then instead of going from -1/2 to +1/2, it goes from 0 to 1. @1470 If you want to be fancier you could ask for the thing to have a different transition shape or have a different amount of time that it transitions from 0 to one instead of the entire half of the |
es: @1470 |
@1485 cycle that this one takes to transition from 0 to 1. But for right now I'm just going to do the simplest possible thing, which is just this. So this is multiplying by -1/2 -- And then adding 1/2 gives you this. |
es: @1485 |
@1500 This thing, the cosine ... This cosine is sometimes called a "raised cosine." It has a name: It's sometimes |
es: @1500 |
@1515 called the Hann Window and people use it also to multiply snippets of signal by before they take a Fourier transform of it in order to do either a frequency domain analysis of it or convolve it with something else or something like that. |
es: @1515 |
@1530 So you will see this trick of taking a cosine wave and raising it so that it's tangent to the horizontal axis and then multiplying it by a signal in order to control how it acts at both ends of it -- |
es: @1530 |
@1545 We'll see that again over the course of this and the next quarter. So one cycle of this is called a Hann Window sometimes. <<clicks to get different starting-points in the graph>> There's a cycle there. What this |
es: @1545 |
@1560 patch is doing is doing them end to end. So you can think of the patch not as just making continuous sound but also, if you like, as making a succession of Hann Windows -- a "pulse train" if you like -- which is pulsing every time the phasor cycles |
es: @1560 |
@1575 and the maximum pulse is in the middle of the cycle of the phasor. Yeah? Student: So if you used that signal as an index to the table, it would read out at varying pitch? |
es: @1575 |
Miller: @1590 If we use this to generate the index into the table that's exactly what would happen. And that would be interesting. Yeah. I don't want to hear it right now, but that would be a thing to try. The reason I'm doing this is |
es: @1590 |
@1605 so we can take the original sample output, the sound output, and multiply by this, in order to control its amplitude. So instead of going into the tabread4~ to control the location that |
es: @1605 |
@1620 it's reading at, I'll take this thing and multiply it by the output. |
es: @1620 |
Let's see. I should get these two to have the same values. This is 10. @1635 This is 14. This is 86. ... So here's the original one [sound] and here's the windowed one. [sound] Now, you could either |
es: @1635 |
@1650 like this more or less. This is not a thing that you have to do because this is right and the other thing's wrong. It's just that this has a spectrum that more correctly imitates the spectrum or sound of the original |
es: @1650 |
@1665 sound that we had. Whereas this [sound] has got more highs. And you can like that, but it also has more distortion in some sense because you hear |
es: @1665 |
@1680 something that wasn't really present in the original sample. Any questions about this? ... Yeah? |
es: @1680 |
Student: @1695 Isn't it possible to just filter out the high frequency noise? |
es: @1695 |
Miller: It is. Yeah, right. Right. So that's another whole thing you could do. Rather than take this thing and take the highs out by windowing it, @1710 you could also take the highs out by low-pass filtering it. But you would also take the highs of the original sample out. Whereas here, if the original sample has highs they'll still be there when you window it. (They'll be different in some way, but they'll still be there.) |
es: @1710 |
@1725 Yeah. Other questions? OK. |
es: @1725 |
So this, multiplication by this window -- @1740 I'm going to clean this up a little bit so you can see a little bit better what's happening; I'm going to make this not collide with itself -- |
es: @1740 |
@1755 This is the same as that; what I added was this multiplier and that corresponds to the multiplying by the line~ in the other realization of the sampler. |
es: @1755 |
It just had to be @1770 done differently because ...<<opening "2.01/0.sampling.envelope.Pd">> This line, which is the envelope generator which is controlling |
es: @1770 |
@1785 the other one... This was feasible because I had a sequence of messages here generated by a metronome. |
es: @1785 |
In the other one I didn't have the sequence of messages because it was generated by a phasor~, which is operating continuously -- it's an audio signal. So I had to do something different. This <<patch using messages & metro>> @1800 is perhaps more flexible, but at the same time it's more complicated and there are also some disadvantages to it. |
es: @1800 |
In particular, these messages happen between @1815 audio samples. In fact, they happen between blocks of audio samples. So what really happens downstairs in Pd is that Pd grinds out 64 samples at a time in order to be efficient and these messages actually happen on the 64-sample boundaries. |
es: @1815 |
@1830 Pd tries to hide this fact. But at the same time what that means is you don't have sample-accuracy in when the tabread4~ actually started reading the sample. So if you want that level of accuracy it's more appropriate, I think, |
es: @1830 |
@1845 to use the signal approach rather than this approach. |
es: @1845 |
On the other hand, if you've got MIDI coming in to start things out you don't have that accuracy anyway and this is the better approach. So they just both coexist and you have to get a sense of @1860 when to try one and when to try the other. It's clear what the distinction is between those two? ... |
es: @1860 |
So that's kind of done, this. @1875 Now what I'm going to do, not to belabor this anymore because now I can launch a whole diatribe about how to make different window shapes and that can be a lot of fun, but that's for a little bit later on in the quarter I think. |
es: @1875 |
@1890 But now I want to start working on polyphonic voice allocation so we can turn thiese thing into fun instruments that you can run and play chords. OK. So to do that the main tool is going to be the fact that you can |
es: @1890 |
@1905 put things in sub-patches with an interesting twist -- and this is all Pd lore as opposed to real computer knowledge ... |
es: @1905 |
The twist is that in Pd you can ask it to have a patch loaded from a different file into a @1920 sub-window and if you do that then you can have multiple copies of the sub-window and when you edit one of them they will all be edited in a way that stays coherent. |
es: @1920 |
This doesn't sound all that important yet because, obviously, you can make eight copies @1935 of something and if you want to change it you can just change it in all the eight copies, but it will become important as things become more complicated to be able to keep things coherent. |
es: @1935 |
The way to do that is very simple in principle and then in the details @1950 it gets complicated, so first I'll show you the simplicity in principle and then I'll make everything unbearably complicated, for the next half hour. What I'm going to do is save this. ... |
es: @1950 |
@1965 I think, for pedagogical reasons, it would be smarter to start with the other flavor of sampler, which I already closed. So this one: <<"2.01/0.sampling.envelope.pd">> -- Except that I'm |
es: @1965 |
@1980 going to rebuild it for the most part. |
es: @1980 |
But just for now ... It's called "0.sampling.envelope" -- What we're going to do is make a new patch and then we're going to put an object in. We're just going to say @1995 "0.sampling.envelope" . Then, if I open this, I get my own patch. Furthermore, if I ask for several of these, I have copies of "0.sampling.envelope". |
es: @1995 |
@2010 (Notice I'm getting all sorts of errors because I'm doing things that I shouldn't do.) |
es: @2010 |
... Things that are named -- You shouldn't have copies of that have the same name because how do you distinguish it? So @2025 that's basically it -- I mean, that's how you cause a patch to load other patches. |
es: @2025 |
Now if I wanted a five- or eight-voice sampler I would load eight of these things and then I would do the hard part, which is figuring out how to get messages into them appropriately @2040 to do what it is I wanted to do. So if someone says "Play three notes" I don't want it to tell the same voice to play all three notes. |
es: @2040 |
I want to choose three of the voices and assign one note to each of those voices. Then I have to have them @2055 be able not to be mixed up about which one is doing what. That takes bookkeeping and attention to detail, which I will now show you how to deal with. Questions on what I've done so far? ... Yeah? |
es: @2055 |
Student: @2070 With the sub-patch, if you want to re-edit it after you make it is that a problem? |
es: @2070 |
Miller: It's OK, but here's the thing: I can edit this and it won't have been @2085 edited in the other one until I hit "save" in this one and then when I save it the others will all have the same edit. Then the others have the same change. |
es: @2085 |
@2100 Notice, by the way, this one didn't read the sound files because I told it to read it in a message by name and it didn't know which one of these tables I meant when I named it because they all have the same name, so we have to deal with that. |
es: @2100 |
Right now, my way of dealing with it @2115 is going to be brute force and stupid. I'm going to take this and get rid of it -- By the way I hit "save" so I get rid of it in all three of them. And then go back and do what I should have done before. <<making a subpatch "pd soundarray>>. |
es: @2115 |
@2130 Put it here. By the way, I'll just whack |
es: @2130 |
@2145 the loadbang action so we'll get it. So now we have three things, all of which amount to sub-patch. Oh, I just made a bad mistake. |
es: @2145 |
I actually saved this patch. Well, it's all right, it's a copy @2160 from another day so the original patch is still there. So now we have two different kinds of sub-patches: This one <<0.sampling.envelope>> is called by a file name and this one <<pd soundarray>> is called by saying "pd" and this one <<pd soundarray>> will be saved as part of |
es: @2160 |
@2175 this patch. So anything that I put inside here is part of this document and if I change something in here the change is reflected by ... Let me save this thing so I don't get in trouble later. <<"3.poly-sampler.pd">> |
es: @2175 |
@2190 This is going to be three. I'm going to be optimistic and call it a polyphonic sampler. All right. |
es: @2190 |
@2205 Now what we need to do is get messages into sampling envelope <<0.sampling.envelope>> to cause it to do things. In fact, since it's a polyphonic sampler, let me do something that's going to be essential |
es: @2205 |
@2220 for our mental health: which is to have the array actually be this one <<from oh.wav>> |
es: @2220 |
Whoops, don't have it. All right, I wasn't going to tell you this, but rather than move that one in <<to the current directory>> I'm just going to call it @2235 by its relative path name.<<"../1.17/oh.wav">> I'll fix this later. I'm going to have that be the loadbang action. |
es: @2235 |
That's because I want to be able to have different pitches of it and have you be able to hear it and if it's saying ... if we have another three whatever -- "@2250 ...soft and relaxing..." it's going to be harder to hear what's going on. So now if I want to hear one voice of it, for instance, I can go in here and say 60. There it is. [tone] So now I have a nice |
es: @2250 |
@2265 monophonic sample. Cool. Now how do I make it polyphonic? |
es: @2265 |
@2280 First off, we probably shouldn't have the metronome in here, but what we should have is an "inlet". Now, when I say inlet notice it puts an inlet |
es: @2280 |
@2295 in this box. In fact, when I save this box it's going to put an inlet on all three of them and that inlet corresponds to the fact that I said "inlet", which is an object whose purpose is to put an inlet on the patch |
es: @2295 |
@2310 if it ever gets called as a sub-patch -- as an "abstraction." |
es: @2310 |
OK. So this is one of two ways you can get the messages and signals into and out of sub-patches, which is you just make inlets and outlets @2325 in there and connect them. I should say at some point there is such a thing as inlet and also inlet~, like this -- which |
es: @2325 |
@2340 is the signal version of it which makes an inlet that expects audio signals. That's a different thing from making an inlet that expects messages. You'll see that later in gory detail. I'm going to try to keep things simple today. -- |
es: @2340 |
@2355 Just do "inlet". |
es: @2355 |
So now this is kind of cool. Save this and close it. Now I've got something where I can say, for instance, number ... @2370 [tones at different pitches]. That's ugly! |
es: @2370 |
Maybe I should go in and make the envelope be a little more assertive: Like this: @2385 [tone] |
es: @2385 |
So 50 milliseconds was too slow for having the voice start in that particular instance. OK. Now, for instance, if I want @2400 nice major chords I'll say OK why don't we add 4 to be up a musical third. Actually, let's make it simpler conceptually. Then add 7 which is a |
es: @2400 |
@2415 musical fifth. This is just to prove to you that this thing is actually polyphonic. Now if I say 60 I get the whole triad. [sequence of triads at different pitches] |
es: @2415 |
@2430 I forget who it was ... |
es: @2430 |
Conlon Nancarrow has a lot of music that sounds like this. OK. Anyway, you've all heard this kind of sound, right? @2445 Questions about this? ... Yeah? Student: Can you send the message to all the copies? |
es: @2445 |
Miller: @2460 Yeah, you have to connect it to the copies or somehow distribute the messages to the copies because this copy is actually going to be doing this pitch, and so on. Yeah? Student: Did you say how you're copying/pasting those groups of objects? |
es: @2460 |
Miller: @2475 Oh. Control-D for duplicate. Any time you have something that's selected you can hit control-D and it duplicates the whole thing. You can even do it to a whole thing like that. Oh, gee, now I've got two of them |
es: @2475 |
@2490 so I can do this: |
es: @2490 |
Well, actually, I can have as many of these now as my computer can run. You haven't had any trouble with your computer not being able to run things yet probably, @2505 but now you will be able to make yourself trouble having your computer actually run everything. Yeah? Student: Is the abstraction, with an inlet, like a regular pd object? |
es: @2505 |
Miller: If you like, it's a whole @2520 new kind of object that I made today, that's not part of Pd but it's part of my private library. Student: If you wanted to choose the order that they play, could you put one dac~ at the bottom? |
es: @2520 |
Miller: @2535 There are two things you can do along those lines. Student: If you put a patch for each note ...? |
es: @2535 |
Miller: Yeah, but it would be smarter to have just a single one and have a sequence of different pitches going to it, @2550 because you don't need them to overlap. In other words, it's easier to control something, if you have a monophonic synthesizer, to send it sequence of things than it is to have a polyphonic thing that follows each other. For instance, if you want to say "do, re, mi" |
es: @2550 |
@2565 and get a trumpeter to do it you don't get three trumpeters and tell each one to play a note. Student: Not polyphonically ... |
es: @2565 |
Miller: Yeah. On the other hand, you can, for instance, ask it to do these things @2580 arpeggiated: |
es: @2580 |
This is a slight aside .. but there is a wonderful object called "pipe" which remembers numbers and puts them out @2595 after a delay. So if you want to make rounds or canons do this... |
es: @2595 |
@2610 This is not exactly an answer to your question, but it's a related idea. Now if I hit 60 you get: [arpeggio major chord] And now what it'll do, it'll be a major cord. [tone] . |
es: @2610 |
Student: @2625 How is "pipe" different from "delay". Miller: Yup, how is "pipe" different from "delay"? "Pipe" will remember as many numbers as ... -- OK, first off -- "delay" gives you bangs and "pipe" will |
es: @2625 |
@2640 actually remember numbers. Pipe will remember as many numbers as you give it so that you can do this: [tone] . And you'll get -- oh that's not a good example because it's too fast. Let's make it be a second; |
es: @2640 |
@2655 then two seconds. |
es: @2655 |
Oh wait, there's too much going on, so let me just not have this third one. So now I'll say. [sequence of tone pairs] @2670 So what's happening? Oh I should do it this way. This thing remembers numbers, but it also can remember more than one number at a time so that it will remember a whole sequence of things that happens. So it's actually a |
es: @2670 |
@2685 memory object as opposed to "delay" which doesn't remember stuff. |
es: @2685 |
This is useful. It's not as useful as you think it's going to be, because it doesn't turn out to be a generally ... @2700 that frequent that you want to have exactly the same sequence of stuff come out after a delay of time. |
es: @2700 |
I mean occasionally you want it, but it's more likely that you @2715 want to do something that varies how things change in such a way that pipe no longer becomes the right solution. And there's no way to sort of build it out into something better -- It just is what it is. Also, when you send a whole bunch of stuff in |
es: @2715 |
@2730 then suddenly you might say, "Well actually, why don't you just forget the third and fifth things that I told you but remember all the others." |
es: @2730 |
But there's no way in pipe to do that. And so the designing pattern in the computer music ... it's actually not good to have, @2745 to schedule, a whole bunch of stuff under the feature and then have it happen. It's better to always schedule the very next thing that's going to happen in case you're going to change the tempo or change some other aspect of what you're going to do -- because then you might find out that all that stuff you scheduled you might |
es: @2745 |
@2760 have to re-compute anyway. So pipe does the wrong thing, which is just schedule a whole bunch of stuff into the future. |
es: @2760 |
So, that was just sort of an answer to the question as opposed to useful @2775 information. So here's now, back to the triad generator: Other questions about this? Let's see, |
es: @2775 |
@2790 why is this not useful? What's the next thing you would want to do? ... Hook it up to a keyboard maybe, but I don't have a keyboard so that's not a problem for me right now. |
es: @2790 |
How about changing the lengths of the notes or changing other qualities of them. @2805 Right now they're short and kind of brutal, and maybe we would want to do something that would allow you to say well "Make me a chord that lasts a half second or a second long," -- have that be another parameter. |
es: @2805 |
@2820 That's kind of a typical thing that you might wish to do. |
es: @2820 |
@2835 Would you want to have a whole bunch of different inlets to this thing? |
es: @2835 |
Maybe not because if I decided to have like 10 inlets to control 10 different aspects @2850 of how the sampler works -- This doesn't have 10 controls on it, it has maybe five or six things controlled right now. -- But by the time you have eight of these and maybe a half dozen inlets on this you have a lot of wires running around. |
es: @2850 |
You're going to really want to use @2865 just pack and unpack, which are things that will allow you to take numbers and combine them into messages that have more than one value in them so that you can not have wires flying all over the place, each one of which just carries one number. |
es: @2865 |
@2880 So let me just make the thing now: Why don't I save this one, or rather leave this one the way it is and work on a new one.<<saving "4.poly-sampler-duration.pd">> |
es: @2880 |
Save as four. @2895 Sample duration. So now ".samping.envelope" -- If I go changing it it's going to change it |
es: @2895 |
@2910 for both of these patches, which could be a good thing, but for right now it's not going to be a good thing. So I'm going to save it as something else. Go in here and say save as. Now it's going to be |
es: @2910 |
@2925 "sampler-voice-with-duration.pd" That's a terrible idea because now we're going to have to type that whole thing out. |
es: @2925 |
@2940 And if I get one letter wrong it'll fail.... OK. Now my plan is going to be: I'm going to put lists of two numbers in and the numbers are going to be a pitch and |
es: @2940 |
@2955 a duration. The pitch will be just what it is and the duration will be in milliseconds. It's going to be easy, right? I'm going to want more of these later, but for right now let's just have one of them. |
es: @2955 |
So what we're going to do is @2970 here we're going to have to use the pack object to put messages together. To start with, let's just do it the most simple-minded way, which is to pack two numbers, one of which is going to supply the duration and one of which is going to supply the pitch. |
es: @2970 |
@2985 So now I'm going to say duration 1,000 and pitch 60 and it's going to last a second, right? No. Because? Why doesn't this work? |
es: @2985 |
Student: @3000 The duration doesn't get to the subpatch? |
es: @3000 |
Miller: Yeah, it's sort of that. I'm even being more simple minded. I didn't change the abstraction to do anything to the second number, so of course it can't do anything with it. I didn't fix it. OK. So go in here. @3015 (If a number box gets a message with two numbers it just takes the first number. You could do a variety of different things, but that's the way it does it.) So what we want to do is just unpack the other number. |
es: @3015 |
@3030 Move this here. So that's all we need is an unpack object, which by default expects two numbers. This one is now going to be a |
es: @3030 |
@3045 duration in milliseconds, which I think is just going to be the value of this delay. Tada! Oh, delay: The first inlet |
es: @3045 |
@3060 you send a bang to will schedule a bang to come out after the amount of delay and the second inlet changes the delay time so it <<the second inlet>> receives numbers. |
es: @3060 |
As a shortcut, you can feed it a number into the first inlet @3075 and that will not only set the delay time but also arm the delay. In other words, also schedule the set-off. But this is the more readable way of doing it. I'm just going to set the number here and then all this stuff is going to happen which, by the way, is going to start the delay off. |
es: @3075 |
@3090 So I'm going to save that. |
es: @3090 |
Maybe it's already going to work. Dig! @3105 That was too easy! It's still true that when I tell it something new it has to steal the voice from the old one. Oh, "stealing voice" -- that's MIDI talk. "Voice stealing" is when you have a thing here which is a "voice." Voices, |
es: @3105 |
@3120 that's borrowed from chorale talk. A voice is a person standing up saying something... But in computer music talk it's a thing that's able to make one pitch at a time. |
es: @3120 |
The idea here is that @3135 each pitch is going to be made by one of several identical sub-patches. So that's what "voice" is. So "stealing the voice" means if I have the thing playing and suddenly give it another pitch |
es: @3135 |
@3150 before the first one is done, I want it to cleanly stop playing the previous one and start playing the new one. |
es: @3150 |
All the machinery is already in there to do that. What we have to do then is mute the thing @3165 by taking the line~ that drives the output and ramping it hurriedly to zero and then resetting the location of the array to the beginning and |
es: @3165 |
@3180 starting the whole thing over. Now we've got everything we need to do this polyphonically except for one other thing which is this: |
es: @3180 |
Now suppose I want to be able to give it a bunch of numbers and have it @3195 not steal the same one, but allocate a new voice each time so we can hear them all separately. Then what you need to do -- and this is going to be work -- then what we need to do is have a bank of these and have each time you give it a new one choose a different one of them to send |
es: @3195 |
@3210 a message to. |
es: @3210 |
It's like an automobile distributor, which will send a spark to the cylinder that's supposed to go off next. So we know how to generate those numbers just fine. That's @3225 this kind of patch, which you've already seen: You need a floating point number "float" and then a "+ 1" -- That makes a loop. Let me just make that loop first and you can see |
es: @3225 |
@3240 what that's good for. That's counting, but now what we're going to do is we're going to say we want some number of voices. |
es: @3240 |
I'll just make there be eight. That's a reasonable number. @3255 So what I really want to do is count to eight. Let's say "+ 1" all right, but then modulo eight "mod 8." |
es: @3255 |
@3270 Then we're counting 0 through 7. Let's see. I have to introduce a new object now -- I'll just do that. |
es: @3270 |
@3285 I won't do the simple one, I'll do the one that we're really going to need. There's an object sitting here called "route," which looks at messages and simply |
es: @3285 |
@3300 routes them according to what the first number in the message is. |
es: @3300 |
So, for instance, if I give it the number 0 through 7 to look for, if I give it a 7 it puts it out this outlet, but if I give it a 0 @3315 it puts it out that one. 1, 2, 3, 4, 5, 6, ... 7, 0, and so on. It has, by the way, eight outputs because there's a last one which is what it outputs if it |
es: @3315 |
@3330 doesn't match any of the numbers I gave it -- which is always a possibility. |
es: @3330 |
I didn't have to give it exactly these numbers. I could have said I only care about numbers five and six or something like that. But in this case I want all the possible numbers this can generate @3345 to make outputs. |
es: @3345 |
Now it's even worse than that because what I really want to do is have route ... I'm going to just demonstrate this ... I want to have @3360 route take this kind of message and somehow route that message according to this number. So what I need is a message with three objects in it. |
es: @3360 |
So we're going to have to have pack with @3375 three numbers in it. The first number's going to have to be the number we route according to. The second and third numbers are going to be these numbers here <<pitch and duration>> except that I want the thing to change |
es: @3375 |
@3390 whenever I wiggle this number <<pitch>>, just to make it easy. |
es: @3390 |
So what I really want is whenever I get message out of here it's going to stuff these values in here and then make this thing go. So to do that @3405 I have to unpack it again. This looks ridiculous that we're doing pack followed by unpack, but actually that happens all the time that you have to do that. |
es: @3405 |
This is now the value of 1,000, so we'll put it there. This is the value @3420 58 and we'll put it here. Then we're going to bang that, but we care what order we do those two things in because we want to bang this after this number has gone in. So we |
es: @3420 |
@3435 need our old friend trigger. I'll use the abbreviation trigger bang float <<"t b f".>> Let's see. |
es: @3435 |
@3450 I'm going to bang this, but meanwhile we're going to throw this in here. And then let's just look at that to see how we're doing. Print. All right. Now |
es: @3450 |
@3465 each time I give it a new number, out comes a triple of numbers which consists of: the voice it chose and then the pitch I gave it and then the duration I gave it. |
es: @3465 |
@3480 This would be an excellent moment to stop and fish for questions ... Student: What is the "route" actually doing there? |
es: @3480 |
Miller: Ah, yeah. I'm not using that yet. What that's going to be good for is: @3495 This first number is going to be which of the eight sub-windows I want to send a message to and route is going to do that for us. ... Yeah? Student: Does route send the whole message it gets? |
es: @3495 |
Miller: @3510 No. It'll strip the number. So that's the next thing to do is just send this thing in here. So I'm going to call this "before" and "AFTER." |
es: @3510 |
@3525 Oh, sorry about the caps. Caps lock. OK. Now we start doing this. |
es: @3525 |
@3540 Actually, "AFTER" came before, but anyway -- whenever the message starts with 0, the "route 0" matched and it came out here. |
es: @3540 |
@3555 By the way, it gave me the other two numbers, which is what I want to feed the sub-patch with. |
es: @3555 |
Now we're done because. @3570 (I'm going to leave that there.) Now we just make eight of these and have them talk to this. All right. Are we going to get it all on one screen? |
es: @3570 |
@3585 I could have chosen a smaller number. But no. So I'm going to make eight of these. You can tell I've done this before. I know which way to organize them. |
es: @3585 |
@3600 Let's see. I didn't make the right number of them though yet. |
es: @3600 |
@3615 Computer scientists hate this because I'm actually manually iterating something and, of course, the program should be smart to do the work of doing these connections for me. [tone] |
es: @3615 |
Now I've got @3630 polyphonic sampling. Right? Or actually to really prove this is doing what I think it's doing let's give it a nice chord like this: |
es: @3630 |
@3645 60. Notice the commas. That means send both messages please. All right, this is horrifying. |
es: @3645 |
@3660 You can put it right there. [tone, laughter] Tada. So what's happening here is this is the same thing if I had managed somehow |
es: @3660 |
to simultaneously @3675 type all these numbers all into here. So each one of these things generates a message and, in fact, you see here what it did to them. [tone] |
es: @3675 |
I don't know, but whatever that was, six numbers... @3690 oh wait it starts here, each got assigned a voice number and then here are the six pitches that you see that I typed in there and here's the durations I asked for. |
es: @3690 |
OK. More on this @3705 next time. |
es: @3705 |