From 1c49e88fb1b7279d0ac594d59af538cab617bbd2 Mon Sep 17 00:00:00 2001 From: charlieroberts Date: Wed, 7 Jun 2017 18:25:39 -0700 Subject: [PATCH] harmony tutorial and make clear() a global --- dist/index.js | 3 ++- index.html | 3 ++- js/example.js | 44 +++++++++++++++++++++++--------------------- js/gibber.js | 1 + 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/dist/index.js b/dist/index.js index 5f8787b..474c5f7 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2261,7 +2261,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope var Examples = (_Examples = { introduction: '/* gibberwocky.live - introduction\n * \n * This introduction assumes that you have the gibberwocky.demo.als\n * project open and running in Live. If not, it\'s easy to make your own\n * version; just place an instance of the gibberwocky_master plugin on \n * Live\'s master track, and an instance of the gibberwocky_midi plugin\n * on any track you\'d like to control with gibberwokcy.\n *\n * To execute any line of code, hit Ctrl+Enter. \n * To stop all running sequences, hit Ctrl+. (period), or execute clear() \n * (Ctrl+. doesn\'t work on some non-US keyboards).\n *\n * Make sure Live\'s transport is running (hit play). When you\'ve played\n * around with this demo, start working your way through the tutorials\n * listed in the \'demos\' tab in the sidebar.\n */\n\n// start kick drum using impulse (preset 606) on tracks[0]\ntracks[0].midinote.seq( 60, Euclid(5,8) )\n\n// randomly pick between open and closed hi-hats\n// and eighth notes vs. 1/16th notes. If 1/16th\n// notes are played, always play two back to back.\ntracks[0].midinote.seq( [64,65].rnd(), [1/8,1/16].rnd(1/16,2), 1 )\n\n// play a scintillating bass line\ntracks[1].note.seq( [-14,-12,-9,-8], 1/8 )\n\n// play chords with piano sound\ntracks[2].chord.seq( Rndi(0,8,3), 2 )\n\n// control bass filter cutoff\ntracks[1].devices[0][\'Filter Freq\']( mul( beats(2), .75 ) ) \n\n// control panning of piano\ntracks[2].pan( lfo( .15 ) ) \n\n// control time parameter of impulse\ntracks[0].devices[0][\'Global Time\']( beats(8.33) ) \n\n// control transpostion of impulse with an lfo\n// increasing in frequency over 8.66 beats\ntracks[0].devices[0][\'Global Transpose\']( lfo( beats(8.66) ) ) \n' -}, _defineProperty(_Examples, 'tutorial 1: basic messaging', '/*\n * gibberwocky.live - tutorial #1: basic messaging\n *\n * This first intro will explain how to send\n * MIDI note messages and control device and track parameters.\n *\n * To start, makesure you open the gibberwocky.demo project and\n * have Live\'s transport running.\n*/\n\n// The demo gibberwocky project has three tracks: drums, bass, and ambient\n// piano. Let\'s start playing notes with the bass. The bass is located on the \n// second track, zero-indexed (start counting from zero).\nbass = tracks[1]\nbass.midinote( 60 ) // send middle C\n\n// Click on the \'lom\' tab (Live Object Model) in the sidebar on the right side\n// of the gibberwocky client. This lists all the parameters exposed for control\n// to gibberwocky. The bass track is listed under \'2-Muugy\' (Muggy is the name\n// of the bass preset). If you uncollapse this branch, you see that the track\n// contains a single Simpler device (all gibberwocky objects are ignored). Open\n// up that Simpler branch, and you see all the parameters that can be controlled.\n// If you drag and drop the \'Filter Freq\' parameter into the code editor, it\n// will insert the full path for that control into the editor. It should look\n// something like this:\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\']\n\n// This is the path to a function we can call to change the filter cutoff frequency,\n// like so:\n\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\'](.75)\ntracks[\'2-Muugy\'].midinote( 36 )\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\'](.25)\ntracks[\'2-Muugy\'].midinote( 36 )\n\n// Note that we can shorten this in a number of ways. First, we can always refer\n// to tracks and devices by their array position. In this case, the track index is\n// 1 and the device index is 0 (remember, gibberwocky devices are ignored).\n\ntracks[1].devices[0][\'Filter Freq\']( .5 ) // same effect!\n\n// we can also use the shortcut we created earlier\nbass.devices[0][\'Filter Freq\']( .35 )\n\n// or...\nsimpler = tracks[1].devices[0]\nsimpler[\'Filter Freq\']( 1 )\n\n// Conveniently (well, in most cases) all parameters are measured from 0-1, so\n// you don\'t really have to worry about ranges.\n\n// In addition to controlling devices, we can also control parameters of each\n// track in Live, such as volume, panning, mute and solo. This includes\n// the return tracks and the master track as well.\n\ntracks[0].volume( 0 ) // effectively mute our drums track \nreturns[0].volume( 1 ) // increase our reverb volume\ntracks[0].sends[0]( 1 ) // send our drum track full-blast to our reverb\nmaster.volume( .5 ) // set the master volume\n\n// OK, that\'s some basics out of the way. Try the sequencing tutorial next!'), _defineProperty(_Examples, 'tutorial 2: basic sequencing', '/* gibberwocky.live - tutorial #2: basic sequencing\n *\n * This tutorial will provide an introdution to sequencing messages in gibberwocky. In\n * order for sequencing in gibberwocky.live to work, you must start the Global Transport\n * running in Live. We\'re also assuming you\'re running the gibberwocky.demo project for\n * this tutorial.\n */\n\n// In tutorial #1, we saw how we could send MIDI messages to specific tracks\n// in Live. We can easily sequence any of these methods by adding\n// a call to .seq(). For example:\n\n// send noteon message with a first value of 36\ntracks[1].midinote( 36 )\n\n// send same value every quarter note\ntracks[1].midinote.seq( 36, 1/4 )\n\n// You can stop all sequences in gibberwocky with the Ctrl+. keyboard shortcut\n// (Ctrl + period) or by executing the command clear(). \n// You can also stop all sequences on a specific track:\ntracks[1].stop()\n\n// Most sequences in gibberwocky contain values (36) and timings (1/4). To\n// sequence multiple values we simply pass an array:\ntracks[1].midinote.seq( [36,48,60], 1/4 )\n\n// ... and we can do the same thing with multiple timings:\ntracks[1].midinote.seq( [36,48,60], [1/4,1/8] )\n\n// We can also sequence our note velocities and durations.\ntracks[1].midinote.seq( 48, 1/2 )\ntracks[1].velocity.seq( [16, 64, 127], 1/2 )\ntracks[1].duration.seq( [10, 100,500], 1/2 )\n\n// If you experimented with running multiple variations of the midinote \n// sequences you might have noticed that only one runs at a time. For example,\n// if you run these two lines:\n\ntracks[1].midinote.seq( 72, 1/4 )\ntracks[1].midinote.seq( 48, 1/4 )\n\n// ...you\'ll notice only the second one actually triggers. By default, gibberwocky\n// will replace an existing sequence with a new one. To stop this, you can pass an ID number \n// as a third argument to calls to .seq(). In the examples of sequencing we\'ve seen so far,\n// no ID has been given, which means gibberwocky is assuming a default ID of 0 for each\n// sequence. When you launch a sequence on a channel that has the same ID as another running \n// sequence, the older sequence is stopped. If the sequences have different IDs they run \n// concurrently. Note this makes it really easy to create polyrhythms.\n\ntracks[1].midinote.seq( 48, 1 ) // assumes ID of 0\ntracks[1].midinote.seq( 60, 1/2, 1 ) \ntracks[1].midinote.seq( 72, 1/3, 2 ) \ntracks[1].midinote.seq( 84, 1/7, 3 ) \n\n// We can also sequence calls to midichord. You might remember from the first tutorial\n// that we pass midichord an array of values, where each value represents one note. This\n// means we need to pass an array of arrays in order to move between different chords.\n\nclear()\ntracks[2].midichord.seq( [[60,64,68], [62,66,72]], 1/2 )\n\n// Even we\'re only sequencing a single chord, we still need to pass a 2D array. Of course,\n// specifying arrays of MIDI values is not necessarily an optimal representation for chords.\n// Move on to tutorial #3 to learn more about how to leverage music theory in gibberwocky.'), _defineProperty(_Examples, 'tutorial 3: harmony', '/* gibberwocky.max - tutorial #3: Harmony\n *\n * This tutorial covers the basics of using harmony in gibberwocky.midi. It assumes you\n * know the basics of sequencing (tutorial #2) and have an appropriate MIDI output setup.\n * It also assumes you have the gibberwocky help patch open and the transport running.\n *\n * In the previous tutorials we looked at using raw MIDI values to send messages. However,\n * using MIDI note numbers is not an ideal representation. gibberwocky includes knoweldge of\n * scales, chords, and note names to make musical sequencing easier and more flexible. In this\n * tutorial, instead of using channel.midinote() and channel.midichord() we\'ll be using \n * channel.note() and channel.chord(). These methods use gibberwocky\'s theory objects to\n * determine what MIDI notes are eventually outputted.\n */\n\n// In our previous tutorial, we sent out C in the fourth octave by using MIDI number 60:\ndevices[\'bass\'].midinote( 60 )\n\n// We can also specify notes with calls to the note() method by passing a name and octave.\ndevices[\'bass\'].note( \'c4\' )\ndevices[\'bass\'].note( \'fb3\' )\n\ndevices[\'bass\'].note.seq( [\'c4\',\'e4\',\'g4\'], 1/8 )\n\n// remember, Ctrl+. stops all running sequences.\n\n// In gibberwocky, the default scale employed is C minor, starting in the fourth octave. \n// This means that if we pass 0 as a value to note(), C4 will also be played.\ndevices[\'bass\'].note( 0 )\n\n// sequence C minor scale, starting in the fourth octave:\ndevices[\'bass\'].note.seq( [0,1,2,3,4,5,6,7], 1/8 )\n\n// negative scale indices also work:\ndevices[\'bass\'].note.seq( [-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7], 1/8 )\n\n// there is a global Scale object we can use to change the root and mode\n// for all scales. Run the lines below individually with the previous note sequence running.\nScale.root( \'d4\' )\nScale.mode( \'lydian\' )\n\nScale.root( \'c4\' )\nScale.mode( \'phrygian\' )\n\n// We can also sequence changes to the root / mode:\nScale.root.seq( [\'c2\',\'d2\',\'f2\',\'g2\'], 2 )\nScale.mode.seq( [\'lydian\', \'ionian\', \'locrian\'], 2 )\n\n// stop the scale sequencing\nScale.root[0].stop()\nScale.mode[0].stop()\nScale.root( \'c4\' )\n\n// We can also define our own scales using chromatic scale indices. Unfortunately, \n// microtuning with MIDI is very diffcult, so only the standard eleven notes of \n// Western harmony are supported. Scales can have arbtrary numbers of notes.\nScale.modes[ \'my mode\' ] = [ 0,1,2,3,5,6,10 ]\nScale.mode( \'my mode\' )\n\nScale.modes[ \'another mode\' ] = [0,1]\nScale.mode( \'another mode\' )\n\nScale.mode.seq( [\'my mode\', \'another mode\'], 4 )\n\n/******** chords **********/\n// Last but not least there are a few different ways to specify chords in gibberwocky.\n// First, clear the current scene using Ctrl+.\n\n// change the release time, scale mode, and root\ndevices[\'bass\'].release( 75 )\n\n// We can use note names:\ndevices[\'bass\'].chord( [\'c4\',\'eb4\',\'gb4\',\'a4\'] )\n\n// Or we can use scale indices:\ndevices[\'bass\'].chord( [0,2,4,5] )\n\n// sequence in two-dimensional array\ndevices[\'bass\'].chord.seq( [[0,2,4,5], [1,3,4,6]], 1 )\n\n// We can also use strings that identify common chord names.\ndevices[\'bass\'].chord( \'c4maj7\' )\ndevices[\'bass\'].chord( \'c#4sus7b9\' )\n\n\ndevices[\'bass\'].chord.seq( [\'c4dim7\', \'bb3maj7\', \'fb3aug7\'], 1 )\n\n// OK, that\'s harmony in a nutshell. Next learn a bit about patterns and\n// pattern manipulation in gibberwocky in tutorial #4.'), _defineProperty(_Examples, 'tutorial 4: patterns and pattern transformations', '/* gibberwocky.max - tutorial #4: Patterns and Transformations\n *\n * This tutorial covers the basics of using patterns in gibberwocky.max. It assumes you\n * know the basics of sequencing (tutorial #2), have the the gibberwocky help patch\n * loaded, and the Global Transport running.\n *\n * In tutorial #2 we briefly mentioned that sequences consist of values and timings. These\n * are both stored in Pattern objects in gibberwocky, and these patterns can be controlled\n * and manipulated in a variety of ways over time.\n */\n \n// Make sure the console is open in your sidebar to see the calls to Gibber.log()\n// Create a Pattern with some initial values.\nmyvalues = Pattern( 60,62,64,65 )\n\nGibber.log( myvalues() ) // 60\nGibber.log( myvalues() ) // 62\nGibber.log( myvalues() ) // 64\nGibber.log( myvalues() ) // 65\nGibber.log( myvalues() ) // back to 60...\n\n// sequence using this pattern:\ndevices[\'bass\'].midinote.seq( myvalues, 1/8 )\n\n// Everytime we pass values and timings to .seq(), it converts these into Pattern objects\n// (unless we\'re already passing a Pattern object(s)). Remember from tutorial #2 that\n// all of our sequences have an ID number, which defaults to 0. We can access these patterns\n// as follows:\n\ndevices[\'bass\'].midinote.seq( [62,74,38,50], [1/2,1/4] )\nGibber.log( devices[\'bass\'].midinote[0].values.toString() ) \nGibber.log( devices[\'bass\'].midinote[0].timings.toString() ) \n\n// Now that we can access them, we can apply transformations:\n\ndevices[\'bass\'].midinote[0].values.reverse()\ndevices[\'bass\'].midinote[0].values.transpose( 1 ) // add 1 to each value\ndevices[\'bass\'].midinote[0].values.scale( 1.5 ) // scale each value by .5\ndevices[\'bass\'].midinote[0].values.rotate( 1 ) // shift values to the right\ndevices[\'bass\'].midinote[0].values.rotate( -1 ) // shift values to the left\ndevices[\'bass\'].midinote[0].values.reset() // reset to initial values\n\n// We can sequence these transformations:\ndevices[\'bass\'].midinote[0].values.rotate.seq( 1,1 )\ndevices[\'bass\'].midinote[0].values.reverse.seq( 1, 2 )\ndevices[\'bass\'].midinote[0].values.transpose.seq( 1, 2 )\ndevices[\'bass\'].midinote[0].values.reset.seq( 1, 8 )\n\n// This enables us to quickly create variation over time. One more tutorial to go!\n// Learn more about creating synthesis graphs for modulation in tutorial #5.'), _defineProperty(_Examples, 'tutorial 5: modulating with gen~', '/* Gen is an extension for Max for Live for synthesizing audio/video signals.\nLFOs, ramps, stochastic signals... Gen can create a wide variety of modulation sources for\nexploration.\n\nWe\'ve seen that the first outlet of gibberwocky is used for messaging. The remaining outlets\nare used for signals created by Gen objects. You can determine the number of outlets\nusing the @signals property; for example, [gibberwocky @signals 4], as seen in the gibberwocky\nhelp patch, has four outputs for audio signals in addtion to its messaging output (for a total\nof 5).\n*/\n\n// Let\'s experiment! Create a [gibberwocky @signals 1] object and connect the rightmost outlet\n// to a [scope~]. We can send a simple ramp as follows:\nsignals[0]( phasor(1) )\n\n// This creates a sawtooth wave with a range of {0,1}. We can also do sine waves:\nsignals[0]( cycle(1) )\n\n// Note that the cycle ugen generates a full bandwidth audio signal with a range of {-1,1}\n// Often times we want to specify a center point (bias) for our sine oscillator, in addition to \n// a specific amplitude and frequency. The lfo() function provides a simpler syntax for doing this:\n\n// frequency, amplitude, bias\nmylfo = lfo( 2, .2, .7 )\n\nsignals[0]( mylfo )\n\n// We can also easily sequence parameters of our LFO XXX CURRENTLY BROKEN:\n\nmylfo.frequency.seq( [ .5,1,2,4 ], 2 )\n\n/* ... as well as sequence any other parameter in Live controlled by a genish.js graph. Although the lfo()\nugen provides named properties for controlling frequency, amplitude, and centroid, there is a more\ngeneric way to sequence any aspect of a gen~ ugen by using the index operator ( [] ). For example,\ncycle() contains a single inlet that controls its frequency, to sequence it we would use: */\n\nmycycle = cycle( .25 )\n\nmycycle[ 0 ].seq( [ .25, 1, 2 ], 1 )\n\nsignals[0]( add( .5, div( mycycle, 2 ) ) )\n\n/*For other ugens that have more than one argument (see the genish.js random tutorial for an example) we\nsimply indicate the appropriate index... for example, mysah[ 1 ] etc. For documentation on the types of\nugens that are available, see the gen~ reference: https://docs.cycling74.com/max7/vignettes/gen~_operators*/'), _defineProperty(_Examples, 'tutorial 6: randomness', '/* gibberwocky.max - tutorial #6: Randomness\n *\n * This tutorial covers the basics of using randomness in gibberwocky.max. \n * It assumes you\'ve done all the other tutorials (#4 might be OK to have skipped),\n * have the gibberwocky help patch loaded, DSP turned on in Max and the global\n * transport rnning.\n *\n * Randomness in gibberwocky can be used to both create random values for sequencing \n * as well as stochastic signals for modulation purposes.\n */\n \n// rndf() and rndi() are used to generate a single random float or integer\n// make sure you have the console tab in the gibberwocky sidebar\nlog( rndf() ) // outputs floats between 0-1\nlog( rndi() ) // outputs either 0 or 1\n\n// although 0 and 1 are the default min/max values, we can pass\n// arbitrary bounds:\n\nlog( rndf(-1,1) )\nlog( rndi(0,127) )\n\n// if we pass a third value, we can create multiple random numbers at once,\n// returned as an array.\n\nlog( rndf( 0,1,4 ) )\nlog( rndi( 0,127,3 ) )\n\n// so, if we wanted to sequence a random midinote to the \'bass\' device\n// in the gibberwocky help patcher, we could sequence a function as follows:\n\ndevices[\'bass\'].midinote.seq( ()=> rndi(0,127), 1/8 )\n\n// Whenever gibberwocky sees a function in a sequence, it calls that function\n// to generate a value or a timing. In practice this is common enough with\n// random numbers that gibberwocky has a shortcut for creating functions\n// that return a random value(s) in a particular range.\n// Simply capitalize the call to rndi or rndf (to Rndi / Rndf ).\n\nclear() // clear previous sequence\ndevices[\'bass\'].note.seq( Rndi(-14,-7), 1/8 )\n\n// And chords:\nclear()\ndevices[\'bass\'].chord.seq( Rndi(14,21,3), 1/8 )\n\n// In addition to creating functions outputting random numbers, we can\n// also randomly pick from the arrays used to initialize patterns.\n\n// randomly play open or closed hi-hat every 1/16th note\ndevices[\'drums\'].midinote.seq( [42,46].rnd(), 1/16 )\n\n// For timings, it\'s often important to ensure that patterns eventually align\n// themselves with a beat grid. For example, if we randomly choose a single 1/16th \n// note timing, then every subsequent note played will be offset from a 1/8th note\n// grid until a second 1/16th note is chosen. We can ensure that particular values\n// are repeated whenever they are selected to help with this problem.\n\n// play constant kick drum to hear how bass aligns with 1/4 grid\ndevices[\'drums\'].midinote.seq( 36, 1/4 )\n\n// whenever a 1/16th timing is used, use it twice in a row\ndevices[\'bass\'].note.seq( -14, [1/8,1/16].rnd( 1/16,2 ) )\n\n// whenever a 1/16th timing is used, use it twice in a row and\n// whenever a 1/12th timing is used, use it three times in a row\ndevices[\'bass\'].note.seq( -14, [1/8,1/16,1/12].rnd( 1/16,2,1/12,3 ) )\n\n// OK, that\'s the basics of using randomness in patterns. But we can also use\n// noise to create randomness in modulations.\n\n// here\'s noise() going out the second outlet of gibberwocky\nsignals[0]( noise() ) \n\n// we can scale the noise\nsignals[0]( mul( noise(), .5 ) ) \n\n// we can also use sample and hold (sah) to selectively sample a noise signal.\n// below, we sample noise whenever a separate noise signal crosses\n// a threshold of .99995\nsignals[0]( sah( noise(), noise(), .99995 ) ) \n\n// alternatively, randomly sample a sine wave\nsignals[0]( sah( cycle(2), noise(), .999 ) )\n\n// OK, that\'s it for randomness... use it wisely!'), _defineProperty(_Examples, 'using the Score() object', '// Scores are lists of functions with associated\n// relative time values. In the score below, the first function has\n// a time value of 0, which means it begins playing immediately. The\n// second has a value of 1, which means it beings playing one measure\n// after the previously executed function. The other funcions have\n// timestamps of two, which means they begins playing two measures after\n// the previously executed function. Scores have start(), stop(),\n// loop(), pause() and rewind() methods.\n\ns = Score([\n 0, ()=> devices[\'bass\'].note.seq( -14, 1/4 ),\n \n 1, ()=> devices[\'bass\'].note.seq( 0, Euclid(5,8) ),\n \n 2, ()=> {\n arp = Arp( [0,1,3,5], 3, \'updown2\' )\n devices[\'bass\'].note.seq( arp, 1/32 )\n },\n \n 2, ()=> arp.transpose( 1 ),\n \n 2, ()=> arp.shuffle()\n])\n\n// Scores can also be stopped automatically to await manual retriggering.\n\ns2 = Score([\n 0, ()=> devices[\'bass\'].note( 0 ),\n\n 1/2, ()=> devices[\'bass\'].note( 1 ),\n\n Score.wait, null,\n\n 0, ()=> devices[\'bass\'].note( 2 )\n])\n\n// restart playback\ns2.next()\n\n// CURRENTLY BROKEN\n/* The loop() method tells a score to... loop. An optional argument specifies\n * an amount of time to wait between the end of one loop and the start of the next.*/\n\ns3 = Score([\n 0, ()=> devices[\'bass\'].note.seq( 0, 1/4 ),\n 1, ()=> devices[\'bass\'].note.seq( [0,7], 1/8 ),\n 1, ()=> devices[\'bass\'].note.seq( [0, 7, 14], 1/12 )\n])\n\ns3.loop( 1 )\n\n'), _defineProperty(_Examples, 'using the Arp() object (arpeggiator)', '/*\n * This tutorial assumes familiarity with the material\n * covered in tutorials 2–4.\n *\n * The Arp() object creates wrapped Pattern objects (see tutorial\n * #4) that are simply functions playing arpeggios. However,\n * the pattern transformations available in gibberwocky open\n * up a great deal of flexiblity in manipulating these arpeggios.\n */\n\n// Make an arp: chord, number of octaves, mode.\nmyarp = Arp( [0,2,4,5], 4, \'updown\' )\n\n// other modes include \'up\' and \'down\'. XXX updown2 is broken :( \n\n// play arpeggiator with 1/16 notes\ndevices[\'bass\'].note.seq( myarp, 1/16 )\n\n// change root of Scale (see tutorial #3)\nScale.root( \'c2\' )\n\n// randomize arpeggiator\nmyarp.shuffle()\n\n// transpose arpeggiator over time\nmyarp.transpose.seq( 1,1 )\n\n// reset arpeggiator\nmyarp.reset()\n\n// stop arpeggiator\ndevices[\'bass\'].stop()\n\n// The Arp() object can also be used with MIDI note values instead of\n// gibberwocky\'s system of harmony. However, arp objects are designed\n// to work with calls to note() by default, accordingly, they tranpose\n// patterns by seven per octave (there are seven notes in a scale of one\n// octave). For MIDI notes, there are 12 values... we can specify this\n// as a fourth parameter to the Arp() constructor.\n\nmidiArp = Arp( [60,62,64,67,71], 4, \'down\', 12 )\n\ndevices[\'bass\'].midinote.seq( midiArp, 1/32 )\n\n// bring everything down an octace\nmidiArp.transpose( -12 )\n\n// change number of octaves\nmidiArp.octaves = 2\n'), _defineProperty(_Examples, 'using the Euclid() object (euclidean rhythms)', '/*\n * This tutorial assumes familiarty with the material\n * covered in tutorial #2. It will cover the basics of\n * working with Euclidean rhythms in gibberwocky.\n *\n * Euclidean rhythms are specifcations of rhythm using\n * a number of pulses allocated over a number of beats.\n * The algorithm attempts to distribute the pulses as\n * evenly as possible over all beats while maintaining\n * a grid. You can read a paper describing this here:\n *\n * http://archive.bridgesmathart.org/2005/bridges2005-47.pdf\n *\n * For example, consider the rhythm \'5,8\' where there\n * are 5 pulses over the span of eight notes while\n * maintaining a temporal grid. The algorithm distributes \n * these as follows: "x.xx.xx." where \'x\' represents a pulse\n * and \'.\' represents a rest. Below are a few other examples:\n *\n * 1,4 : x...\n * 2,3 : x.x\n * 2,5 : x.x..\n * 3,5 : x.x.x\n * 3,8 : x..x..x.\n * 4,9 : x.x.x.x..\n * 5,9 : x.x.x.x.x\n *\n * In gibberwocky, by default the number of beats chosen\n * also determines the time used by each beat; selecting\n * \'5,8\' means 5 pulses spread across 8 1/8 notes. However,\n * you can also specify a different temporal resolution for\n * the resulting pattern: \'5,8,1/16\' means 5 pulses spread\n * across 8 beats where each beat is a 1/16th note.\n *\n * You can specify Euclidean rhyhtms using the Euclid()\n * function, which returns a pattern (see tutorial #4);\n * in the example below I\'ve assigned this to the variable E.\n */\n\n// store for faster reference\nE = Euclid\n\ndevices[\'bass\'].duration( 10 )\n\n// 5 pulses spread over 8 eighth notes\ndevices[\'bass\'].midinote.seq( 60, E(5,8) )\n\n// 3 pulses spread over 8 sixteenth notes\ndevices[\'bass\'].midinote.seq( 48, E( 3, 8, 1/16 ), 1 )\n\n// a quick way of notating x.x.\ndevices[\'bass\'].midinote.seq( 36, E(2,4), 2 ) \n\n// because Euclid() generates Pattern objects (see tutorial #3)\n// we can transform the patterns it generates:\n\ndevices[\'bass\'].midinote[1].timings.rotate.seq( 1,1 )\n\n'), _defineProperty(_Examples, 'using the Steps() object (step-sequencer)', '/* Steps() creates a group of sequencer objects. Each\n * sequencer is responsible for playing a single note,\n * where the velocity of each note is determined by\n * a hexadecimal value (0-f), where f is the loudest note.\n * A value of \'.\' means that no MIDI note message is sent\n * with for that particular pattern element.\n *\n * The lengths of the patterns found in a Steps object can\n * differ. By default, the amount of time for each step in\n * a pattern equals 1 divided by the number of steps in the\n * pattern. In the example below, most patterns have sixteen\n * steps, so each step represents a sixteenth note. However,\n * the first two patterns (60 and 62) only have four steps, so\n * each is a quarter note. \n *\n * The individual patterns can be accessed using the note\n * numbers they are assigned to. So, given an instance with\n * the name \'a\' (as below), the pattern for note 60 can be\n * accessed at a[60]. Note that you have to access with brackets\n * as a.60 is not valid JavaScript.\n *\n * The second argument to Steps is the instrument to target. Note\n * that while the example below is designed to work with the\n * Analogue Drums device found in the gibberwocky help file,\n * that instrument is actually NOT velocity sensitive. \n */\n\nsteps = Steps({\n [36]: \'ffff\', \n [38]: \'.a.a\',\n [41]: \'........7.9.c..d\',\n [43]: \'..6..78..b......\',\n [45]: \'..c.f....f..f..3\', \n [42]: \'.e.a.a...e.a.e.a\', \n [46]: \'..............e.\',\n}, devices[\'drums\'] )\n\n// rotate one pattern (assigned to midinote 71)\n// in step sequencer every measure\nsteps[42].rotate.seq( 1,1 )\n\n// reverse all steps each measure\nsteps.reverse.seq( 1, 2 )'), _Examples); +}, _defineProperty(_Examples, 'tutorial 1: basic messaging', '/*\n * gibberwocky.live - tutorial #1: basic messaging\n *\n * This first intro will explain how to send\n * MIDI note messages and control device and track parameters.\n *\n * To start, makesure you open the gibberwocky.demo project and\n * have Live\'s transport running.\n*/\n\n// The demo gibberwocky project has three tracks: drums, bass, and ambient\n// piano. Let\'s start playing notes with the bass. The bass is located on the \n// second track, zero-indexed (start counting from zero).\nbass = tracks[1]\nbass.midinote( 60 ) // send middle C\n\n// Click on the \'lom\' tab (Live Object Model) in the sidebar on the right side\n// of the gibberwocky client. This lists all the parameters exposed for control\n// to gibberwocky. The bass track is listed under \'2-Muugy\' (Muggy is the name\n// of the bass preset). If you uncollapse this branch, you see that the track\n// contains a single Simpler device (all gibberwocky objects are ignored). Open\n// up that Simpler branch, and you see all the parameters that can be controlled.\n// If you drag and drop the \'Filter Freq\' parameter into the code editor, it\n// will insert the full path for that control into the editor. It should look\n// something like this:\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\']\n\n// This is the path to a function we can call to change the filter cutoff frequency,\n// like so:\n\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\'](.75)\ntracks[\'2-Muugy\'].midinote( 36 )\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\'](.25)\ntracks[\'2-Muugy\'].midinote( 36 )\n\n// Note that we can shorten this in a number of ways. First, we can always refer\n// to tracks and devices by their array position. In this case, the track index is\n// 1 and the device index is 0 (remember, gibberwocky devices are ignored).\n\ntracks[1].devices[0][\'Filter Freq\']( .5 ) // same effect!\n\n// we can also use the shortcut we created earlier\nbass.devices[0][\'Filter Freq\']( .35 )\n\n// or...\nsimpler = tracks[1].devices[0]\nsimpler[\'Filter Freq\']( 1 )\n\n// Conveniently (well, in most cases) all parameters are measured from 0-1, so\n// you don\'t really have to worry about ranges.\n\n// In addition to controlling devices, we can also control parameters of each\n// track in Live, such as volume, panning, mute and solo. This includes\n// the return tracks and the master track as well.\n\ntracks[0].volume( 0 ) // effectively mute our drums track \nreturns[0].volume( 1 ) // increase our reverb volume\ntracks[0].sends[0]( 1 ) // send our drum track full-blast to our reverb\nmaster.volume( .5 ) // set the master volume\n\n// OK, that\'s some basics out of the way. Try the sequencing tutorial next!'), _defineProperty(_Examples, 'tutorial 2: basic sequencing', '/* gibberwocky.live - tutorial #2: basic sequencing\n *\n * This tutorial will provide an introdution to sequencing messages in gibberwocky. In\n * order for sequencing in gibberwocky.live to work, you must start the Global Transport\n * running in Live. We\'re also assuming you\'re running the gibberwocky.demo project for\n * this tutorial.\n */\n\n// In tutorial #1, we saw how we could send MIDI messages to specific tracks\n// in Live. We can easily sequence any of these methods by adding\n// a call to .seq(). For example:\n\n// send noteon message with a first value of 36\ntracks[1].midinote( 36 )\n\n// send same value every quarter note\ntracks[1].midinote.seq( 36, 1/4 )\n\n// You can stop all sequences in gibberwocky with the Ctrl+. keyboard shortcut\n// (Ctrl + period) or by executing the command clear(). \n// You can also stop all sequences on a specific track:\ntracks[1].stop()\n\n// Most sequences in gibberwocky contain values (36) and timings (1/4). To\n// sequence multiple values we simply pass an array:\ntracks[1].midinote.seq( [36,48,60], 1/4 )\n\n// ... and we can do the same thing with multiple timings:\ntracks[1].midinote.seq( [36,48,60], [1/4,1/8] )\n\n// We can also sequence our note velocities and durations.\nclear()\ntracks[1].midinote.seq( 48, 1/2 )\ntracks[1].velocity.seq( [16, 64, 127], 1/2 )\ntracks[1].duration.seq( [10, 100,500], 1/2 )\n\n// If you experimented with running multiple variations of the midinote \n// sequences you might have noticed that only one runs at a time. For example,\n// if you run these two lines:\n\nclear()\ntracks[1].midinote.seq( 72, 1/4 )\ntracks[1].midinote.seq( 48, 1/4 )\n\n// ...you\'ll notice only the second one actually triggers. By default, gibberwocky\n// will replace an existing sequence with a new one. To stop this, you can pass an ID number \n// as a third argument to calls to .seq(). In the examples of sequencing we\'ve seen so far,\n// no ID has been given, which means gibberwocky is assuming a default ID of 0 for each\n// sequence. When you launch a sequence on a channel that has the same ID as another running \n// sequence, the older sequence is stopped. If the sequences have different IDs they run \n// concurrently. Note this makes it really easy to create polyrhythms.\n\nclear()\ntracks[1].midinote.seq( 48, 1 ) // assumes ID of 0\ntracks[1].midinote.seq( 60, 1/2, 1 ) \ntracks[1].midinote.seq( 72, 1/3, 2 ) \ntracks[1].midinote.seq( 84, 1/7, 3 ) \n\n// We can also sequence calls to midichord. You might remember from the first tutorial\n// that we pass midichord an array of values, where each value represents one note. This\n// means we need to pass an array of arrays in order to move between different chords.\n\nclear()\ntracks[2].midichord.seq( [[60,64,68], [62,66,72]], 1/2 )\n\n// Even we\'re only sequencing a single chord, we still need to pass a 2D array. Of course,\n// specifying arrays of MIDI values is not necessarily an optimal representation for chords.\n// Move on to tutorial #3 to learn more about how to leverage music theory in gibberwocky.'), _defineProperty(_Examples, 'tutorial 3: harmony', '/* gibberwocky.live - tutorial #3: Harmony\n *\n * This tutorial covers the basics of using harmony in gibberwocky.live. It assumes you\n * know the basics of sequencing (tutorial #2) and are using the gibberwocky.demo project. \n *\n * In the previous tutorials we looked at using raw MIDI values to send messages. However,\n * using MIDI note numbers is not an ideal representation. gibberwocky includes knoweldge of\n * scales, chords, and note names to make musical sequencing easier and more flexible. In this\n * tutorial, instead of using track.midinote() and track.midichord() we\'ll be using \n * channel.note() and channel.chord(). These methods use gibberwocky\'s theory objects to\n * determine what MIDI notes are eventually outputted.\n */\n\n// In our previous tutorial, we sent out C in the fourth octave by using MIDI number 60:\nbass = tracks[1]\nbass.midinote( 60 )\n\n// We can also specify notes with calls to the note() method by passing a name and octave.\nbass.note( \'c4\' )\nbass.note( \'fb3\' )\n\nbass.note.seq( [\'c2\',\'e2\',\'g2\'], 1/8 )\n\n// remember, Ctrl+. (or clear()) stops all running sequences.\n\n// In gibberwocky, the default scale employed is C minor, starting in the fourth octave. \n// This means that if we pass 0 as a value to note(), C4 will also be played.\nbass.note( 0 )\n\n// sequence C minor scale, starting in the fourth octave:\nbass.note.seq( [0,1,2,3,4,5,6,7], 1/8 )\n\n// negative scale indices also work:\nbass..note.seq( [-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7], 1/8 )\n\n// there is a global Scale object we can use to change the root and mode\n// for all scales. Run the lines below individually with the previous note sequence running.\nScale.root( \'d4\' )\nScale.mode( \'lydian\' )\n\nScale.root( \'c4\' )\nScale.mode( \'phrygian\' )\n\n// We can also sequence changes to the root / mode:\nScale.root.seq( [\'c2\',\'d2\',\'f2\',\'g2\'], 2 )\nScale.mode.seq( [\'lydian\', \'ionian\', \'locrian\'], 2 )\n\n// stop the scale sequencing\nScale.root[0].stop()\nScale.mode[0].stop()\nScale.root( \'c4\' )\n\n// We can also define our own scales using chromatic scale indices. Unfortunately, \n// microtuning with MIDI is very diffcult, so only the standard eleven notes of \n// Western harmony are supported. Scales can have arbtrary numbers of notes.\nScale.modes[ \'my mode\' ] = [ 0,1,2,3,5,6,10 ]\nScale.mode( \'my mode\' )\n\nScale.modes[ \'another mode\' ] = [0,1]\nScale.mode( \'another mode\' )\n\nScale.mode.seq( [\'my mode\', \'another mode\'], 4 )\n\n/******** chords **********/\n// Last but not least there are a few different ways to specify chords in gibberwocky.\n// First, clear the current scene using Ctrl+.\n\npad = tracks[2]\n\n// We can use note names:\npad.chord( [\'c4\',\'eb4\',\'gb4\',\'a4\'] )\n\n// Or we can use scale indices:\npad.chord( [0,2,4,5] )\n\n// sequence in two-dimensional array\npad.chord.seq( [[0,2,4,5], [1,3,4,6]], 1 )\n\n// We can also use strings that identify common chord names.\npad.chord( \'c4maj7\' )\npad.chord( \'c#4sus7b9\' )\n\n\npad.chord.seq( [\'c4dim7\', \'bb3maj7\', \'fb3aug7\'], 2 )\n\n// OK, that\'s harmony in a nutshell. Next learn a bit about patterns and\n// pattern manipulation in gibberwocky in tutorial #4.'), _defineProperty(_Examples, 'tutorial 4: patterns and pattern transformations', '/* gibberwocky.max - tutorial #4: Patterns and Transformations\n *\n * This tutorial covers the basics of using patterns in gibberwocky.max. It assumes you\n * know the basics of sequencing (tutorial #2), have the the gibberwocky help patch\n * loaded, and the Global Transport running.\n *\n * In tutorial #2 we briefly mentioned that sequences consist of values and timings. These\n * are both stored in Pattern objects in gibberwocky, and these patterns can be controlled\n * and manipulated in a variety of ways over time.\n */\n \n// Make sure the console is open in your sidebar to see the calls to Gibber.log()\n// Create a Pattern with some initial values.\nmyvalues = Pattern( 60,62,64,65 )\n\nGibber.log( myvalues() ) // 60\nGibber.log( myvalues() ) // 62\nGibber.log( myvalues() ) // 64\nGibber.log( myvalues() ) // 65\nGibber.log( myvalues() ) // back to 60...\n\n// sequence using this pattern:\ndevices[\'bass\'].midinote.seq( myvalues, 1/8 )\n\n// Everytime we pass values and timings to .seq(), it converts these into Pattern objects\n// (unless we\'re already passing a Pattern object(s)). Remember from tutorial #2 that\n// all of our sequences have an ID number, which defaults to 0. We can access these patterns\n// as follows:\n\ndevices[\'bass\'].midinote.seq( [62,74,38,50], [1/2,1/4] )\nGibber.log( devices[\'bass\'].midinote[0].values.toString() ) \nGibber.log( devices[\'bass\'].midinote[0].timings.toString() ) \n\n// Now that we can access them, we can apply transformations:\n\ndevices[\'bass\'].midinote[0].values.reverse()\ndevices[\'bass\'].midinote[0].values.transpose( 1 ) // add 1 to each value\ndevices[\'bass\'].midinote[0].values.scale( 1.5 ) // scale each value by .5\ndevices[\'bass\'].midinote[0].values.rotate( 1 ) // shift values to the right\ndevices[\'bass\'].midinote[0].values.rotate( -1 ) // shift values to the left\ndevices[\'bass\'].midinote[0].values.reset() // reset to initial values\n\n// We can sequence these transformations:\ndevices[\'bass\'].midinote[0].values.rotate.seq( 1,1 )\ndevices[\'bass\'].midinote[0].values.reverse.seq( 1, 2 )\ndevices[\'bass\'].midinote[0].values.transpose.seq( 1, 2 )\ndevices[\'bass\'].midinote[0].values.reset.seq( 1, 8 )\n\n// This enables us to quickly create variation over time. One more tutorial to go!\n// Learn more about creating synthesis graphs for modulation in tutorial #5.'), _defineProperty(_Examples, 'tutorial 5: modulating with gen~', '/* Gen is an extension for Max for Live for synthesizing audio/video signals.\nLFOs, ramps, stochastic signals... Gen can create a wide variety of modulation sources for\nexploration.\n\nWe\'ve seen that the first outlet of gibberwocky is used for messaging. The remaining outlets\nare used for signals created by Gen objects. You can determine the number of outlets\nusing the @signals property; for example, [gibberwocky @signals 4], as seen in the gibberwocky\nhelp patch, has four outputs for audio signals in addtion to its messaging output (for a total\nof 5).\n*/\n\n// Let\'s experiment! Create a [gibberwocky @signals 1] object and connect the rightmost outlet\n// to a [scope~]. We can send a simple ramp as follows:\nsignals[0]( phasor(1) )\n\n// This creates a sawtooth wave with a range of {0,1}. We can also do sine waves:\nsignals[0]( cycle(1) )\n\n// Note that the cycle ugen generates a full bandwidth audio signal with a range of {-1,1}\n// Often times we want to specify a center point (bias) for our sine oscillator, in addition to \n// a specific amplitude and frequency. The lfo() function provides a simpler syntax for doing this:\n\n// frequency, amplitude, bias\nmylfo = lfo( 2, .2, .7 )\n\nsignals[0]( mylfo )\n\n// We can also easily sequence parameters of our LFO XXX CURRENTLY BROKEN:\n\nmylfo.frequency.seq( [ .5,1,2,4 ], 2 )\n\n/* ... as well as sequence any other parameter in Live controlled by a genish.js graph. Although the lfo()\nugen provides named properties for controlling frequency, amplitude, and centroid, there is a more\ngeneric way to sequence any aspect of a gen~ ugen by using the index operator ( [] ). For example,\ncycle() contains a single inlet that controls its frequency, to sequence it we would use: */\n\nmycycle = cycle( .25 )\n\nmycycle[ 0 ].seq( [ .25, 1, 2 ], 1 )\n\nsignals[0]( add( .5, div( mycycle, 2 ) ) )\n\n/*For other ugens that have more than one argument (see the genish.js random tutorial for an example) we\nsimply indicate the appropriate index... for example, mysah[ 1 ] etc. For documentation on the types of\nugens that are available, see the gen~ reference: https://docs.cycling74.com/max7/vignettes/gen~_operators*/'), _defineProperty(_Examples, 'tutorial 6: randomness', '/* gibberwocky.max - tutorial #6: Randomness\n *\n * This tutorial covers the basics of using randomness in gibberwocky.max. \n * It assumes you\'ve done all the other tutorials (#4 might be OK to have skipped),\n * have the gibberwocky help patch loaded, DSP turned on in Max and the global\n * transport rnning.\n *\n * Randomness in gibberwocky can be used to both create random values for sequencing \n * as well as stochastic signals for modulation purposes.\n */\n \n// rndf() and rndi() are used to generate a single random float or integer\n// make sure you have the console tab in the gibberwocky sidebar\nlog( rndf() ) // outputs floats between 0-1\nlog( rndi() ) // outputs either 0 or 1\n\n// although 0 and 1 are the default min/max values, we can pass\n// arbitrary bounds:\n\nlog( rndf(-1,1) )\nlog( rndi(0,127) )\n\n// if we pass a third value, we can create multiple random numbers at once,\n// returned as an array.\n\nlog( rndf( 0,1,4 ) )\nlog( rndi( 0,127,3 ) )\n\n// so, if we wanted to sequence a random midinote to the \'bass\' device\n// in the gibberwocky help patcher, we could sequence a function as follows:\n\ndevices[\'bass\'].midinote.seq( ()=> rndi(0,127), 1/8 )\n\n// Whenever gibberwocky sees a function in a sequence, it calls that function\n// to generate a value or a timing. In practice this is common enough with\n// random numbers that gibberwocky has a shortcut for creating functions\n// that return a random value(s) in a particular range.\n// Simply capitalize the call to rndi or rndf (to Rndi / Rndf ).\n\nclear() // clear previous sequence\ndevices[\'bass\'].note.seq( Rndi(-14,-7), 1/8 )\n\n// And chords:\nclear()\ndevices[\'bass\'].chord.seq( Rndi(14,21,3), 1/8 )\n\n// In addition to creating functions outputting random numbers, we can\n// also randomly pick from the arrays used to initialize patterns.\n\n// randomly play open or closed hi-hat every 1/16th note\ndevices[\'drums\'].midinote.seq( [42,46].rnd(), 1/16 )\n\n// For timings, it\'s often important to ensure that patterns eventually align\n// themselves with a beat grid. For example, if we randomly choose a single 1/16th \n// note timing, then every subsequent note played will be offset from a 1/8th note\n// grid until a second 1/16th note is chosen. We can ensure that particular values\n// are repeated whenever they are selected to help with this problem.\n\n// play constant kick drum to hear how bass aligns with 1/4 grid\ndevices[\'drums\'].midinote.seq( 36, 1/4 )\n\n// whenever a 1/16th timing is used, use it twice in a row\ndevices[\'bass\'].note.seq( -14, [1/8,1/16].rnd( 1/16,2 ) )\n\n// whenever a 1/16th timing is used, use it twice in a row and\n// whenever a 1/12th timing is used, use it three times in a row\ndevices[\'bass\'].note.seq( -14, [1/8,1/16,1/12].rnd( 1/16,2,1/12,3 ) )\n\n// OK, that\'s the basics of using randomness in patterns. But we can also use\n// noise to create randomness in modulations.\n\n// here\'s noise() going out the second outlet of gibberwocky\nsignals[0]( noise() ) \n\n// we can scale the noise\nsignals[0]( mul( noise(), .5 ) ) \n\n// we can also use sample and hold (sah) to selectively sample a noise signal.\n// below, we sample noise whenever a separate noise signal crosses\n// a threshold of .99995\nsignals[0]( sah( noise(), noise(), .99995 ) ) \n\n// alternatively, randomly sample a sine wave\nsignals[0]( sah( cycle(2), noise(), .999 ) )\n\n// OK, that\'s it for randomness... use it wisely!'), _defineProperty(_Examples, 'using the Score() object', '// Scores are lists of functions with associated\n// relative time values. In the score below, the first function has\n// a time value of 0, which means it begins playing immediately. The\n// second has a value of 1, which means it beings playing one measure\n// after the previously executed function. The other funcions have\n// timestamps of two, which means they begins playing two measures after\n// the previously executed function. Scores have start(), stop(),\n// loop(), pause() and rewind() methods.\n\ns = Score([\n 0, ()=> devices[\'bass\'].note.seq( -14, 1/4 ),\n \n 1, ()=> devices[\'bass\'].note.seq( 0, Euclid(5,8) ),\n \n 2, ()=> {\n arp = Arp( [0,1,3,5], 3, \'updown2\' )\n devices[\'bass\'].note.seq( arp, 1/32 )\n },\n \n 2, ()=> arp.transpose( 1 ),\n \n 2, ()=> arp.shuffle()\n])\n\n// Scores can also be stopped automatically to await manual retriggering.\n\ns2 = Score([\n 0, ()=> devices[\'bass\'].note( 0 ),\n\n 1/2, ()=> devices[\'bass\'].note( 1 ),\n\n Score.wait, null,\n\n 0, ()=> devices[\'bass\'].note( 2 )\n])\n\n// restart playback\ns2.next()\n\n// CURRENTLY BROKEN\n/* The loop() method tells a score to... loop. An optional argument specifies\n * an amount of time to wait between the end of one loop and the start of the next.*/\n\ns3 = Score([\n 0, ()=> devices[\'bass\'].note.seq( 0, 1/4 ),\n 1, ()=> devices[\'bass\'].note.seq( [0,7], 1/8 ),\n 1, ()=> devices[\'bass\'].note.seq( [0, 7, 14], 1/12 )\n])\n\ns3.loop( 1 )\n\n'), _defineProperty(_Examples, 'using the Arp() object (arpeggiator)', '/*\n * This tutorial assumes familiarity with the material\n * covered in tutorials 2–4.\n *\n * The Arp() object creates wrapped Pattern objects (see tutorial\n * #4) that are simply functions playing arpeggios. However,\n * the pattern transformations available in gibberwocky open\n * up a great deal of flexiblity in manipulating these arpeggios.\n */\n\n// Make an arp: chord, number of octaves, mode.\nmyarp = Arp( [0,2,4,5], 4, \'updown\' )\n\n// other modes include \'up\' and \'down\'. XXX updown2 is broken :( \n\n// play arpeggiator with 1/16 notes\ndevices[\'bass\'].note.seq( myarp, 1/16 )\n\n// change root of Scale (see tutorial #3)\nScale.root( \'c2\' )\n\n// randomize arpeggiator\nmyarp.shuffle()\n\n// transpose arpeggiator over time\nmyarp.transpose.seq( 1,1 )\n\n// reset arpeggiator\nmyarp.reset()\n\n// stop arpeggiator\ndevices[\'bass\'].stop()\n\n// The Arp() object can also be used with MIDI note values instead of\n// gibberwocky\'s system of harmony. However, arp objects are designed\n// to work with calls to note() by default, accordingly, they tranpose\n// patterns by seven per octave (there are seven notes in a scale of one\n// octave). For MIDI notes, there are 12 values... we can specify this\n// as a fourth parameter to the Arp() constructor.\n\nmidiArp = Arp( [60,62,64,67,71], 4, \'down\', 12 )\n\ndevices[\'bass\'].midinote.seq( midiArp, 1/32 )\n\n// bring everything down an octace\nmidiArp.transpose( -12 )\n\n// change number of octaves\nmidiArp.octaves = 2\n'), _defineProperty(_Examples, 'using the Euclid() object (euclidean rhythms)', '/*\n * This tutorial assumes familiarty with the material\n * covered in tutorial #2. It will cover the basics of\n * working with Euclidean rhythms in gibberwocky.\n *\n * Euclidean rhythms are specifcations of rhythm using\n * a number of pulses allocated over a number of beats.\n * The algorithm attempts to distribute the pulses as\n * evenly as possible over all beats while maintaining\n * a grid. You can read a paper describing this here:\n *\n * http://archive.bridgesmathart.org/2005/bridges2005-47.pdf\n *\n * For example, consider the rhythm \'5,8\' where there\n * are 5 pulses over the span of eight notes while\n * maintaining a temporal grid. The algorithm distributes \n * these as follows: "x.xx.xx." where \'x\' represents a pulse\n * and \'.\' represents a rest. Below are a few other examples:\n *\n * 1,4 : x...\n * 2,3 : x.x\n * 2,5 : x.x..\n * 3,5 : x.x.x\n * 3,8 : x..x..x.\n * 4,9 : x.x.x.x..\n * 5,9 : x.x.x.x.x\n *\n * In gibberwocky, by default the number of beats chosen\n * also determines the time used by each beat; selecting\n * \'5,8\' means 5 pulses spread across 8 1/8 notes. However,\n * you can also specify a different temporal resolution for\n * the resulting pattern: \'5,8,1/16\' means 5 pulses spread\n * across 8 beats where each beat is a 1/16th note.\n *\n * You can specify Euclidean rhyhtms using the Euclid()\n * function, which returns a pattern (see tutorial #4);\n * in the example below I\'ve assigned this to the variable E.\n */\n\n// store for faster reference\nE = Euclid\n\ndevices[\'bass\'].duration( 10 )\n\n// 5 pulses spread over 8 eighth notes\ndevices[\'bass\'].midinote.seq( 60, E(5,8) )\n\n// 3 pulses spread over 8 sixteenth notes\ndevices[\'bass\'].midinote.seq( 48, E( 3, 8, 1/16 ), 1 )\n\n// a quick way of notating x.x.\ndevices[\'bass\'].midinote.seq( 36, E(2,4), 2 ) \n\n// because Euclid() generates Pattern objects (see tutorial #3)\n// we can transform the patterns it generates:\n\ndevices[\'bass\'].midinote[1].timings.rotate.seq( 1,1 )\n\n'), _defineProperty(_Examples, 'using the Steps() object (step-sequencer)', '/* Steps() creates a group of sequencer objects. Each\n * sequencer is responsible for playing a single note,\n * where the velocity of each note is determined by\n * a hexadecimal value (0-f), where f is the loudest note.\n * A value of \'.\' means that no MIDI note message is sent\n * with for that particular pattern element.\n *\n * The lengths of the patterns found in a Steps object can\n * differ. By default, the amount of time for each step in\n * a pattern equals 1 divided by the number of steps in the\n * pattern. In the example below, most patterns have sixteen\n * steps, so each step represents a sixteenth note. However,\n * the first two patterns (60 and 62) only have four steps, so\n * each is a quarter note. \n *\n * The individual patterns can be accessed using the note\n * numbers they are assigned to. So, given an instance with\n * the name \'a\' (as below), the pattern for note 60 can be\n * accessed at a[60]. Note that you have to access with brackets\n * as a.60 is not valid JavaScript.\n *\n * The second argument to Steps is the instrument to target. Note\n * that while the example below is designed to work with the\n * Analogue Drums device found in the gibberwocky help file,\n * that instrument is actually NOT velocity sensitive. \n */\n\nsteps = Steps({\n [36]: \'ffff\', \n [38]: \'.a.a\',\n [41]: \'........7.9.c..d\',\n [43]: \'..6..78..b......\',\n [45]: \'..c.f....f..f..3\', \n [42]: \'.e.a.a...e.a.e.a\', \n [46]: \'..............e.\',\n}, devices[\'drums\'] )\n\n// rotate one pattern (assigned to midinote 71)\n// in step sequencer every measure\nsteps[42].rotate.seq( 1,1 )\n\n// reverse all steps each measure\nsteps.reverse.seq( 1, 2 )'), _Examples); module.exports = Examples; },{}],9:[function(require,module,exports){ @@ -2705,6 +2705,7 @@ var Gibber = { window.Arp = this.Arp; window.Communication = this.Communication; window.log = this.log; + window.clear = this.clear; window.Theory = this.Theory; window.Scale = this.Theory.Scale.master; diff --git a/index.html b/index.html index 7f047e7..a724542 100644 --- a/index.html +++ b/index.html @@ -3069,7 +3069,7 @@ var Examples = (_Examples = { introduction: '/* gibberwocky.live - introduction\n * \n * This introduction assumes that you have the gibberwocky.demo.als\n * project open and running in Live. If not, it\'s easy to make your own\n * version; just place an instance of the gibberwocky_master plugin on \n * Live\'s master track, and an instance of the gibberwocky_midi plugin\n * on any track you\'d like to control with gibberwokcy.\n *\n * To execute any line of code, hit Ctrl+Enter. \n * To stop all running sequences, hit Ctrl+. (period), or execute clear() \n * (Ctrl+. doesn\'t work on some non-US keyboards).\n *\n * Make sure Live\'s transport is running (hit play). When you\'ve played\n * around with this demo, start working your way through the tutorials\n * listed in the \'demos\' tab in the sidebar.\n */\n\n// start kick drum using impulse (preset 606) on tracks[0]\ntracks[0].midinote.seq( 60, Euclid(5,8) )\n\n// randomly pick between open and closed hi-hats\n// and eighth notes vs. 1/16th notes. If 1/16th\n// notes are played, always play two back to back.\ntracks[0].midinote.seq( [64,65].rnd(), [1/8,1/16].rnd(1/16,2), 1 )\n\n// play a scintillating bass line\ntracks[1].note.seq( [-14,-12,-9,-8], 1/8 )\n\n// play chords with piano sound\ntracks[2].chord.seq( Rndi(0,8,3), 2 )\n\n// control bass filter cutoff\ntracks[1].devices[0][\'Filter Freq\']( mul( beats(2), .75 ) ) \n\n// control panning of piano\ntracks[2].pan( lfo( .15 ) ) \n\n// control time parameter of impulse\ntracks[0].devices[0][\'Global Time\']( beats(8.33) ) \n\n// control transpostion of impulse with an lfo\n// increasing in frequency over 8.66 beats\ntracks[0].devices[0][\'Global Transpose\']( lfo( beats(8.66) ) ) \n' -}, _defineProperty(_Examples, 'tutorial 1: basic messaging', '/*\n * gibberwocky.live - tutorial #1: basic messaging\n *\n * This first intro will explain how to send\n * MIDI note messages and control device and track parameters.\n *\n * To start, makesure you open the gibberwocky.demo project and\n * have Live\'s transport running.\n*/\n\n// The demo gibberwocky project has three tracks: drums, bass, and ambient\n// piano. Let\'s start playing notes with the bass. The bass is located on the \n// second track, zero-indexed (start counting from zero).\nbass = tracks[1]\nbass.midinote( 60 ) // send middle C\n\n// Click on the \'lom\' tab (Live Object Model) in the sidebar on the right side\n// of the gibberwocky client. This lists all the parameters exposed for control\n// to gibberwocky. The bass track is listed under \'2-Muugy\' (Muggy is the name\n// of the bass preset). If you uncollapse this branch, you see that the track\n// contains a single Simpler device (all gibberwocky objects are ignored). Open\n// up that Simpler branch, and you see all the parameters that can be controlled.\n// If you drag and drop the \'Filter Freq\' parameter into the code editor, it\n// will insert the full path for that control into the editor. It should look\n// something like this:\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\']\n\n// This is the path to a function we can call to change the filter cutoff frequency,\n// like so:\n\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\'](.75)\ntracks[\'2-Muugy\'].midinote( 36 )\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\'](.25)\ntracks[\'2-Muugy\'].midinote( 36 )\n\n// Note that we can shorten this in a number of ways. First, we can always refer\n// to tracks and devices by their array position. In this case, the track index is\n// 1 and the device index is 0 (remember, gibberwocky devices are ignored).\n\ntracks[1].devices[0][\'Filter Freq\']( .5 ) // same effect!\n\n// we can also use the shortcut we created earlier\nbass.devices[0][\'Filter Freq\']( .35 )\n\n// or...\nsimpler = tracks[1].devices[0]\nsimpler[\'Filter Freq\']( 1 )\n\n// Conveniently (well, in most cases) all parameters are measured from 0-1, so\n// you don\'t really have to worry about ranges.\n\n// In addition to controlling devices, we can also control parameters of each\n// track in Live, such as volume, panning, mute and solo. This includes\n// the return tracks and the master track as well.\n\ntracks[0].volume( 0 ) // effectively mute our drums track \nreturns[0].volume( 1 ) // increase our reverb volume\ntracks[0].sends[0]( 1 ) // send our drum track full-blast to our reverb\nmaster.volume( .5 ) // set the master volume\n\n// OK, that\'s some basics out of the way. Try the sequencing tutorial next!'), _defineProperty(_Examples, 'tutorial 2: basic sequencing', '/* gibberwocky.live - tutorial #2: basic sequencing\n *\n * This tutorial will provide an introdution to sequencing messages in gibberwocky. In\n * order for sequencing in gibberwocky.live to work, you must start the Global Transport\n * running in Live. We\'re also assuming you\'re running the gibberwocky.demo project for\n * this tutorial.\n */\n\n// In tutorial #1, we saw how we could send MIDI messages to specific tracks\n// in Live. We can easily sequence any of these methods by adding\n// a call to .seq(). For example:\n\n// send noteon message with a first value of 36\ntracks[1].midinote( 36 )\n\n// send same value every quarter note\ntracks[1].midinote.seq( 36, 1/4 )\n\n// You can stop all sequences in gibberwocky with the Ctrl+. keyboard shortcut\n// (Ctrl + period) or by executing the command clear(). \n// You can also stop all sequences on a specific track:\ntracks[1].stop()\n\n// Most sequences in gibberwocky contain values (36) and timings (1/4). To\n// sequence multiple values we simply pass an array:\ntracks[1].midinote.seq( [36,48,60], 1/4 )\n\n// ... and we can do the same thing with multiple timings:\ntracks[1].midinote.seq( [36,48,60], [1/4,1/8] )\n\n// We can also sequence our note velocities and durations.\ntracks[1].midinote.seq( 48, 1/2 )\ntracks[1].velocity.seq( [16, 64, 127], 1/2 )\ntracks[1].duration.seq( [10, 100,500], 1/2 )\n\n// If you experimented with running multiple variations of the midinote \n// sequences you might have noticed that only one runs at a time. For example,\n// if you run these two lines:\n\ntracks[1].midinote.seq( 72, 1/4 )\ntracks[1].midinote.seq( 48, 1/4 )\n\n// ...you\'ll notice only the second one actually triggers. By default, gibberwocky\n// will replace an existing sequence with a new one. To stop this, you can pass an ID number \n// as a third argument to calls to .seq(). In the examples of sequencing we\'ve seen so far,\n// no ID has been given, which means gibberwocky is assuming a default ID of 0 for each\n// sequence. When you launch a sequence on a channel that has the same ID as another running \n// sequence, the older sequence is stopped. If the sequences have different IDs they run \n// concurrently. Note this makes it really easy to create polyrhythms.\n\ntracks[1].midinote.seq( 48, 1 ) // assumes ID of 0\ntracks[1].midinote.seq( 60, 1/2, 1 ) \ntracks[1].midinote.seq( 72, 1/3, 2 ) \ntracks[1].midinote.seq( 84, 1/7, 3 ) \n\n// We can also sequence calls to midichord. You might remember from the first tutorial\n// that we pass midichord an array of values, where each value represents one note. This\n// means we need to pass an array of arrays in order to move between different chords.\n\nclear()\ntracks[2].midichord.seq( [[60,64,68], [62,66,72]], 1/2 )\n\n// Even we\'re only sequencing a single chord, we still need to pass a 2D array. Of course,\n// specifying arrays of MIDI values is not necessarily an optimal representation for chords.\n// Move on to tutorial #3 to learn more about how to leverage music theory in gibberwocky.'), _defineProperty(_Examples, 'tutorial 3: harmony', '/* gibberwocky.max - tutorial #3: Harmony\n *\n * This tutorial covers the basics of using harmony in gibberwocky.midi. It assumes you\n * know the basics of sequencing (tutorial #2) and have an appropriate MIDI output setup.\n * It also assumes you have the gibberwocky help patch open and the transport running.\n *\n * In the previous tutorials we looked at using raw MIDI values to send messages. However,\n * using MIDI note numbers is not an ideal representation. gibberwocky includes knoweldge of\n * scales, chords, and note names to make musical sequencing easier and more flexible. In this\n * tutorial, instead of using channel.midinote() and channel.midichord() we\'ll be using \n * channel.note() and channel.chord(). These methods use gibberwocky\'s theory objects to\n * determine what MIDI notes are eventually outputted.\n */\n\n// In our previous tutorial, we sent out C in the fourth octave by using MIDI number 60:\ndevices[\'bass\'].midinote( 60 )\n\n// We can also specify notes with calls to the note() method by passing a name and octave.\ndevices[\'bass\'].note( \'c4\' )\ndevices[\'bass\'].note( \'fb3\' )\n\ndevices[\'bass\'].note.seq( [\'c4\',\'e4\',\'g4\'], 1/8 )\n\n// remember, Ctrl+. stops all running sequences.\n\n// In gibberwocky, the default scale employed is C minor, starting in the fourth octave. \n// This means that if we pass 0 as a value to note(), C4 will also be played.\ndevices[\'bass\'].note( 0 )\n\n// sequence C minor scale, starting in the fourth octave:\ndevices[\'bass\'].note.seq( [0,1,2,3,4,5,6,7], 1/8 )\n\n// negative scale indices also work:\ndevices[\'bass\'].note.seq( [-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7], 1/8 )\n\n// there is a global Scale object we can use to change the root and mode\n// for all scales. Run the lines below individually with the previous note sequence running.\nScale.root( \'d4\' )\nScale.mode( \'lydian\' )\n\nScale.root( \'c4\' )\nScale.mode( \'phrygian\' )\n\n// We can also sequence changes to the root / mode:\nScale.root.seq( [\'c2\',\'d2\',\'f2\',\'g2\'], 2 )\nScale.mode.seq( [\'lydian\', \'ionian\', \'locrian\'], 2 )\n\n// stop the scale sequencing\nScale.root[0].stop()\nScale.mode[0].stop()\nScale.root( \'c4\' )\n\n// We can also define our own scales using chromatic scale indices. Unfortunately, \n// microtuning with MIDI is very diffcult, so only the standard eleven notes of \n// Western harmony are supported. Scales can have arbtrary numbers of notes.\nScale.modes[ \'my mode\' ] = [ 0,1,2,3,5,6,10 ]\nScale.mode( \'my mode\' )\n\nScale.modes[ \'another mode\' ] = [0,1]\nScale.mode( \'another mode\' )\n\nScale.mode.seq( [\'my mode\', \'another mode\'], 4 )\n\n/******** chords **********/\n// Last but not least there are a few different ways to specify chords in gibberwocky.\n// First, clear the current scene using Ctrl+.\n\n// change the release time, scale mode, and root\ndevices[\'bass\'].release( 75 )\n\n// We can use note names:\ndevices[\'bass\'].chord( [\'c4\',\'eb4\',\'gb4\',\'a4\'] )\n\n// Or we can use scale indices:\ndevices[\'bass\'].chord( [0,2,4,5] )\n\n// sequence in two-dimensional array\ndevices[\'bass\'].chord.seq( [[0,2,4,5], [1,3,4,6]], 1 )\n\n// We can also use strings that identify common chord names.\ndevices[\'bass\'].chord( \'c4maj7\' )\ndevices[\'bass\'].chord( \'c#4sus7b9\' )\n\n\ndevices[\'bass\'].chord.seq( [\'c4dim7\', \'bb3maj7\', \'fb3aug7\'], 1 )\n\n// OK, that\'s harmony in a nutshell. Next learn a bit about patterns and\n// pattern manipulation in gibberwocky in tutorial #4.'), _defineProperty(_Examples, 'tutorial 4: patterns and pattern transformations', '/* gibberwocky.max - tutorial #4: Patterns and Transformations\n *\n * This tutorial covers the basics of using patterns in gibberwocky.max. It assumes you\n * know the basics of sequencing (tutorial #2), have the the gibberwocky help patch\n * loaded, and the Global Transport running.\n *\n * In tutorial #2 we briefly mentioned that sequences consist of values and timings. These\n * are both stored in Pattern objects in gibberwocky, and these patterns can be controlled\n * and manipulated in a variety of ways over time.\n */\n \n// Make sure the console is open in your sidebar to see the calls to Gibber.log()\n// Create a Pattern with some initial values.\nmyvalues = Pattern( 60,62,64,65 )\n\nGibber.log( myvalues() ) // 60\nGibber.log( myvalues() ) // 62\nGibber.log( myvalues() ) // 64\nGibber.log( myvalues() ) // 65\nGibber.log( myvalues() ) // back to 60...\n\n// sequence using this pattern:\ndevices[\'bass\'].midinote.seq( myvalues, 1/8 )\n\n// Everytime we pass values and timings to .seq(), it converts these into Pattern objects\n// (unless we\'re already passing a Pattern object(s)). Remember from tutorial #2 that\n// all of our sequences have an ID number, which defaults to 0. We can access these patterns\n// as follows:\n\ndevices[\'bass\'].midinote.seq( [62,74,38,50], [1/2,1/4] )\nGibber.log( devices[\'bass\'].midinote[0].values.toString() ) \nGibber.log( devices[\'bass\'].midinote[0].timings.toString() ) \n\n// Now that we can access them, we can apply transformations:\n\ndevices[\'bass\'].midinote[0].values.reverse()\ndevices[\'bass\'].midinote[0].values.transpose( 1 ) // add 1 to each value\ndevices[\'bass\'].midinote[0].values.scale( 1.5 ) // scale each value by .5\ndevices[\'bass\'].midinote[0].values.rotate( 1 ) // shift values to the right\ndevices[\'bass\'].midinote[0].values.rotate( -1 ) // shift values to the left\ndevices[\'bass\'].midinote[0].values.reset() // reset to initial values\n\n// We can sequence these transformations:\ndevices[\'bass\'].midinote[0].values.rotate.seq( 1,1 )\ndevices[\'bass\'].midinote[0].values.reverse.seq( 1, 2 )\ndevices[\'bass\'].midinote[0].values.transpose.seq( 1, 2 )\ndevices[\'bass\'].midinote[0].values.reset.seq( 1, 8 )\n\n// This enables us to quickly create variation over time. One more tutorial to go!\n// Learn more about creating synthesis graphs for modulation in tutorial #5.'), _defineProperty(_Examples, 'tutorial 5: modulating with gen~', '/* Gen is an extension for Max for Live for synthesizing audio/video signals.\nLFOs, ramps, stochastic signals... Gen can create a wide variety of modulation sources for\nexploration.\n\nWe\'ve seen that the first outlet of gibberwocky is used for messaging. The remaining outlets\nare used for signals created by Gen objects. You can determine the number of outlets\nusing the @signals property; for example, [gibberwocky @signals 4], as seen in the gibberwocky\nhelp patch, has four outputs for audio signals in addtion to its messaging output (for a total\nof 5).\n*/\n\n// Let\'s experiment! Create a [gibberwocky @signals 1] object and connect the rightmost outlet\n// to a [scope~]. We can send a simple ramp as follows:\nsignals[0]( phasor(1) )\n\n// This creates a sawtooth wave with a range of {0,1}. We can also do sine waves:\nsignals[0]( cycle(1) )\n\n// Note that the cycle ugen generates a full bandwidth audio signal with a range of {-1,1}\n// Often times we want to specify a center point (bias) for our sine oscillator, in addition to \n// a specific amplitude and frequency. The lfo() function provides a simpler syntax for doing this:\n\n// frequency, amplitude, bias\nmylfo = lfo( 2, .2, .7 )\n\nsignals[0]( mylfo )\n\n// We can also easily sequence parameters of our LFO XXX CURRENTLY BROKEN:\n\nmylfo.frequency.seq( [ .5,1,2,4 ], 2 )\n\n/* ... as well as sequence any other parameter in Live controlled by a genish.js graph. Although the lfo()\nugen provides named properties for controlling frequency, amplitude, and centroid, there is a more\ngeneric way to sequence any aspect of a gen~ ugen by using the index operator ( [] ). For example,\ncycle() contains a single inlet that controls its frequency, to sequence it we would use: */\n\nmycycle = cycle( .25 )\n\nmycycle[ 0 ].seq( [ .25, 1, 2 ], 1 )\n\nsignals[0]( add( .5, div( mycycle, 2 ) ) )\n\n/*For other ugens that have more than one argument (see the genish.js random tutorial for an example) we\nsimply indicate the appropriate index... for example, mysah[ 1 ] etc. For documentation on the types of\nugens that are available, see the gen~ reference: https://docs.cycling74.com/max7/vignettes/gen~_operators*/'), _defineProperty(_Examples, 'tutorial 6: randomness', '/* gibberwocky.max - tutorial #6: Randomness\n *\n * This tutorial covers the basics of using randomness in gibberwocky.max. \n * It assumes you\'ve done all the other tutorials (#4 might be OK to have skipped),\n * have the gibberwocky help patch loaded, DSP turned on in Max and the global\n * transport rnning.\n *\n * Randomness in gibberwocky can be used to both create random values for sequencing \n * as well as stochastic signals for modulation purposes.\n */\n \n// rndf() and rndi() are used to generate a single random float or integer\n// make sure you have the console tab in the gibberwocky sidebar\nlog( rndf() ) // outputs floats between 0-1\nlog( rndi() ) // outputs either 0 or 1\n\n// although 0 and 1 are the default min/max values, we can pass\n// arbitrary bounds:\n\nlog( rndf(-1,1) )\nlog( rndi(0,127) )\n\n// if we pass a third value, we can create multiple random numbers at once,\n// returned as an array.\n\nlog( rndf( 0,1,4 ) )\nlog( rndi( 0,127,3 ) )\n\n// so, if we wanted to sequence a random midinote to the \'bass\' device\n// in the gibberwocky help patcher, we could sequence a function as follows:\n\ndevices[\'bass\'].midinote.seq( ()=> rndi(0,127), 1/8 )\n\n// Whenever gibberwocky sees a function in a sequence, it calls that function\n// to generate a value or a timing. In practice this is common enough with\n// random numbers that gibberwocky has a shortcut for creating functions\n// that return a random value(s) in a particular range.\n// Simply capitalize the call to rndi or rndf (to Rndi / Rndf ).\n\nclear() // clear previous sequence\ndevices[\'bass\'].note.seq( Rndi(-14,-7), 1/8 )\n\n// And chords:\nclear()\ndevices[\'bass\'].chord.seq( Rndi(14,21,3), 1/8 )\n\n// In addition to creating functions outputting random numbers, we can\n// also randomly pick from the arrays used to initialize patterns.\n\n// randomly play open or closed hi-hat every 1/16th note\ndevices[\'drums\'].midinote.seq( [42,46].rnd(), 1/16 )\n\n// For timings, it\'s often important to ensure that patterns eventually align\n// themselves with a beat grid. For example, if we randomly choose a single 1/16th \n// note timing, then every subsequent note played will be offset from a 1/8th note\n// grid until a second 1/16th note is chosen. We can ensure that particular values\n// are repeated whenever they are selected to help with this problem.\n\n// play constant kick drum to hear how bass aligns with 1/4 grid\ndevices[\'drums\'].midinote.seq( 36, 1/4 )\n\n// whenever a 1/16th timing is used, use it twice in a row\ndevices[\'bass\'].note.seq( -14, [1/8,1/16].rnd( 1/16,2 ) )\n\n// whenever a 1/16th timing is used, use it twice in a row and\n// whenever a 1/12th timing is used, use it three times in a row\ndevices[\'bass\'].note.seq( -14, [1/8,1/16,1/12].rnd( 1/16,2,1/12,3 ) )\n\n// OK, that\'s the basics of using randomness in patterns. But we can also use\n// noise to create randomness in modulations.\n\n// here\'s noise() going out the second outlet of gibberwocky\nsignals[0]( noise() ) \n\n// we can scale the noise\nsignals[0]( mul( noise(), .5 ) ) \n\n// we can also use sample and hold (sah) to selectively sample a noise signal.\n// below, we sample noise whenever a separate noise signal crosses\n// a threshold of .99995\nsignals[0]( sah( noise(), noise(), .99995 ) ) \n\n// alternatively, randomly sample a sine wave\nsignals[0]( sah( cycle(2), noise(), .999 ) )\n\n// OK, that\'s it for randomness... use it wisely!'), _defineProperty(_Examples, 'using the Score() object', '// Scores are lists of functions with associated\n// relative time values. In the score below, the first function has\n// a time value of 0, which means it begins playing immediately. The\n// second has a value of 1, which means it beings playing one measure\n// after the previously executed function. The other funcions have\n// timestamps of two, which means they begins playing two measures after\n// the previously executed function. Scores have start(), stop(),\n// loop(), pause() and rewind() methods.\n\ns = Score([\n 0, ()=> devices[\'bass\'].note.seq( -14, 1/4 ),\n \n 1, ()=> devices[\'bass\'].note.seq( 0, Euclid(5,8) ),\n \n 2, ()=> {\n arp = Arp( [0,1,3,5], 3, \'updown2\' )\n devices[\'bass\'].note.seq( arp, 1/32 )\n },\n \n 2, ()=> arp.transpose( 1 ),\n \n 2, ()=> arp.shuffle()\n])\n\n// Scores can also be stopped automatically to await manual retriggering.\n\ns2 = Score([\n 0, ()=> devices[\'bass\'].note( 0 ),\n\n 1/2, ()=> devices[\'bass\'].note( 1 ),\n\n Score.wait, null,\n\n 0, ()=> devices[\'bass\'].note( 2 )\n])\n\n// restart playback\ns2.next()\n\n// CURRENTLY BROKEN\n/* The loop() method tells a score to... loop. An optional argument specifies\n * an amount of time to wait between the end of one loop and the start of the next.*/\n\ns3 = Score([\n 0, ()=> devices[\'bass\'].note.seq( 0, 1/4 ),\n 1, ()=> devices[\'bass\'].note.seq( [0,7], 1/8 ),\n 1, ()=> devices[\'bass\'].note.seq( [0, 7, 14], 1/12 )\n])\n\ns3.loop( 1 )\n\n'), _defineProperty(_Examples, 'using the Arp() object (arpeggiator)', '/*\n * This tutorial assumes familiarity with the material\n * covered in tutorials 2–4.\n *\n * The Arp() object creates wrapped Pattern objects (see tutorial\n * #4) that are simply functions playing arpeggios. However,\n * the pattern transformations available in gibberwocky open\n * up a great deal of flexiblity in manipulating these arpeggios.\n */\n\n// Make an arp: chord, number of octaves, mode.\nmyarp = Arp( [0,2,4,5], 4, \'updown\' )\n\n// other modes include \'up\' and \'down\'. XXX updown2 is broken :( \n\n// play arpeggiator with 1/16 notes\ndevices[\'bass\'].note.seq( myarp, 1/16 )\n\n// change root of Scale (see tutorial #3)\nScale.root( \'c2\' )\n\n// randomize arpeggiator\nmyarp.shuffle()\n\n// transpose arpeggiator over time\nmyarp.transpose.seq( 1,1 )\n\n// reset arpeggiator\nmyarp.reset()\n\n// stop arpeggiator\ndevices[\'bass\'].stop()\n\n// The Arp() object can also be used with MIDI note values instead of\n// gibberwocky\'s system of harmony. However, arp objects are designed\n// to work with calls to note() by default, accordingly, they tranpose\n// patterns by seven per octave (there are seven notes in a scale of one\n// octave). For MIDI notes, there are 12 values... we can specify this\n// as a fourth parameter to the Arp() constructor.\n\nmidiArp = Arp( [60,62,64,67,71], 4, \'down\', 12 )\n\ndevices[\'bass\'].midinote.seq( midiArp, 1/32 )\n\n// bring everything down an octace\nmidiArp.transpose( -12 )\n\n// change number of octaves\nmidiArp.octaves = 2\n'), _defineProperty(_Examples, 'using the Euclid() object (euclidean rhythms)', '/*\n * This tutorial assumes familiarty with the material\n * covered in tutorial #2. It will cover the basics of\n * working with Euclidean rhythms in gibberwocky.\n *\n * Euclidean rhythms are specifcations of rhythm using\n * a number of pulses allocated over a number of beats.\n * The algorithm attempts to distribute the pulses as\n * evenly as possible over all beats while maintaining\n * a grid. You can read a paper describing this here:\n *\n * http://archive.bridgesmathart.org/2005/bridges2005-47.pdf\n *\n * For example, consider the rhythm \'5,8\' where there\n * are 5 pulses over the span of eight notes while\n * maintaining a temporal grid. The algorithm distributes \n * these as follows: "x.xx.xx." where \'x\' represents a pulse\n * and \'.\' represents a rest. Below are a few other examples:\n *\n * 1,4 : x...\n * 2,3 : x.x\n * 2,5 : x.x..\n * 3,5 : x.x.x\n * 3,8 : x..x..x.\n * 4,9 : x.x.x.x..\n * 5,9 : x.x.x.x.x\n *\n * In gibberwocky, by default the number of beats chosen\n * also determines the time used by each beat; selecting\n * \'5,8\' means 5 pulses spread across 8 1/8 notes. However,\n * you can also specify a different temporal resolution for\n * the resulting pattern: \'5,8,1/16\' means 5 pulses spread\n * across 8 beats where each beat is a 1/16th note.\n *\n * You can specify Euclidean rhyhtms using the Euclid()\n * function, which returns a pattern (see tutorial #4);\n * in the example below I\'ve assigned this to the variable E.\n */\n\n// store for faster reference\nE = Euclid\n\ndevices[\'bass\'].duration( 10 )\n\n// 5 pulses spread over 8 eighth notes\ndevices[\'bass\'].midinote.seq( 60, E(5,8) )\n\n// 3 pulses spread over 8 sixteenth notes\ndevices[\'bass\'].midinote.seq( 48, E( 3, 8, 1/16 ), 1 )\n\n// a quick way of notating x.x.\ndevices[\'bass\'].midinote.seq( 36, E(2,4), 2 ) \n\n// because Euclid() generates Pattern objects (see tutorial #3)\n// we can transform the patterns it generates:\n\ndevices[\'bass\'].midinote[1].timings.rotate.seq( 1,1 )\n\n'), _defineProperty(_Examples, 'using the Steps() object (step-sequencer)', '/* Steps() creates a group of sequencer objects. Each\n * sequencer is responsible for playing a single note,\n * where the velocity of each note is determined by\n * a hexadecimal value (0-f), where f is the loudest note.\n * A value of \'.\' means that no MIDI note message is sent\n * with for that particular pattern element.\n *\n * The lengths of the patterns found in a Steps object can\n * differ. By default, the amount of time for each step in\n * a pattern equals 1 divided by the number of steps in the\n * pattern. In the example below, most patterns have sixteen\n * steps, so each step represents a sixteenth note. However,\n * the first two patterns (60 and 62) only have four steps, so\n * each is a quarter note. \n *\n * The individual patterns can be accessed using the note\n * numbers they are assigned to. So, given an instance with\n * the name \'a\' (as below), the pattern for note 60 can be\n * accessed at a[60]. Note that you have to access with brackets\n * as a.60 is not valid JavaScript.\n *\n * The second argument to Steps is the instrument to target. Note\n * that while the example below is designed to work with the\n * Analogue Drums device found in the gibberwocky help file,\n * that instrument is actually NOT velocity sensitive. \n */\n\nsteps = Steps({\n [36]: \'ffff\', \n [38]: \'.a.a\',\n [41]: \'........7.9.c..d\',\n [43]: \'..6..78..b......\',\n [45]: \'..c.f....f..f..3\', \n [42]: \'.e.a.a...e.a.e.a\', \n [46]: \'..............e.\',\n}, devices[\'drums\'] )\n\n// rotate one pattern (assigned to midinote 71)\n// in step sequencer every measure\nsteps[42].rotate.seq( 1,1 )\n\n// reverse all steps each measure\nsteps.reverse.seq( 1, 2 )'), _Examples); +}, _defineProperty(_Examples, 'tutorial 1: basic messaging', '/*\n * gibberwocky.live - tutorial #1: basic messaging\n *\n * This first intro will explain how to send\n * MIDI note messages and control device and track parameters.\n *\n * To start, makesure you open the gibberwocky.demo project and\n * have Live\'s transport running.\n*/\n\n// The demo gibberwocky project has three tracks: drums, bass, and ambient\n// piano. Let\'s start playing notes with the bass. The bass is located on the \n// second track, zero-indexed (start counting from zero).\nbass = tracks[1]\nbass.midinote( 60 ) // send middle C\n\n// Click on the \'lom\' tab (Live Object Model) in the sidebar on the right side\n// of the gibberwocky client. This lists all the parameters exposed for control\n// to gibberwocky. The bass track is listed under \'2-Muugy\' (Muggy is the name\n// of the bass preset). If you uncollapse this branch, you see that the track\n// contains a single Simpler device (all gibberwocky objects are ignored). Open\n// up that Simpler branch, and you see all the parameters that can be controlled.\n// If you drag and drop the \'Filter Freq\' parameter into the code editor, it\n// will insert the full path for that control into the editor. It should look\n// something like this:\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\']\n\n// This is the path to a function we can call to change the filter cutoff frequency,\n// like so:\n\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\'](.75)\ntracks[\'2-Muugy\'].midinote( 36 )\n\ntracks[\'2-Muugy\'].devices[\'Simpler\'][\'Filter Freq\'](.25)\ntracks[\'2-Muugy\'].midinote( 36 )\n\n// Note that we can shorten this in a number of ways. First, we can always refer\n// to tracks and devices by their array position. In this case, the track index is\n// 1 and the device index is 0 (remember, gibberwocky devices are ignored).\n\ntracks[1].devices[0][\'Filter Freq\']( .5 ) // same effect!\n\n// we can also use the shortcut we created earlier\nbass.devices[0][\'Filter Freq\']( .35 )\n\n// or...\nsimpler = tracks[1].devices[0]\nsimpler[\'Filter Freq\']( 1 )\n\n// Conveniently (well, in most cases) all parameters are measured from 0-1, so\n// you don\'t really have to worry about ranges.\n\n// In addition to controlling devices, we can also control parameters of each\n// track in Live, such as volume, panning, mute and solo. This includes\n// the return tracks and the master track as well.\n\ntracks[0].volume( 0 ) // effectively mute our drums track \nreturns[0].volume( 1 ) // increase our reverb volume\ntracks[0].sends[0]( 1 ) // send our drum track full-blast to our reverb\nmaster.volume( .5 ) // set the master volume\n\n// OK, that\'s some basics out of the way. Try the sequencing tutorial next!'), _defineProperty(_Examples, 'tutorial 2: basic sequencing', '/* gibberwocky.live - tutorial #2: basic sequencing\n *\n * This tutorial will provide an introdution to sequencing messages in gibberwocky. In\n * order for sequencing in gibberwocky.live to work, you must start the Global Transport\n * running in Live. We\'re also assuming you\'re running the gibberwocky.demo project for\n * this tutorial.\n */\n\n// In tutorial #1, we saw how we could send MIDI messages to specific tracks\n// in Live. We can easily sequence any of these methods by adding\n// a call to .seq(). For example:\n\n// send noteon message with a first value of 36\ntracks[1].midinote( 36 )\n\n// send same value every quarter note\ntracks[1].midinote.seq( 36, 1/4 )\n\n// You can stop all sequences in gibberwocky with the Ctrl+. keyboard shortcut\n// (Ctrl + period) or by executing the command clear(). \n// You can also stop all sequences on a specific track:\ntracks[1].stop()\n\n// Most sequences in gibberwocky contain values (36) and timings (1/4). To\n// sequence multiple values we simply pass an array:\ntracks[1].midinote.seq( [36,48,60], 1/4 )\n\n// ... and we can do the same thing with multiple timings:\ntracks[1].midinote.seq( [36,48,60], [1/4,1/8] )\n\n// We can also sequence our note velocities and durations.\nclear()\ntracks[1].midinote.seq( 48, 1/2 )\ntracks[1].velocity.seq( [16, 64, 127], 1/2 )\ntracks[1].duration.seq( [10, 100,500], 1/2 )\n\n// If you experimented with running multiple variations of the midinote \n// sequences you might have noticed that only one runs at a time. For example,\n// if you run these two lines:\n\nclear()\ntracks[1].midinote.seq( 72, 1/4 )\ntracks[1].midinote.seq( 48, 1/4 )\n\n// ...you\'ll notice only the second one actually triggers. By default, gibberwocky\n// will replace an existing sequence with a new one. To stop this, you can pass an ID number \n// as a third argument to calls to .seq(). In the examples of sequencing we\'ve seen so far,\n// no ID has been given, which means gibberwocky is assuming a default ID of 0 for each\n// sequence. When you launch a sequence on a channel that has the same ID as another running \n// sequence, the older sequence is stopped. If the sequences have different IDs they run \n// concurrently. Note this makes it really easy to create polyrhythms.\n\nclear()\ntracks[1].midinote.seq( 48, 1 ) // assumes ID of 0\ntracks[1].midinote.seq( 60, 1/2, 1 ) \ntracks[1].midinote.seq( 72, 1/3, 2 ) \ntracks[1].midinote.seq( 84, 1/7, 3 ) \n\n// We can also sequence calls to midichord. You might remember from the first tutorial\n// that we pass midichord an array of values, where each value represents one note. This\n// means we need to pass an array of arrays in order to move between different chords.\n\nclear()\ntracks[2].midichord.seq( [[60,64,68], [62,66,72]], 1/2 )\n\n// Even we\'re only sequencing a single chord, we still need to pass a 2D array. Of course,\n// specifying arrays of MIDI values is not necessarily an optimal representation for chords.\n// Move on to tutorial #3 to learn more about how to leverage music theory in gibberwocky.'), _defineProperty(_Examples, 'tutorial 3: harmony', '/* gibberwocky.live - tutorial #3: Harmony\n *\n * This tutorial covers the basics of using harmony in gibberwocky.live. It assumes you\n * know the basics of sequencing (tutorial #2) and are using the gibberwocky.demo project. \n *\n * In the previous tutorials we looked at using raw MIDI values to send messages. However,\n * using MIDI note numbers is not an ideal representation. gibberwocky includes knoweldge of\n * scales, chords, and note names to make musical sequencing easier and more flexible. In this\n * tutorial, instead of using track.midinote() and track.midichord() we\'ll be using \n * channel.note() and channel.chord(). These methods use gibberwocky\'s theory objects to\n * determine what MIDI notes are eventually outputted.\n */\n\n// In our previous tutorial, we sent out C in the fourth octave by using MIDI number 60:\nbass = tracks[1]\nbass.midinote( 60 )\n\n// We can also specify notes with calls to the note() method by passing a name and octave.\nbass.note( \'c4\' )\nbass.note( \'fb3\' )\n\nbass.note.seq( [\'c2\',\'e2\',\'g2\'], 1/8 )\n\n// remember, Ctrl+. (or clear()) stops all running sequences.\n\n// In gibberwocky, the default scale employed is C minor, starting in the fourth octave. \n// This means that if we pass 0 as a value to note(), C4 will also be played.\nbass.note( 0 )\n\n// sequence C minor scale, starting in the fourth octave:\nbass.note.seq( [0,1,2,3,4,5,6,7], 1/8 )\n\n// negative scale indices also work:\nbass..note.seq( [-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7], 1/8 )\n\n// there is a global Scale object we can use to change the root and mode\n// for all scales. Run the lines below individually with the previous note sequence running.\nScale.root( \'d4\' )\nScale.mode( \'lydian\' )\n\nScale.root( \'c4\' )\nScale.mode( \'phrygian\' )\n\n// We can also sequence changes to the root / mode:\nScale.root.seq( [\'c2\',\'d2\',\'f2\',\'g2\'], 2 )\nScale.mode.seq( [\'lydian\', \'ionian\', \'locrian\'], 2 )\n\n// stop the scale sequencing\nScale.root[0].stop()\nScale.mode[0].stop()\nScale.root( \'c4\' )\n\n// We can also define our own scales using chromatic scale indices. Unfortunately, \n// microtuning with MIDI is very diffcult, so only the standard eleven notes of \n// Western harmony are supported. Scales can have arbtrary numbers of notes.\nScale.modes[ \'my mode\' ] = [ 0,1,2,3,5,6,10 ]\nScale.mode( \'my mode\' )\n\nScale.modes[ \'another mode\' ] = [0,1]\nScale.mode( \'another mode\' )\n\nScale.mode.seq( [\'my mode\', \'another mode\'], 4 )\n\n/******** chords **********/\n// Last but not least there are a few different ways to specify chords in gibberwocky.\n// First, clear the current scene using Ctrl+.\n\npad = tracks[2]\n\n// We can use note names:\npad.chord( [\'c4\',\'eb4\',\'gb4\',\'a4\'] )\n\n// Or we can use scale indices:\npad.chord( [0,2,4,5] )\n\n// sequence in two-dimensional array\npad.chord.seq( [[0,2,4,5], [1,3,4,6]], 1 )\n\n// We can also use strings that identify common chord names.\npad.chord( \'c4maj7\' )\npad.chord( \'c#4sus7b9\' )\n\n\npad.chord.seq( [\'c4dim7\', \'bb3maj7\', \'fb3aug7\'], 2 )\n\n// OK, that\'s harmony in a nutshell. Next learn a bit about patterns and\n// pattern manipulation in gibberwocky in tutorial #4.'), _defineProperty(_Examples, 'tutorial 4: patterns and pattern transformations', '/* gibberwocky.max - tutorial #4: Patterns and Transformations\n *\n * This tutorial covers the basics of using patterns in gibberwocky.max. It assumes you\n * know the basics of sequencing (tutorial #2), have the the gibberwocky help patch\n * loaded, and the Global Transport running.\n *\n * In tutorial #2 we briefly mentioned that sequences consist of values and timings. These\n * are both stored in Pattern objects in gibberwocky, and these patterns can be controlled\n * and manipulated in a variety of ways over time.\n */\n \n// Make sure the console is open in your sidebar to see the calls to Gibber.log()\n// Create a Pattern with some initial values.\nmyvalues = Pattern( 60,62,64,65 )\n\nGibber.log( myvalues() ) // 60\nGibber.log( myvalues() ) // 62\nGibber.log( myvalues() ) // 64\nGibber.log( myvalues() ) // 65\nGibber.log( myvalues() ) // back to 60...\n\n// sequence using this pattern:\ndevices[\'bass\'].midinote.seq( myvalues, 1/8 )\n\n// Everytime we pass values and timings to .seq(), it converts these into Pattern objects\n// (unless we\'re already passing a Pattern object(s)). Remember from tutorial #2 that\n// all of our sequences have an ID number, which defaults to 0. We can access these patterns\n// as follows:\n\ndevices[\'bass\'].midinote.seq( [62,74,38,50], [1/2,1/4] )\nGibber.log( devices[\'bass\'].midinote[0].values.toString() ) \nGibber.log( devices[\'bass\'].midinote[0].timings.toString() ) \n\n// Now that we can access them, we can apply transformations:\n\ndevices[\'bass\'].midinote[0].values.reverse()\ndevices[\'bass\'].midinote[0].values.transpose( 1 ) // add 1 to each value\ndevices[\'bass\'].midinote[0].values.scale( 1.5 ) // scale each value by .5\ndevices[\'bass\'].midinote[0].values.rotate( 1 ) // shift values to the right\ndevices[\'bass\'].midinote[0].values.rotate( -1 ) // shift values to the left\ndevices[\'bass\'].midinote[0].values.reset() // reset to initial values\n\n// We can sequence these transformations:\ndevices[\'bass\'].midinote[0].values.rotate.seq( 1,1 )\ndevices[\'bass\'].midinote[0].values.reverse.seq( 1, 2 )\ndevices[\'bass\'].midinote[0].values.transpose.seq( 1, 2 )\ndevices[\'bass\'].midinote[0].values.reset.seq( 1, 8 )\n\n// This enables us to quickly create variation over time. One more tutorial to go!\n// Learn more about creating synthesis graphs for modulation in tutorial #5.'), _defineProperty(_Examples, 'tutorial 5: modulating with gen~', '/* Gen is an extension for Max for Live for synthesizing audio/video signals.\nLFOs, ramps, stochastic signals... Gen can create a wide variety of modulation sources for\nexploration.\n\nWe\'ve seen that the first outlet of gibberwocky is used for messaging. The remaining outlets\nare used for signals created by Gen objects. You can determine the number of outlets\nusing the @signals property; for example, [gibberwocky @signals 4], as seen in the gibberwocky\nhelp patch, has four outputs for audio signals in addtion to its messaging output (for a total\nof 5).\n*/\n\n// Let\'s experiment! Create a [gibberwocky @signals 1] object and connect the rightmost outlet\n// to a [scope~]. We can send a simple ramp as follows:\nsignals[0]( phasor(1) )\n\n// This creates a sawtooth wave with a range of {0,1}. We can also do sine waves:\nsignals[0]( cycle(1) )\n\n// Note that the cycle ugen generates a full bandwidth audio signal with a range of {-1,1}\n// Often times we want to specify a center point (bias) for our sine oscillator, in addition to \n// a specific amplitude and frequency. The lfo() function provides a simpler syntax for doing this:\n\n// frequency, amplitude, bias\nmylfo = lfo( 2, .2, .7 )\n\nsignals[0]( mylfo )\n\n// We can also easily sequence parameters of our LFO XXX CURRENTLY BROKEN:\n\nmylfo.frequency.seq( [ .5,1,2,4 ], 2 )\n\n/* ... as well as sequence any other parameter in Live controlled by a genish.js graph. Although the lfo()\nugen provides named properties for controlling frequency, amplitude, and centroid, there is a more\ngeneric way to sequence any aspect of a gen~ ugen by using the index operator ( [] ). For example,\ncycle() contains a single inlet that controls its frequency, to sequence it we would use: */\n\nmycycle = cycle( .25 )\n\nmycycle[ 0 ].seq( [ .25, 1, 2 ], 1 )\n\nsignals[0]( add( .5, div( mycycle, 2 ) ) )\n\n/*For other ugens that have more than one argument (see the genish.js random tutorial for an example) we\nsimply indicate the appropriate index... for example, mysah[ 1 ] etc. For documentation on the types of\nugens that are available, see the gen~ reference: https://docs.cycling74.com/max7/vignettes/gen~_operators*/'), _defineProperty(_Examples, 'tutorial 6: randomness', '/* gibberwocky.max - tutorial #6: Randomness\n *\n * This tutorial covers the basics of using randomness in gibberwocky.max. \n * It assumes you\'ve done all the other tutorials (#4 might be OK to have skipped),\n * have the gibberwocky help patch loaded, DSP turned on in Max and the global\n * transport rnning.\n *\n * Randomness in gibberwocky can be used to both create random values for sequencing \n * as well as stochastic signals for modulation purposes.\n */\n \n// rndf() and rndi() are used to generate a single random float or integer\n// make sure you have the console tab in the gibberwocky sidebar\nlog( rndf() ) // outputs floats between 0-1\nlog( rndi() ) // outputs either 0 or 1\n\n// although 0 and 1 are the default min/max values, we can pass\n// arbitrary bounds:\n\nlog( rndf(-1,1) )\nlog( rndi(0,127) )\n\n// if we pass a third value, we can create multiple random numbers at once,\n// returned as an array.\n\nlog( rndf( 0,1,4 ) )\nlog( rndi( 0,127,3 ) )\n\n// so, if we wanted to sequence a random midinote to the \'bass\' device\n// in the gibberwocky help patcher, we could sequence a function as follows:\n\ndevices[\'bass\'].midinote.seq( ()=> rndi(0,127), 1/8 )\n\n// Whenever gibberwocky sees a function in a sequence, it calls that function\n// to generate a value or a timing. In practice this is common enough with\n// random numbers that gibberwocky has a shortcut for creating functions\n// that return a random value(s) in a particular range.\n// Simply capitalize the call to rndi or rndf (to Rndi / Rndf ).\n\nclear() // clear previous sequence\ndevices[\'bass\'].note.seq( Rndi(-14,-7), 1/8 )\n\n// And chords:\nclear()\ndevices[\'bass\'].chord.seq( Rndi(14,21,3), 1/8 )\n\n// In addition to creating functions outputting random numbers, we can\n// also randomly pick from the arrays used to initialize patterns.\n\n// randomly play open or closed hi-hat every 1/16th note\ndevices[\'drums\'].midinote.seq( [42,46].rnd(), 1/16 )\n\n// For timings, it\'s often important to ensure that patterns eventually align\n// themselves with a beat grid. For example, if we randomly choose a single 1/16th \n// note timing, then every subsequent note played will be offset from a 1/8th note\n// grid until a second 1/16th note is chosen. We can ensure that particular values\n// are repeated whenever they are selected to help with this problem.\n\n// play constant kick drum to hear how bass aligns with 1/4 grid\ndevices[\'drums\'].midinote.seq( 36, 1/4 )\n\n// whenever a 1/16th timing is used, use it twice in a row\ndevices[\'bass\'].note.seq( -14, [1/8,1/16].rnd( 1/16,2 ) )\n\n// whenever a 1/16th timing is used, use it twice in a row and\n// whenever a 1/12th timing is used, use it three times in a row\ndevices[\'bass\'].note.seq( -14, [1/8,1/16,1/12].rnd( 1/16,2,1/12,3 ) )\n\n// OK, that\'s the basics of using randomness in patterns. But we can also use\n// noise to create randomness in modulations.\n\n// here\'s noise() going out the second outlet of gibberwocky\nsignals[0]( noise() ) \n\n// we can scale the noise\nsignals[0]( mul( noise(), .5 ) ) \n\n// we can also use sample and hold (sah) to selectively sample a noise signal.\n// below, we sample noise whenever a separate noise signal crosses\n// a threshold of .99995\nsignals[0]( sah( noise(), noise(), .99995 ) ) \n\n// alternatively, randomly sample a sine wave\nsignals[0]( sah( cycle(2), noise(), .999 ) )\n\n// OK, that\'s it for randomness... use it wisely!'), _defineProperty(_Examples, 'using the Score() object', '// Scores are lists of functions with associated\n// relative time values. In the score below, the first function has\n// a time value of 0, which means it begins playing immediately. The\n// second has a value of 1, which means it beings playing one measure\n// after the previously executed function. The other funcions have\n// timestamps of two, which means they begins playing two measures after\n// the previously executed function. Scores have start(), stop(),\n// loop(), pause() and rewind() methods.\n\ns = Score([\n 0, ()=> devices[\'bass\'].note.seq( -14, 1/4 ),\n \n 1, ()=> devices[\'bass\'].note.seq( 0, Euclid(5,8) ),\n \n 2, ()=> {\n arp = Arp( [0,1,3,5], 3, \'updown2\' )\n devices[\'bass\'].note.seq( arp, 1/32 )\n },\n \n 2, ()=> arp.transpose( 1 ),\n \n 2, ()=> arp.shuffle()\n])\n\n// Scores can also be stopped automatically to await manual retriggering.\n\ns2 = Score([\n 0, ()=> devices[\'bass\'].note( 0 ),\n\n 1/2, ()=> devices[\'bass\'].note( 1 ),\n\n Score.wait, null,\n\n 0, ()=> devices[\'bass\'].note( 2 )\n])\n\n// restart playback\ns2.next()\n\n// CURRENTLY BROKEN\n/* The loop() method tells a score to... loop. An optional argument specifies\n * an amount of time to wait between the end of one loop and the start of the next.*/\n\ns3 = Score([\n 0, ()=> devices[\'bass\'].note.seq( 0, 1/4 ),\n 1, ()=> devices[\'bass\'].note.seq( [0,7], 1/8 ),\n 1, ()=> devices[\'bass\'].note.seq( [0, 7, 14], 1/12 )\n])\n\ns3.loop( 1 )\n\n'), _defineProperty(_Examples, 'using the Arp() object (arpeggiator)', '/*\n * This tutorial assumes familiarity with the material\n * covered in tutorials 2–4.\n *\n * The Arp() object creates wrapped Pattern objects (see tutorial\n * #4) that are simply functions playing arpeggios. However,\n * the pattern transformations available in gibberwocky open\n * up a great deal of flexiblity in manipulating these arpeggios.\n */\n\n// Make an arp: chord, number of octaves, mode.\nmyarp = Arp( [0,2,4,5], 4, \'updown\' )\n\n// other modes include \'up\' and \'down\'. XXX updown2 is broken :( \n\n// play arpeggiator with 1/16 notes\ndevices[\'bass\'].note.seq( myarp, 1/16 )\n\n// change root of Scale (see tutorial #3)\nScale.root( \'c2\' )\n\n// randomize arpeggiator\nmyarp.shuffle()\n\n// transpose arpeggiator over time\nmyarp.transpose.seq( 1,1 )\n\n// reset arpeggiator\nmyarp.reset()\n\n// stop arpeggiator\ndevices[\'bass\'].stop()\n\n// The Arp() object can also be used with MIDI note values instead of\n// gibberwocky\'s system of harmony. However, arp objects are designed\n// to work with calls to note() by default, accordingly, they tranpose\n// patterns by seven per octave (there are seven notes in a scale of one\n// octave). For MIDI notes, there are 12 values... we can specify this\n// as a fourth parameter to the Arp() constructor.\n\nmidiArp = Arp( [60,62,64,67,71], 4, \'down\', 12 )\n\ndevices[\'bass\'].midinote.seq( midiArp, 1/32 )\n\n// bring everything down an octace\nmidiArp.transpose( -12 )\n\n// change number of octaves\nmidiArp.octaves = 2\n'), _defineProperty(_Examples, 'using the Euclid() object (euclidean rhythms)', '/*\n * This tutorial assumes familiarty with the material\n * covered in tutorial #2. It will cover the basics of\n * working with Euclidean rhythms in gibberwocky.\n *\n * Euclidean rhythms are specifcations of rhythm using\n * a number of pulses allocated over a number of beats.\n * The algorithm attempts to distribute the pulses as\n * evenly as possible over all beats while maintaining\n * a grid. You can read a paper describing this here:\n *\n * http://archive.bridgesmathart.org/2005/bridges2005-47.pdf\n *\n * For example, consider the rhythm \'5,8\' where there\n * are 5 pulses over the span of eight notes while\n * maintaining a temporal grid. The algorithm distributes \n * these as follows: "x.xx.xx." where \'x\' represents a pulse\n * and \'.\' represents a rest. Below are a few other examples:\n *\n * 1,4 : x...\n * 2,3 : x.x\n * 2,5 : x.x..\n * 3,5 : x.x.x\n * 3,8 : x..x..x.\n * 4,9 : x.x.x.x..\n * 5,9 : x.x.x.x.x\n *\n * In gibberwocky, by default the number of beats chosen\n * also determines the time used by each beat; selecting\n * \'5,8\' means 5 pulses spread across 8 1/8 notes. However,\n * you can also specify a different temporal resolution for\n * the resulting pattern: \'5,8,1/16\' means 5 pulses spread\n * across 8 beats where each beat is a 1/16th note.\n *\n * You can specify Euclidean rhyhtms using the Euclid()\n * function, which returns a pattern (see tutorial #4);\n * in the example below I\'ve assigned this to the variable E.\n */\n\n// store for faster reference\nE = Euclid\n\ndevices[\'bass\'].duration( 10 )\n\n// 5 pulses spread over 8 eighth notes\ndevices[\'bass\'].midinote.seq( 60, E(5,8) )\n\n// 3 pulses spread over 8 sixteenth notes\ndevices[\'bass\'].midinote.seq( 48, E( 3, 8, 1/16 ), 1 )\n\n// a quick way of notating x.x.\ndevices[\'bass\'].midinote.seq( 36, E(2,4), 2 ) \n\n// because Euclid() generates Pattern objects (see tutorial #3)\n// we can transform the patterns it generates:\n\ndevices[\'bass\'].midinote[1].timings.rotate.seq( 1,1 )\n\n'), _defineProperty(_Examples, 'using the Steps() object (step-sequencer)', '/* Steps() creates a group of sequencer objects. Each\n * sequencer is responsible for playing a single note,\n * where the velocity of each note is determined by\n * a hexadecimal value (0-f), where f is the loudest note.\n * A value of \'.\' means that no MIDI note message is sent\n * with for that particular pattern element.\n *\n * The lengths of the patterns found in a Steps object can\n * differ. By default, the amount of time for each step in\n * a pattern equals 1 divided by the number of steps in the\n * pattern. In the example below, most patterns have sixteen\n * steps, so each step represents a sixteenth note. However,\n * the first two patterns (60 and 62) only have four steps, so\n * each is a quarter note. \n *\n * The individual patterns can be accessed using the note\n * numbers they are assigned to. So, given an instance with\n * the name \'a\' (as below), the pattern for note 60 can be\n * accessed at a[60]. Note that you have to access with brackets\n * as a.60 is not valid JavaScript.\n *\n * The second argument to Steps is the instrument to target. Note\n * that while the example below is designed to work with the\n * Analogue Drums device found in the gibberwocky help file,\n * that instrument is actually NOT velocity sensitive. \n */\n\nsteps = Steps({\n [36]: \'ffff\', \n [38]: \'.a.a\',\n [41]: \'........7.9.c..d\',\n [43]: \'..6..78..b......\',\n [45]: \'..c.f....f..f..3\', \n [42]: \'.e.a.a...e.a.e.a\', \n [46]: \'..............e.\',\n}, devices[\'drums\'] )\n\n// rotate one pattern (assigned to midinote 71)\n// in step sequencer every measure\nsteps[42].rotate.seq( 1,1 )\n\n// reverse all steps each measure\nsteps.reverse.seq( 1, 2 )'), _Examples); module.exports = Examples; },{}],9:[function(require,module,exports){ @@ -3513,6 +3513,7 @@ window.Arp = this.Arp; window.Communication = this.Communication; window.log = this.log; + window.clear = this.clear; window.Theory = this.Theory; window.Scale = this.Theory.Scale.master; diff --git a/js/example.js b/js/example.js index 1022fa3..66ba2e3 100644 --- a/js/example.js +++ b/js/example.js @@ -142,6 +142,7 @@ tracks[1].midinote.seq( [36,48,60], 1/4 ) tracks[1].midinote.seq( [36,48,60], [1/4,1/8] ) // We can also sequence our note velocities and durations. +clear() tracks[1].midinote.seq( 48, 1/2 ) tracks[1].velocity.seq( [16, 64, 127], 1/2 ) tracks[1].duration.seq( [10, 100,500], 1/2 ) @@ -150,6 +151,7 @@ tracks[1].duration.seq( [10, 100,500], 1/2 ) // sequences you might have noticed that only one runs at a time. For example, // if you run these two lines: +clear() tracks[1].midinote.seq( 72, 1/4 ) tracks[1].midinote.seq( 48, 1/4 ) @@ -161,6 +163,7 @@ tracks[1].midinote.seq( 48, 1/4 ) // sequence, the older sequence is stopped. If the sequences have different IDs they run // concurrently. Note this makes it really easy to create polyrhythms. +clear() tracks[1].midinote.seq( 48, 1 ) // assumes ID of 0 tracks[1].midinote.seq( 60, 1/2, 1 ) tracks[1].midinote.seq( 72, 1/3, 2 ) @@ -177,40 +180,40 @@ tracks[2].midichord.seq( [[60,64,68], [62,66,72]], 1/2 ) // specifying arrays of MIDI values is not necessarily an optimal representation for chords. // Move on to tutorial #3 to learn more about how to leverage music theory in gibberwocky.`, -['tutorial 3: harmony'] :`/* gibberwocky.max - tutorial #3: Harmony +['tutorial 3: harmony'] :`/* gibberwocky.live - tutorial #3: Harmony * - * This tutorial covers the basics of using harmony in gibberwocky.midi. It assumes you - * know the basics of sequencing (tutorial #2) and have an appropriate MIDI output setup. - * It also assumes you have the gibberwocky help patch open and the transport running. + * This tutorial covers the basics of using harmony in gibberwocky.live. It assumes you + * know the basics of sequencing (tutorial #2) and are using the gibberwocky.demo project. * * In the previous tutorials we looked at using raw MIDI values to send messages. However, * using MIDI note numbers is not an ideal representation. gibberwocky includes knoweldge of * scales, chords, and note names to make musical sequencing easier and more flexible. In this - * tutorial, instead of using channel.midinote() and channel.midichord() we'll be using + * tutorial, instead of using track.midinote() and track.midichord() we'll be using * channel.note() and channel.chord(). These methods use gibberwocky's theory objects to * determine what MIDI notes are eventually outputted. */ // In our previous tutorial, we sent out C in the fourth octave by using MIDI number 60: -devices['bass'].midinote( 60 ) +bass = tracks[1] +bass.midinote( 60 ) // We can also specify notes with calls to the note() method by passing a name and octave. -devices['bass'].note( 'c4' ) -devices['bass'].note( 'fb3' ) +bass.note( 'c4' ) +bass.note( 'fb3' ) -devices['bass'].note.seq( ['c4','e4','g4'], 1/8 ) +bass.note.seq( ['c2','e2','g2'], 1/8 ) -// remember, Ctrl+. stops all running sequences. +// remember, Ctrl+. (or clear()) stops all running sequences. // In gibberwocky, the default scale employed is C minor, starting in the fourth octave. // This means that if we pass 0 as a value to note(), C4 will also be played. -devices['bass'].note( 0 ) +bass.note( 0 ) // sequence C minor scale, starting in the fourth octave: -devices['bass'].note.seq( [0,1,2,3,4,5,6,7], 1/8 ) +bass.note.seq( [0,1,2,3,4,5,6,7], 1/8 ) // negative scale indices also work: -devices['bass'].note.seq( [-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7], 1/8 ) +bass.note.seq( [-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7], 1/8 ) // there is a global Scale object we can use to change the root and mode // for all scales. Run the lines below individually with the previous note sequence running. @@ -244,24 +247,23 @@ Scale.mode.seq( ['my mode', 'another mode'], 4 ) // Last but not least there are a few different ways to specify chords in gibberwocky. // First, clear the current scene using Ctrl+. -// change the release time, scale mode, and root -devices['bass'].release( 75 ) +pad = tracks[2] // We can use note names: -devices['bass'].chord( ['c4','eb4','gb4','a4'] ) +pad.chord( ['c4','eb4','gb4','a4'] ) // Or we can use scale indices: -devices['bass'].chord( [0,2,4,5] ) +pad.chord( [0,2,4,5] ) // sequence in two-dimensional array -devices['bass'].chord.seq( [[0,2,4,5], [1,3,4,6]], 1 ) +pad.chord.seq( [[0,2,4,5], [1,3,4,6]], 1 ) // We can also use strings that identify common chord names. -devices['bass'].chord( 'c4maj7' ) -devices['bass'].chord( 'c#4sus7b9' ) +pad.chord( 'c4maj7' ) +pad.chord( 'c#4sus7b9' ) -devices['bass'].chord.seq( ['c4dim7', 'bb3maj7', 'fb3aug7'], 1 ) +pad.chord.seq( ['c4dim7', 'bb3maj7', 'fb3aug7'], 2 ) // OK, that's harmony in a nutshell. Next learn a bit about patterns and // pattern manipulation in gibberwocky in tutorial #4.`, diff --git a/js/gibber.js b/js/gibber.js index bfc28d2..50c407c 100644 --- a/js/gibber.js +++ b/js/gibber.js @@ -29,6 +29,7 @@ let Gibber = { window.Arp = this.Arp window.Communication = this.Communication window.log = this.log + window.clear = this.clear window.Theory = this.Theory window.Scale = this.Theory.Scale.master