SuperCollider Forum
May 18, 2013, 10:38:10 AM
 News: The SuperCollider forum is currently experiencing a rash of spambot registrations. New user requests may not be approved quickly as a result -- and if your email address looks like spam, it might not be approved at all. We are working to improve the security of the registration process, and to provide alternate means to contact the administrators to get a new account. Thanks for your patience.
 Home Help Search Calendar Login Register
 Show Posts Pages: [1] 2 3 ... 13
 1 Howto / Synths / Re: controlling synth on: April 02, 2009, 09:03:49 PM The only way to get new values into a running Synth is using a Control input. Controls are automatically created from arguments of the SynthDef function.The code you posted looks of the value of d.at("name") once when building the SynthDef. After that, it's hard coded and can't be changed (without rebuilding the SynthDef).I'd suggest, keep the dictionary on the client side and send the new value as needed using .set --Code:d = Dictionary.new;d.put("cfreq", 90);(SynthDef("name", { |cfreq = 440|   var instr;   instr = SinOsc.ar(freq);   Out.ar(0, instr);}).send(s))y = Synth("name", [\cfreq, d.at("cfreq")]);d["cfreq"] = 900;y.set("cfreq", d["cfreq"]);hjh
 2 General Discussion / General Discussion / Re: loading buffers automatically with Pbind on: February 16, 2009, 05:33:53 PM Very tricky one. Pproto creates a separate environment that exists only within the pattern while it's executing. The function that you give at the start of Pproto executes within this separate environment. But, your wavetable functions exist in the main environment. Environments don't share values - there's no kind of nested scope like you have with functions. So, when {arg a; ~sin2.(a) } executes, ~sin2 is nil because the function is running inside an environment that knows nothing about ~sin2.A workaround is to use topEnvironment[\sin2] in place of ~sin2. Or, put inEnvir in front of the function:Pdef(\toto, ~mkbuf.(inEnvir {arg a; ~sin2.(a); a.postln; }, Pbind(\instrument, \wavetable)));This connects the function to the outer environment.Quote from: grirgz on February 12, 2009, 06:34:54 PMCode:~mkbuf = {    arg fun, pat;    Pproto({        var cc;        cc = Signal.newClear(512);        fun.(cc);        ~buf = Buffer.loadCollection(s, cc.asWavetable);    }, Pset(\bufnum, Pkey(\buf), pat))};Note also that using Buffer.loadCollection in Pproto means that the buffer will not get freed automatically at the end of the pattern. Pproto depends on the event types defined in EventTypesWithCleanup -- if resources are created by other means, Pproto doesn't know what to do with them afterward. The \table event type should suit this purpose.Code:        ~buf = (type: \table, amps: cc.asWavetable).yield;I recently added a cleanup func to Pfset, which might be more intuitive.Code:p = Pfset({ ... ~buf = Buffer.loadCollection(...);}, pattern, { ~buf.free;});QuotePdef(\toto, ~mkbuf.({arg a; ~sinx.(_,3) }, Pbind(\instrument, \wavetable)));The last one isn't right because _ is not a substitute for a.{arg a; ~sinx.(a, 3) } is the same as ~sinx.(_, 3) -- but if you call .value on {arg a; ~sinx.(_,3) }, the result will be a Function that is supposed to call ~sinx - but this function will not actually be called.James
 3 Howto / Language questions / Re: Reading parts from a text file on: February 16, 2009, 04:54:01 PM Quote from: tedor2 on February 11, 2009, 05:15:09 PMDear James, 1, I am ok,  if I use a text file with just the lines of useful data "simple_lines16.txt". (copy and paste from the original). TabFileReader seems to make things easier for a dummy like me. I still would like to use the original file "leftandright16ch.txt", where both channels (Left CH1 and Right CH2) could be read in arrays. Well, I think I just have to find out how to get the line number of where "Left CH1" and "Right CH2" is positioned. Then I could add and minus the numbers, and get the array to be read in from these new parameters. Do you have an idea how to get this line position?http://tedor2.extra.hu/mix/ReadintoArray.zipThe easiest way to find the line numbers is to use a proper text editor (not the one built into sc.app). A lot of programmers swear by text mate, but there are a bunch of freeware choices. Many editors, especially programming-oriented ones, have the option of showing line numbers in the left margin.But, looking at the tab file reader class definition, I don't see an easy way to tell it to stop after a given number of lines. I don't have a quick answer to that problem (except that I probably would write my own reader and parser using the outline in my earlier post, especially if this is something I expect to do a lot).Quote2, I wanted to send you an email on your site concerning the CD with your music, there is an error message after clicking on send. I wonder whether you would send it to the UK as well? ($?) Sure, I'll send to the UK. What was the error message? I can't help you much with the error if I don't know what the error is. (Unfortunately this is all too common in the computer world -- people think it's enough to say "there was an error." So then it takes longer to solve the problem because it's necessary to do another back-and-forth to find out what the problem really was. Sorry to go on about this -- it is a major peeve of mine.)I can tell you that I've had horrible problems with spam from that page, so I block actually rather a lot of phrases. I also had to put in a timer because a lot of spammers submit the input form instantaneously after visiting the page. The side effect is that if you write the message to me in another editor, then go to my page, paste it in quickly and hit "send," as far as the website is concerned, you look like a spammer. Try waiting at least 15 seconds before sending.Or, if all else fails, send me a PM here.James  4 Howto / Language questions / Re: Reading parts from a text file on: January 27, 2009, 03:00:53 PM Quote from: tedor2 on January 26, 2009, 03:46:25 PMthank you for clearing the haze! Do you think I should try learning C? Or which would be the best way to learn the language? Are the help files enough?Nah, don't waste your time with C. (C is still useful for a lot of things, but most of the programming world has moved on to C++ or Java. C is not object-oriented, so it won't teach you much about SC.)I can't think of a "general programming concepts for SC users" guide... maybe look at the Ruby language. It is somewhat similar to SC in some ways.QuoteThere is one major issue concerning this project. There are some invisible characters in the text file:http://www.tedor2.extra.hu/mix/scpostmicro.jpgOh, this is interesting. Yeah, you sometimes have to dig into the raw data to see what's really there before writing the final code. Sometimes I do this to look at the raw data:Code:f = File(p, "r");z = Int8Array.newClear(200);f.read(z);z.clump(8).do({ |row| row.do({ |item| Post << item.asHexString(2) << " "; }); "\t".post; row.do({ |item| item = item.asAscii; Post << if(item.isPrint) { item } { "." }; }); Post <<$\n;});f.close;// prints:0D 54 69 74 6C 65 20 6F    .Title o66 20 74 68 65 20 45 78    f the Ex70 6F 72 74 20 42 72 61    port Bra69 6E 20 44 61 74 61 3A    in Data:09 09 09 45 78 70 6F 72    ...Expor74 20 42 72 61 69 6E 20    t Brain 44 61 74 61 0D 0D 4D 61    Data..Ma78 20 62 75 66 66 65 72    x buffer20 73 69 7A 65 3A 09 09     size:..09 20 30 31 3A 30 30 3A    . 01:00:30 30 2E 30 30 30 0D 53    00.000.S74 61 72 74 20 54 69 6D    tart Tim65 20 69 6E 20 62 75 66    e in buf66 65 72 3A 09 09 09 20    fer:... 30 30 3A 30 30 3A 30 30    00:00:002E 30 30 30 0D 45 6E 64    .000.End20 54 69 6D 65 20 69 6E     Time in20 62 75 66 66 65 72 3A     buffer:09 09 09 20 30 30 3A 30    ... 00:032 3A 34 37 2E 35 39 31    2:47.5910D 0D 49 42 56 41 34 20    ..IBVA4 61 6E 64 20 63 75 72 72    and curr65 6E 74 20 66 69 6C 65    ent file20 69 6E 66 6F 72 6D 61     informa74 69 6F 6E 3A 09 09 09    tion:...The first thing I see from this is that 0D represents a line break in this file, and getLine doesn't recognize it as a line break. (How do I know this is the line break? By comparing the raw output to the appearance in a text editor.)The bad characters show up as NUL in notepad++ on my windows machine, meaning ascii code 0. That is a fairly serious data problem that is harder to correct in SC. Since SC's underbelly is C, the C-style rule for strings apply where a 0 byte means the end of the string. Probably the string in memory has all the characters, but they are ignored past 0 because of the C rule.SC doesn't have a built-in method to strip 0 bytes, so you'll have to write your own getLine function.Code:~getLine = { |file, endChar(13.asAscii)| var char = file.getChar, str = String.new; if(char.isNil) { nil } { while { char.notNil and: { char != endChar } } { if(char.ascii > 0) { str = str.add(char) }; char = file.getChar; }; }; str};Sorry this is such a pain... working with files you didn't create yourself is sometimes hard.James
 5 Howto / Language questions / Re: Reading parts from a text file on: January 26, 2009, 03:12:34 PM Quote from: tedor2 on January 24, 2009, 10:24:25 AMDear James, I rely on your help. Step by step...I think I understood that a text file is made up of lines.A text file is really just a stream of bytes. Some of those bytes are interpreted to mean the end of a line (but it's not required to read the file that way).QuoteCode:(var file = File("/Users/krisztianhofstadter/Desktop/EEG/SC\ read/exported_data", "r"), line;line = file.getLine;while { line.notNil and: { line != "Left CH1" } } { line = file.getLine;};With the first part of the code we read a whole text file into a variable (file) and set up a new variable (line).No -- file = File(path, mode) doesn't read anything. It just opens a file handle. You can read data from the file handle - or just close the handle without reading anything (which is a way to test for a file's existence on disk, e.g. -- see File.exists in the SC lib).QuoteThe second part is trickier: line = file.getLine;"getLine = Reads and returns a String up to lesser of next newline or 1023 chars."I got confused here:)The while function has two parts: testFunc :{ line.notNil and: { line != "Left CH1" } }bodyFunc : {line = file.getLine;}"While" starts reading the text from the beginning (testFunc). It loops the "testFunc" until  it's false. In scope > This mean that the "bodyFunc" evaluates "line = file.getLine", where this evaluation (line = file.getLine) reads strings from the text lines in a loop till it is false?  getLine reads strings from the file >are these strings the "text lines" them self?or are these strings characters next to each other like a word or numbers (Left ~ 000)or just one character in the text (1 ~ L)or is "Left CH1" a string?Try it for yourself -- running some exploratory code will teach you more about reading files.f = File(path, "r");f.getLine;   // what do you see in the post window?f.getLine.dump;  // proves the result is a String, and shows some of the contentsIn the source file, there is a line "Left CH1" that occurs at the beginning of the first data section. When that line is read, line != "Left CH1" becomes false and the while loop stops. The file's position should be after the newline character terminating "Left CH1" (i.e., the next character to be read will be the first character on the line following "Left CH1").QuoteIf "Left CH1" is a string, while was looking for to stop, I think I am alright so far.Yes. Double-quote syntax for string literals is explained in the Literals help file.James
 6 Howto / Language questions / Re: Reading parts from a text file on: January 13, 2009, 01:41:43 PM Reading a file like this takes a few basic capabilities that most computer languages have.- reading strings from a file- searching for characters or substrings in a string- extracting substrings- converting strings to numbersSupercollider can do all of these things, so yes, of course it's possible.What you need to do is think step-by-step about the parts of the file and how each should be processed.First is a header, which you just want to ignore up until the line that says "Left CH1." That's pretty easy -- read a line and check to see if it == "Left CH1" -- if so, stop and go onto the next section. The standard way to do this is with a while loop. (Checking for notNil is also important because you want the loop to stop if the file runs out of lines.)Code:var file = File(path, "r"), line;line = file.getLine;while { line.notNil and: { line != "Left CH1" } } { line = file.getLine;};// the above line = ...; while ...; could be written more concisely as:while { (line = file.getLine).notNil and: { line != "Left CH1" } };Then follow the data. What steps do we need for each line?- there are some bad characters; strip them out- split the string wherever there is white space- remove any empty substrings in the partitioned string (just in case)- throw out the first three columns- convert the rest to floating-point numbersOh, and stop when a line doesn't contain any numbers.Code:while { (line = file.getLine).notNil and: { line.any(_.isDigit) } } { // remove bad characters line = line.reject({ |ch| ch.ascii > 127 }) // split wherever there is a space (including tabs) .delimit({ |ch| ch.isSpace }) // remove empty strings .reject({ |substr| substr.size == 0 }); // starting with the 4th column, convert each string to a float // the result is an array of the FFT magnitudes from the file matrix = matrix.add(line[3..].asFloat);};Then skip a few lines until you get to "Right CH2" and do the same thing to read the next table.I'm not sure of the format you need for the final matrix, but array manipulations can certainly get you there.Solving problems like this is a matter of thinking it through, one step at a time. Looking at the file as a whole, it seems difficult indeed but there is a very clear action to take for each separate line. So look at one line, and break down the process into simple steps.Also it's a good idea to use protect when processing file data. If there is an error in the middle of file processing, you could leave a file handle open and then have no way to close it, not so good.General template:Code:file = File(path, "r");if(file.isOpen) { protect { ... do file stuff in here ... } { file.close; };} { "Couldn't open file".warn; };With this, even if an error occurs inside the protect block, the file is always closed.James
 7 General Discussion / General Discussion / Google map of SC users on: December 24, 2008, 05:00:51 PM An enterprising SC user has put up a global google map to locate other users. maps.google.nl/maps...Kind of fun to see where people are... feel free to add yourself if you like. All it takes is a google account, thus entailing the surrender of your online privacy in perpetuity. (Bit too late for me; I gave that up years ago.)James
 8 General Discussion / General Discussion / The "What's wrong with this picture?" game on: December 24, 2008, 09:31:03 AM Browsing around, wasting time this fine Christmas Eve morning, I saw this and noticed something odd.(Original img location: http://www.flickr.com/photos/danstowell/2898577451/in/pool-supercollider/)What is wrong with this picture?James
 9 Howto / Synths / fun: frequency-stretching evil on: December 18, 2008, 01:10:49 PM Code:b = Buffer.read(s, "sounds/a11wlk01.wav");(SynthDef('freq-stretch-evil', { |stretch = 1, center = 440, out| var sig = PlayBuf.ar(1, b, loop: 1); // stretched sig = PitchShift.ar(sig, 0.2, stretch, timeDispersion: 0.05); // re-centered sig = FreqShift.ar(sig, center * (1-stretch)); Out.ar(out, sig ! 2);}, metadata: (specs: (stretch: [0.25, 4, \exp], center: \freq))).memStore;SynthDescLib.at('freq-stretch-evil').makeWindow;)(Metadata is post-3.2 I believe... if you're on 3.2, leave it out and play the synth manually.)James
 10 Howto / GUI and interaction / Re: Nerdy color sorting fun on: December 13, 2008, 09:39:24 AM Actually the userview/pen thing has some performance problems using Cocoa (OSX) gui objects. Here's another version using an empty statictext, setting the background color. It runs a lot faster in OSX.JamesCode:(var blockSize = 10, blocks = 60, pixels = blockSize * blocks, blockRect = Rect(0, 0, blockSize, blockSize), brightness = { |color| color.red * color.green * color.blue }, colors = Array.fill(16, { Color.rand }).sort({ |a, b| brightness.(a) < brightness.(b) }), matrix = Array.fill(blocks, { Array.fill(blocks, { colors.size.rand }) }), sbounds = GUI.window.screenBounds, w = GUI.window.new("HexaDecaColorDoubleBubbleSort", Rect((sbounds.width - pixels) * 0.5, (sbounds.height - pixels * 0.5), pixels, pixels)), views = matrix.collect({ |row, i| row.collect({ |cell, j| GUI.staticText.new(w, Rect(i * blockSize, j * blockSize, blockSize, blockSize)) .background_(colors[matrix[i][j]]); }); }), updateColor = { |i, j| views[i][j].background_(colors[matrix[i][j]]); }, routine;w.front;routine = Routine({ var numSwaps = 1, temp, // a bit tricky: I want to randomize whether it swaps // horizontally first, or vertically // so I put h-swap and v-swap functions in an array // then, on each iteration, choose randomly which one to do first swaps = [{ |i, j, k| // horizontal swap if((matrix[i][j] > matrix[i][k])) { matrix[i].swap(j, k); updateColor.(i, j); updateColor.(i, k); numSwaps = numSwaps + 1; }; }, { |i, j, k| // vertical swap if(matrix[j][i] > matrix[k][i]) { temp = matrix[j][i]; matrix[j][i] = matrix[k][i]; matrix[k][i] = temp; updateColor.(j, i); updateColor.(k, i); numSwaps = numSwaps + 1; }; }], // another trick: going forward always causes a bias toward the bottom right // so, we will scan forward first, then backward fwdBackwd = Pseq(#[do, reverseDo], inf).asStream, scanDirection; while { numSwaps.debug("number of swaps last pass") > 0 } { numSwaps = 0; scanDirection = fwdBackwd.next; blocks.perform(scanDirection, { |i| (blocks-1).perform(scanDirection, { |j| swaps[#[[0, 1], [1, 0]].choose].do({ |func| func.value(i, j, j + 1); }); 0.01.wait; }); }); }; "done".postln; w.front; // no matter what I'm doing, I want this to pop up}).play(AppClock);w.onClose = { routine.stop };)
 11 Howto / GUI and interaction / Nerdy color sorting fun on: December 12, 2008, 05:25:20 PM I'd been meaning to do this for awhile... when I was a kid, I was obsessed with a small program on the Apple II that had been printed in the magazine of the Puget Sound apple users group (I am really dating myself here). It did a two-dimensional bubble sort of colored blocks, ending up with these curved and tapered bands of color.So I hacked it up in SuperCollider... basically just like I remember it With 3600 blocks it will take quite some time to complete, but it's fascinating to watch as the random matrix slowly organizes itself from the outside in. A smaller matrix runs faster of course, but the bands are chunkier and not as pretty. If you get bored with it, just close the window and the routine will stop.JamesCode:(var blockSize = 10, blocks = 60, pixels = blockSize * blocks, blockRect = Rect(0, 0, blockSize, blockSize), brightness = { |color| color.red * color.green * color.blue }, colors = Array.fill(16, { Color.rand }).sort({ |a, b| brightness.(a) < brightness.(b) }), matrix = Array.fill(blocks, { Array.fill(blocks, { colors.size.rand }) }), sbounds = GUI.window.screenBounds, w = GUI.window.new("HexaDecaColorDoubleBubbleSort", Rect((sbounds.width - pixels) * 0.5, (sbounds.height - pixels * 0.5), pixels, pixels)), views = matrix.collect({ |row, i| row.collect({ |cell, j| GUI.userView.new(w, Rect(i * blockSize, j * blockSize, blockSize, blockSize)) .relativeOrigin_(true) .canFocus_(false) .drawFunc_({ |view| GUI.pen.color_(colors[matrix[i][j]]) .fillRect(blockRect) }); }); }), routine;w.front;routine = Routine({ var numSwaps = 1, temp, // a bit tricky: I want to randomize whether it swaps // horizontally first, or vertically // so I put h-swap and v-swap functions in an array // then, on each iteration, choose randomly which one to do first swaps = [{ |i, j, k| // horizontal swap if((matrix[i][j] > matrix[i][k])) { matrix[i].swap(j, k); views[i][j].refresh; views[i][k].refresh; numSwaps = numSwaps + 1; }; }, { |i, j, k| // vertical swap if(matrix[j][i] > matrix[k][i]) { temp = matrix[j][i]; matrix[j][i] = matrix[k][i]; matrix[k][i] = temp; views[j][i].refresh; views[k][i].refresh; numSwaps = numSwaps + 1; }; }], // another trick: going forward always causes a bias toward the bottom right // so, we will scan forward first, then backward fwdBackwd = Pseq(#[do, reverseDo], inf).asStream, scanDirection; while { numSwaps.debug("number of swaps last pass") > 0 } { numSwaps = 0; scanDirection = fwdBackwd.next; blocks.perform(scanDirection, { |i| (blocks-1).perform(scanDirection, { |j| swaps[#[[0, 1], [1, 0]].choose].do({ |func| func.value(i, j, j + 1); }); 0.01.wait; }); }); }; "done".postln; w.front; // no matter what I'm doing, I want this to pop up}).play(AppClock);w.onClose = { routine.stop };)
 12 Howto / Language questions / Re: MouseButton.kr as recorder and player on: December 01, 2008, 04:10:18 PM Typically I like to keep the buffer with other data about it in one object. Identity dictionaries are really good for this because there is no preset structure and you can add stuff to it anytime -- and its subclass Event is even better because it has a really simple syntax.b = (buf: Buffer.alloc(...));  // (name: value) makes an eventThen in the OSCresponderNode:Code:o = OSCresponderNode(s.addr, '/tr', { |time, resp, msg| if(msg[1] = x.nodeID) { // msg[1] is node id b.put(\dur, msg[3]); // msg[3] is trigger value };}).add;Now when you play back, you can use bufnum: b.buf and also have a duration argument to the synth, populated by b.dur (in seconds) or b.dur * b.buf.sampleRate (in frames).Quotei havent quite figured it out, but should there be a problem if i use my mouse NORMALLY (i.e. choosing another piece of code by double clicking on it) after running this piece of code? is there a way to stop SC from reading the MouseButton so i can use the mouse without worry?As long as mouse button.kr is running, it's going to respond to every click. One solution might be to designate a block of screen coordinates to start and stop recording, and check using MouseX and MouseY (again, adapt this to your synth):Code:withinCoordinates = InRange.kr(MouseX.kr(0, GUI.window.screenBounds.right), leftBound, rightBound) * InRange.kr(MouseY.kr(0, GUI.window.screenBounds.bottom), topBound, bottomBound);buttonPressed = MouseButton.kr;recordTrig = buttonPressed * withinCoordinates;Another way would be to have some sort of GUI thing to click on, which would trigger an action function in the client. The action function could set an argument in the record synth to replace MouseButton. Many GUI objects respond to mouse down as well as mouse up.James
 13 Howto / Language questions / Re: Osc message from Max to trigger a Routine on: December 01, 2008, 03:54:27 PM If you're going to set other things in the synth, then you need to save the result of r.next in a variable, e.g.a = r.next.set(...);James
 14 Howto / Language questions / Re: Osc message from Max to trigger a Routine on: November 30, 2008, 11:19:33 PM How about:r.next.set(\synthArgName, maxrate12);(Since r.next returns the new Synth, you can use it as the receiver of .set. Then, the comment "can yield anything" is no longer valid -- the synth routine will have to yield the synth object.)It isn't clear to me what you want to do with maxrate12, actually. If you were trying to set a value on a Synth, the above would work. If not, then I don't think you would need .set in there.James
 15 Howto / Language questions / Re: Osc message from Max to trigger a Routine on: November 30, 2008, 09:47:51 AM The Routine making the Synths needs to .yield something after playing the synth. Right now I think the loop is ending, causing the Routine to exit - at that point you can't do any more with it. But if that Routine loops infinitely and yields after each synth, you can call .next on the synth-routine to get the next synth.This is how I would do it. For fun, I'll convert your pitch stream to a pattern network  Code:z = Pswitch([ Pseq(#[24, 31, 36, 43, 48, 55], 1), // run of fifths // varying arpeggio Pseq([60, Prand(#[63, 65], 1), 67, Prand(#[70, 72, 74], 1)], { rrand(2, 5) }), Prand(#[74,75,77,79,81], { rrand(3, 9) })], Plazy({ // if 0.5.coin is true, start with item 0; otherwise start with 1 // this mimics the 'if' in the original routine var start = 1 - 0.5.coin.binaryValue; Pseries(start, 1, 3 - start)})).asStream;r = Routine { var freq; while { (freq = z.next).notNil } { Synth("Algorithmic", [freq: freq.midicps]).yield; // can yield anything }};a = r.next;  // do just one synthThen your osc responder can call .next on the synth routine.James
 Pages: [1] 2 3 ... 13