Rengga Dev – Math.random()
is an API in JavaScript. It is a function that gives you a random number. The number returned will be between 0 (inclusive, as in, it’s possible for an actual 0 to be returned) and 1 (exclusive, as in, it’s not possible for an actual 1 to be returned).
# generate a package of chances and values based on an object containing multiple possible zero values ChancePkg = (vals) -> # generating vals and their chances of occuring new_vals = [] # get total number of vals vals_count = 0 for value of vals if vals.hasOwnProperty(value) && vals[value] > 0 vals_count += vals[value] new_vals.push [value, vals[value]] # go through new vals and generate chance for each value new_vals_chances = [] total = 0 for val, i in new_vals # relative amount for random selection amount = total + ( (val[1] / vals_count ) * 100000) # push amount into chances array new_vals_chances.push amount # set value to be the value, no longer an array of data new_vals[i] = parseInt(val[0]) # increase base total total = amount # return package which has array for both non-zero vals and their corrosponding chance return {chances: new_vals_chances, vals: new_vals} # get the sound to silence ratio at the smallest scale getSoundRatio = (measures, beats, values) -> # generating vals and their chances of occuring new_values = [] # get total number of vals values_count = 0 for value of values if values.hasOwnProperty(value) && values[value] > 0 values_count += values[value] new_values.push [value, values[value]] # resolution is the smallest sized note resolution = (beats * (new_values[new_values.length - 1][1] / 4)) # possible is how many resolution sized notes are in the piece possible = measures * (beats * (resolution / 4)) # usage to be used in the loop usage = 0 for value in new_values # how many resolution values are in a single value? (ie. how many sixteenth notes are in a quarter note) res_value = (1 / value[0]) * resolution # use resolution value * occurances usage += res_value * value[1] return usage / possible # generate clef values based on data Piece = (piece) -> {measures, beats, treble_clef, bass_clef, composition} = piece this.treble_clef = { # sound ratio is the presence of sound divided by the presenece of silence in the analyzed piece sound_ratio: getSoundRatio(measures, beats, treble_clef.values) # value package has array for both non-zero values and their corrosponding chance values_pkg: new ChancePkg(treble_clef.values) # interval package has array for both non-zero intervals and their corrosponding chance intervals_pkg: new ChancePkg(treble_clef.intervals) # octaves package has array for both non-zero octaves and their corrosponding chance octaves_pkg: new ChancePkg(treble_clef.octaves) # chords package has array for both non-zero chords and their corrosponding chance chords_pkg: new ChancePkg(treble_clef.chords) # setting the base octave base_octave: 5 # tone wave: 'sine' # gain gain: 0.3 } this.bass_clef = { # sound ratio is the presence of sound divided by the presenece of silence in the analyzed piece sound_ratio: getSoundRatio(measures, beats, bass_clef.values) # value package has array for both non-zero values and their corrosponding chance values_pkg: new ChancePkg(bass_clef.values) # interval package has array for both non-zero intervals and their corrosponding chance intervals_pkg: new ChancePkg(bass_clef.intervals) # octaves package has array for both non-zero octaves and their corrosponding chance octaves_pkg: new ChancePkg(bass_clef.octaves) # chords package has array for both non-zero chords and their corrosponding chance chords_pkg: new ChancePkg(bass_clef.chords) # setting the base octave base_octave: 3 # tone wave: 'sine' # gain gain: 0.3 } this.composition = composition return # initiate audio context audio_context = undefined (init = (g) -> try # "crossbrowser" audio context. audio_context = new (g.AudioContext or g.webkitAudioContext) catch e console.log "No web audio oscillator support in this browser" return ) window # oscillator prototype Oscillator = (tone) -> max_gain = tone.gain this.tone = tone this.play = () -> # capturing current time for play start and stop current_time = audio_context.currentTime # create oscillator o = audio_context.createOscillator() # create gain gn = audio_context.createGain() # set waveform o.type = this.tone.wave # set frequency if this.tone.frequency o.frequency.value = this.tone.frequency # connect oscillator to gain o.connect gn # connect gain to output gn.connect audio_context.destination # set gain amount gn.gain.value = (max_gain / this.tone.vol) / 1 # play it o.start(current_time) # stop after sustain o.stop(current_time + this.tone.sustain) return this # note frequencies array of octave arrays that start on c (our root note) freqs = [ [16.351, 17.324, 18.354, 19.445, 20.601, 21.827, 23.124, 24.499, 25.956, 27.5, 29.135, 30.868] [32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735] [65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471] [130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942] [261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883] [523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767] [1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533] [2093.005, 2217.461, 2349.318, 2489.016, 2637.021, 2793.826, 2959.955, 3135.964, 3322.438, 3520, 3729.31, 3951.066] [4186.009, 4434.922, 4698.636, 4978.032, 5274.042, 5587.652, 5919.91, 6271.928, 6644.876, 7040, 7458.62, 7902.132] [8372.018, 8869.844, 9397.272, 9956.064, 10548.084, 11175.304, 11839.82, 12543.856, 13289.752, 14080, 14917.24, 15804.264] ] # get random val from chance package randomVal = (chance_pkg) -> random = Math.random() * 100000 for chance, i in chance_pkg.chances return chance_pkg.vals[i] if random < chance return # get sequence function getSequence = (clef, composition) -> # get the duration in smallest resolution amount duration = composition.measures * (composition.beats * (composition.resolution / 4)) # note sequence sequence = [] # while there is still duration while duration > 0 # random hit random = Math.random() # if a hit if random < clef.sound_ratio # random chord note count chord = randomVal(clef.chords_pkg) # random length for the chord value = randomVal(clef.values_pkg) # if there isnt enough space if ((1 / value) / (1 / composition.resolution)) >= duration # make it the length of remaining value = ((1 / duration) / (1 / composition.resolution)) # the new chord new_chord = {length: (1 / value), notes: []} # for each note in the chord for note in [1..chord] # get a random interval interval = randomVal(clef.intervals_pkg) # get the random octave octave = randomVal(clef.octaves_pkg) # make intervale relative to key interval += composition.root # if key pushes interval into new octave if interval > 12 interval -= 12 # make the octave relative to the clef's octave new_octave = clef.base_octave + ((2 - octave) * -1) # the frequency of the note note = freqs[new_octave - 1][interval] # if note doesnt already exist in chord if new_chord.notes.indexOf(note) == -1 # push the frequency into the chord's notes new_chord.notes.push {freq: note, int: interval, octave: octave} else # duplicate note in chord, ignoring it for now. console.log 'duplicate note in chord, ignoring it for now.' # push the chord into the sequence sequence.push new_chord # get values resolution-relative value res_value = Math.floor((1 / value) / (1 / composition.resolution)) # if we need to add sustain notes if res_value > 1 # add blank values for blank in [1..res_value - 1] sequence.push 'sus' # subtract from the duration duration -= res_value else # it was a miss, add a zero to the sequence sequence.push 0 # subtract tick from duration duration-- return sequence Note = (tone) -> this.osc = () -> return new Oscillator(tone) return ### # data (to be derived from an analyzed piece of music) ### piece = { # piece data (auld lang syne) measures: 16 # measures in analyzed piece beats: 4 # beats per measure in analyzed piece # all our analysis will be relative to each clef treble_clef: { # note values are the duration of the note / chord. # this is a map of how many times each value appears in the analyzed data values: { 1: 0 # whole 1.5: 4 # dotted half 2: 5 # half 3: 12 # dotted quarter 4: 28 # quarter 6: 0 # dotted eighth 8: 12 # eighth 12: 0 # dotted sixteenth 16: 0 # sixteenth 32: 0 # thirty-second } # relative to the key, the intervals are steps between notes and the root (no octaves) # this includes all single notes and instances of a note in a chord # this is a map of how many times each interval appears in the analyzed data intervals: { 0: 32 # root / perfect unison (F) 1: 0 # minor second (F#) 2: 9 # major second (G) 3: 0 # minor third (G#) 4: 13 # major third (A) 5: 0 # perfect fourth (A#) 6: 6 # tritone (B) 7: 13 # perfect fifth (C) 8: 0 # minor sixth (C#) 9: 15 # major sixth (D) 10: 0 # minor seventh (D#) 11: 12 # major seventh (E) } # octaves are how many times a note appears in each octave (relative to the key) octaves: { 1: 37 # clef - 1 2: 67 # clef 3: 1 # clef + 1 } # instead of using proper chords (dyad, triad, 7th, 9th, and 11th), we only analyze how many notes are in the chord # this is a map of how many times each chord size appears in the analyzed data chords: { 1: 9 # 1 note 2: 47 # 2 notes 3: 0 # 3 notes 4: 0 # 4 notes 5: 0 # 5 notes } } bass_clef: { # note values are the duration of the note / chord. # this is a map of how many times each value appears in the analyzed data values: { 1: 0 # whole 1.5: 4 # dotted half 2: 5 # half 3: 12 # dotted quarter 4: 28 # quarter 6: 0 # dotted eighth 8: 12 # eighth 12: 0 # dotted sixteenth 16: 0 # sixteenth 32: 0 # thirty-second } # relative to the key, the intervals are steps between notes and the root (no octaves) # this includes all single notes and instances of a note in a chord # this is a map of how many times each interval appears in the analyzed data intervals: { 0: 25 # root / perfect unison (F) 1: 0 # minor second (F#) 2: 1 # major second (G) 3: 0 # minor third (G#) 4: 17 # major third (A) 5: 2 # perfect fourth (A#) 6: 0 # tritone (B) 7: 38 # perfect fifth (C) 8: 1 # minor sixth (C#) 9: 4 # major sixth (D) 10: 0 # minor seventh (D#) 11: 2 # major seventh (E) } # octaves are how many times a note appears in each octave (relative to the key) octaves: { 1: 2 # clef - 1 2: 53 # clef 3: 50 # clef + 1 } # instead of using proper chords (dyad, triad, 7th, 9th, and 11th), we only analyze how many notes are in the chord # this is a map of how many times each chord size appears in the analyzed data chords: { 1: 9 # 1 note 2: 46 # 2 notes 3: 0 # 3 notes 4: 0 # 4 notes 5: 0 # 5 notes } } # defining the desired output composition data composition: { measures: 32 # bars to generate beats: 4 # beats per measure tempo: 120 # tempo resolution: 16 # resolution scale of piece root: 5 # root of key (0-11), 0 is 'C' } } # lets analyze our piece data! p = new Piece(piece) # sequence stores trebleSequence = undefined bassSequence = undefined # get sequences getSequences = () -> # creating our treble clef trebleSequence = getSequence(p.treble_clef, p.composition) bassSequence = getSequence(p.bass_clef, p.composition) draw_sequences() getSequenceHtml = (name, composition, sequence) -> $seq_html = $('<div class="' + name + ' clef"></div>') beats = composition.measures * (composition.beats * (composition.resolution / 4)) width_increment = 1 / beats * 100 left = 0 for chord in sequence if typeof chord == "object" width = width_increment * (chord.length / (1 / composition.resolution)) width = width_increment classname = 'chord value-' + Math.round( (1 / chord.length) * 100) / 100 classname = classname.replace('.', '-') notes = '' for note in chord.notes out_of_36 = 36 - (note.int + ((note.octave - 1) * 12)) notes += '<span class="note note-' + out_of_36 + '"></span>' else if chord == 'sus' classname = 'sus' width = width_increment notes = '' else width = width_increment classname = 'blank' notes = '' $seq_html.append '<span class="beat ' + classname + '" style="width: ' + width + '%; left: ' + left + '%">' + notes + '</span>' left += width return $seq_html draw_sequences = () -> composition = p.composition $staffs = $('<div class="staffs-wrapper"></div>') $staffs.append getSequenceHtml('treble', composition, trebleSequence) $staffs.append getSequenceHtml('bass', composition, bassSequence) $('#staff').html $staffs return performance_interval = undefined # play sequences playSequences = () -> composition = p.composition sequences = [trebleSequence, bassSequence] waves = [p.treble_clef.wave, p.bass_clef.wave] gains = [p.treble_clef.gain, p.bass_clef.gain] # total beat count beats = composition.measures * (composition.beats * (composition.resolution / 4)) # css width of beat beat_width = 100 / beats # relative index index = 0 # tempo to ms tempo_time = 60000 / composition.tempo # single beat instance next_beat = () -> for sequence, i in sequences chord = sequence[index] # if beat in any rhythm array has value if typeof chord == "object" # beats per second bps = composition.tempo / 60 # how much of a beat is the length beat_count = chord.length / 0.25 # sustain of the note in seconds chord_length_secs = beat_count * bps / 2 sustain = (chord_length_secs / bps) - 0.1 for note in chord.notes # new note n = new Note({frequency: note.freq, sustain: sustain, wave: waves[i], gain: gains[i], vol: chord.notes.length}) # new oscillator o = n.osc() # play oscillator o.play() if i == 0 then clef = 'treble' else clef = 'bass' if typeof chord == "object" $('.' + clef + ' .beat.active').removeClass 'active' $('.' + clef + ' .beat.go').removeClass clef + '-go' $('.' + clef + ' .beat:nth-child(' + (index + 1) + ')').addClass clef + '-go' else if chord != 'sus' $('.' + clef + ' .beat.active').removeClass 'active' $('.' + clef + ' .beat.go').removeClass clef + '-go' $('.beat:nth-child(' + (index + 1) + ')').addClass 'active' # update index index = (index + 1) % beats # first call of next beat next_beat() # ms to relative speed (based on resolution) time = tempo_time / (composition.resolution / 4) # set interval for next beat to occur at approriate time performance_interval = window.setInterval(next_beat, time) # stop button stopSequences = () -> window.clearInterval(performance_interval) # get sequences getSequences() playing = false play_handler = (p) -> if p == true playSequences() else stopSequences() playing = p $('#play').click () -> $(this).toggleClass 'playing' $('body').toggleClass 'playing' $('#new').toggleClass 'inactive' play_handler(!playing) $('#new').click () -> getSequences()
This program takes the traditional melody of “Auld Lang Syne” and plays random notes from it in piano. A change package is created from the count data and a random number is generated to select a value. The octave is also randomly selected.