@@ -1,401 +1,91 @@
var height = 320 ; var width = 480 ;
chrome . app . window . minWidth = width ;
chrome . app . window . minHeight = height ;
chrome . app . window . maxWidth = width ;
chrome . app . window . maxHeight = height ;
var canvas = document . getElementById ( 'canvas' ) ;
var vc = canvas . getContext ( '2d' ) ;
var ac = new window . AudioContext ( ) ;
var sr = ac . samplerate ;
vc . lineWidth = 1 ; vc . font = "8px monospace" ;
function FBLACK ( ) { vc . fillStyle = 'rgb(0,0,0)' ; }
function FBLUE ( ) { vc . fillStyle = 'rgb(100,100,192)' ; }
function SBLACK ( ) { vc . strokeStyle = 'rgb(0,0,0)' ; }
function SBLUE ( ) { vc . strokeStyle = 'rgb(100,100,192)' ; }
var OM = function ( ) {
//findtop
var anomaly = [ [ 0 , 0 ] , [ 0 , 0 ] , [ 0 , 0 ] , [ 0 , 0 ] , [ 0 , 0 ] ] ; //[type][song][buffer]
var identity = [ //[type][song][note,time,length]
[ //0 = DRUM BEAT (0-31)
[ //pattern 0 - kill over
[ 0 , 0 , 3 ] , [ 0 , 3 , 3 ] , [ 4 , 6 , 3 ] , [ 4 , 9 , 1 ] , [ 0 , 10 , 2 ] , [ 4 , 12 , 3 ] , [ 4 , 15 , 1 ] ,
[ 8 , 0 , 3 ] , [ 8 , 3 , 3 ] , [ 9 , 6 , 2 ] , [ 8 , 8 , 2 ] , [ 9 , 10 , 2 ] , [ 8 , 12 , 4 ] ,
[ 0 , 16 , 3 ] , [ 0 , 19 , 3 ] , [ 4 , 22 , 3 ] , [ 4 , 25 , 1 ] , [ 0 , 26 , 2 ] , [ 4 , 28 , 3 ] , [ 4 , 31 , 1 ] ,
[ 8 , 16 , 3 ] , [ 8 , 19 , 3 ] , [ 9 , 22 , 2 ] , [ 8 , 24 , 2 ] , [ 9 , 26 , 2 ] , [ 8 , 28 , 4 ]
] ,
[ //pattern 1 - serenity
[ 0 , 0 , 4 ] , [ 0 , 4 , 4 ] , [ 4 , 8 , 3 ] , [ 4 , 11 , 3 ] , [ 4 , 14 , 4 ] , [ 0 , 18 , 4 ] , [ 0 , 22 , 2 ] , [ 4 , 24 , 6 ] , [ 4 , 30 , 1 ] , [ 4 , 31 , 1 ] ,
[ 8 , 0 , 4 ] , [ 8 , 4 , 2 ] , [ 9 , 6 , 2 ] , [ 8 , 8 , 8 ] , [ 8 , 16 , 4 ] , [ 8 , 20 , 2 ] , [ 9 , 22 , 2 ] , [ 8 , 24 , 8 ]
]
] ,
[ //1 = DRUM FILL (0-15)
[ //pattern 0 - kill over
[ 4 , 0 , 1 ] , [ 0 , 1 , 2 ] , [ 0 , 3 , 1 ] , [ 4 , 4 , 2 ] , [ 4 , 6 , 1 ] , [ 0 , 7 , 2 ] , [ 0 , 9 , 1 ] , [ 4 , 10 , 2 ] , [ 4 , 12 , 1 ] , [ 0 , 13 , 2 ] , [ 0 , 15 , 1 ] ,
[ 8 , 0 , 3 ] , [ 8 , 3 , 3 ] , [ 9 , 6 , 1 ] , [ 8 , 7 , 2 ] , [ 9 , 9 , 1 ] , [ 8 , 10 , 2 ] , [ 9 , 12 , 1 ] , [ 8 , 13 , 3 ]
] ,
[ //pattern 1 - serenity
[ 0 , 0 , 3 ] , [ 0 , 3 , 1 ] , [ 4 , 4 , 4 ] , [ 0 , 7 , 3 ] , [ 0 , 10 , 2 ] , [ 4 , 12 , 4 ] ,
[ 8 , 0 , 2 ] , [ 9 , 2 , 2 ] , [ 8 , 4 , 6 ] , [ 9 , 10 , 2 ] , [ 8 , 12 , 4 ]
]
] ,
[ //2 = KEYBOARD LEFT HAND (0-63)
[ //pattern 0 - kill over
[ 71 , 0 , 3 ] , [ 83 , 3 , 3 ] , [ 71 , 6 , 3 ] , [ 78 , 9 , 3 ] , [ 71 , 10 , 2 ] , [ 71 , 12 , 2 ] , [ 78 , 14 , 2 ] ,
[ 86 , 16 , 2 ] , [ 90 , 19 , 2 ] , [ 83 , 22 , 2 ] , [ 79 , 24 , 2 ] , [ 74 , 27 , 2 ] , [ 86 , 30 , 2 ] ,
[ 90 , 32 , 2 ] , [ 91 , 34 , 2 ] , [ 83 , 36 , 2 ] , [ 74 , 39 , 2 ] , [ 78 , 42 , 2 ] , [ 83 , 44 , 2 ] , [ 86 , 46 , 2 ] ,
[ 81 , 48 , 2 ] , [ 76 , 50 , 2 ] , [ 85 , 52 , 2 ] , [ 88 , 55 , 2 ] , [ 93 , 58 , 2 ] , [ 81 , 60 , 2 ] , [ 76 , 62 , 2 ] ,
] ,
[ //pattern 1 - serenity
[ 38 , 0 , 3 ] , [ 38 , 4 , 3 ] , [ 38 , 10 , 3 ] , [ 37 , 14 , 3 ] , [ 37 , 18 , 3 ] , [ 37 , 22 , 2 ] , [ 40 , 24 , 3 ] , [ 37 , 28 , 3 ] ,
[ 35 , 0 , 3 ] , [ 35 , 4 , 3 ] , [ 35 , 10 , 3 ] , [ 33 , 14 , 3 ] , [ 33 , 18 , 3 ] , [ 33 , 22 , 2 ] , [ 37 , 24 , 3 ] , [ 33 , 28 , 3 ] ,
[ 35 , 32 , 3 ] , [ 35 , 36 , 3 ] , [ 35 , 42 , 3 ] , [ 37 , 46 , 3 ] , [ 37 , 50 , 3 ] , [ 37 , 54 , 2 ] , [ 40 , 56 , 3 ] , [ 37 , 60 , 3 ] ,
[ 31 , 32 , 3 ] , [ 31 , 36 , 3 ] , [ 31 , 42 , 3 ] , [ 33 , 46 , 3 ] , [ 33 , 50 , 3 ] , [ 33 , 54 , 2 ] , [ 37 , 56 , 3 ] , [ 33 , 60 , 3 ]
]
] ,
[ //3 = KEYBOARD RIGHT HAND (0-128)
[ //pattern 0 - kill over
[ 83 , 0 , 4 ] , [ 90 , 4 , 2 ] , [ 78 , 6 , 3 ] , [ 74 , 9 , 3 ] , [ 83 , 12 , 4 ] ,
[ 90 , 16 , 3 ] , [ 86 , 19 , 3 ] , [ 83 , 21 , 1 ] , [ 90 , 22 , 2 ] , [ 78 , 24 , 2 ] , [ 74 , 26 , 2 ] , [ 83 , 28 , 4 ] ,
[ 88 , 32 , 2 ] , [ 86 , 34 , 1 ] , [ 85 , 35 , 1 ] , [ 83 , 37 , 1 ] , [ 90 , 38 , 2 ] , [ 86 , 40 , 4 ] , [ 88 , 44 , 1 ] , [ 86 , 45 , 1 ] , [ 85 , 46 , 1 ] ,
[ 86 , 48 , 1 ] , [ 85 , 49 , 1 ] , [ 83 , 50 , 1 ] , [ 85 , 52 , 1 ] , [ 83 , 53 , 1 ] , [ 81 , 54 , 1 ] , [ 83 , 56 , 8 ] ,
[ 78 , 64 , 4 ] , [ 90 , 68 , 2 ] , [ 98 , 70 , 3 ] , [ 88 , 73 , 3 ] , [ 97 , 76 , 4 ] ,
[ 88 , 80 , 3 ] , [ 97 , 83 , 3 ] , [ 90 , 86 , 3 ] , [ 86 , 89 , 3 ] , [ 95 , 92 , 4 ] ,
[ 91 , 96 , 3 ] , [ 86 , 99 , 3 ] , [ 95 , 102 , 2 ] , [ 98 , 104 , 3 ] , [ 102 , 107 , 3 ] , [ 91 , 110 , 2 ] , [ 90 , 112 , 3 ] , [ 86 , 115 , 3 ] , [ 95 , 118 , 10 ]
] ,
[ //pattern 1 - serenity
[ 47 , 0 , 2 ] , [ 35 , 2 , 1 ] , [ 59 , 3 , 1 ] , [ 54 , 6 , 1 ] , [ 62 , 7 , 1 ] , [ 66 , 9 , 1 ] , [ 59 , 10 , 2 ] , [ 62 , 12 , 2 ] , [ 54 , 14 , 1 ] , [ 59 , 15 , 1 ] ,
[ 54 , 17 , 1 ] , [ 66 , 18 , 1 ] , [ 59 , 20 , 3 ] , [ 54 , 23 , 1 ] , [ 62 , 24 , 1 ] , [ 54 , 25 , 1 ] , [ 59 , 26 , 1 ] , [ 47 , 28 , 3 ] , [ 47 , 31 , 1 ] ,
[ 47 , 32 , 1 ] , [ 59 , 34 , 1 ] , [ 50 , 36 , 4 ] , [ 54 , 40 , 4 ] , [ 59 , 44 , 1 ] , [ 54 , 45 , 1 ] , [ 47 , 46 , 1 ] ,
[ 54 , 48 , 3 ] , [ 59 , 51 , 3 ] , [ 62 , 54 , 4 ] , [ 62 , 58 , 1 ] , [ 62 , 59 , 1 ] , [ 62 , 60 , 1 ] , [ 62 , 61 , 1 ] ,
[ 64 , 64 , 1 ] , [ 62 , 65 , 1 ] , [ 61 , 66 , 1 ] , [ 62 , 68 , 1 ] , [ 61 , 69 , 1 ] , [ 59 , 70 , 1 ] , [ 61 , 72 , 1 ] , [ 59 , 73 , 1 ] , [ 57 , 74 , 1 ] , [ 59 , 76 , 4 ] ,
[ 35 , 80 , 1 ] , [ 47 , 81 , 3 ] , [ 49 , 85 , 3 ] , [ 50 , 89 , 3 ] , [ 62 , 92 , 4 ] ,
[ 55 , 96 , 3 ] , [ 57 , 99 , 3 ] , [ 59 , 102 , 5 ] , [ 59 , 108 , 1 ] , [ 59 , 109 , 1 ] , [ 59 , 111 , 1 ] ,
[ 57 , 112 , 3 ] , [ 59 , 115 , 3 ] , [ 61 , 118 , 2 ] , [ 61 , 122 , 1 ] , [ 61 , 123 , 1 ] , [ 61 , 124 , 1 ] , [ 61 , 125 , 1 ]
] ,
] ,
[ //4 = BASSLINE
[ //pattern 0 - kill over
[ 23 , 0 , 4 ] , [ 23 , 4 , 4 ] , [ 23 , 10 , 4 ] , [ 25 , 14 , 4 ] , [ 26 , 18 , 4 ] , [ 28 , 22 , 4 ] , [ 25 , 26 , 2 ] , [ 26 , 28 , 4 ] ,
[ 19 , 32 , 4 ] , [ 19 , 36 , 4 ] , [ 19 , 42 , 4 ] , [ 21 , 46 , 4 ] , [ 23 , 50 , 4 ] , [ 25 , 54 , 4 ] , [ 21 , 58 , 2 ] , [ 23 , 60 , 4 ]
] ,
[ //pattern 1 - serenity
[ 23 , 0 , 4 ] , [ 23 , 4 , 4 ] , [ 23 , 10 , 4 ] , [ 25 , 14 , 4 ] , [ 25 , 18 , 4 ] , [ 26 , 22 , 2 ] , [ 28 , 24 , 2 ] , [ 26 , 26 , 2 ] , [ 25 , 28 , 4 ] ,
[ 19 , 32 , 4 ] , [ 19 , 36 , 4 ] , [ 19 , 42 , 4 ] , [ 21 , 46 , 4 ] , [ 21 , 50 , 4 ] , [ 23 , 54 , 2 ] , [ 25 , 56 , 2 ] , [ 23 , 58 , 2 ] , [ 21 , 60 , 4 ]
]
]
] ;
var drumsamples = [ ] ; //buffers with rendered drum (pitched) sounds
var percsamples = [ ] ; //buffers with rendered perc (noise) sounds
var samplesleft ; //drums left to render
var anomalyleft = 10 ;
var DECK = function ( offset ) {
this . offset = offset ;
this . source = null ; this . file = null ;
this . selected = false ; this . ready = false ;
this . title = "no track loaded" ;
this . position = 0 ; this . duration = 0 ;
console . log ( 'deck created.' ) ;
} ;
DECK . prototype . draw = function ( ) {
if ( selected === this ) { FBLUE ( ) ; SBLACK ( ) ; }
else { FBLACK ( ) ; SBLUE ( ) ; }
vc . fillRect ( 0 , this . offset , width , this . offset + 100 ) ;
vc . strokeText ( this . title , 10 , this . offset + 10 ) ;
vc . strokeText ( this . duration , 10 , this . offset + 20 ) ;
vc . strokeText ( this . position , 10 , this . offset + 30 ) ;
} ;
DECK . prototype . open = function ( ) {
var local = this ;
chrome . fileSystem . chooseEntry ( {
type : 'openFile' ,
accepts :[ { mimeTypes :[ 'audio/*' ] } ] ,
acceptsAllTypes :false } ,
function ( entry ) {
local . title = entry . name ;
console . log ( local . title ) ;
entry . file (
function ( file ) {
var reader = new FileReader ( ) ;
reader . readAsArrayBuffer ( file ) ;
reader . onloadend = function ( ) {
var audiodata = reader . result ;
ac . decodeAudioData ( audiodata ,
function ( buffer ) {
local . source = ac . createBufferSource ( ) ;
local . source . buffer = buffer ;
local . source . connect ( ac . destination ) ;
local . source . loop = true ;
local . source . start ( 0 ) ;
} , function ( e ) { console . log ( e ) ; } ) ;
} ;
} ) ;
} ) ;
} ;
var vcontext ; //HTML5 canvas
var acontext ; //WebAudio context
var bpm = 108 ; //idk who cares
var steptime = 15 / bpm ; //sixteenth note length
var nowtime ; //used by parallel hit renderers
var notes = [ ] ; //lookup table for note frequencies
var wavnoise ; //buffer with supposedly white noise
var samplerate ; //samples per second in audio context
var upper = new DECK ( 5 ) ;
var middle = new DECK ( 110 ) ;
var lower = new DECK ( 215 ) ;
var selected = upper ;
//findfx
var hitgain = 2 / 3 ;
var masterchannel ;
var delaytime = steptime * 3 ;
var delaygain = 0 / 3 ;
var delay ;
var feedback ;
var lowpassnote = 59 ;
var lowpassgain = 2 ;
var lowpass ;
var lpgain ;
var highpassnote = 95 ;
var highpassgain = 1 ;
var highpass ;
var hpgain ;
var waveform ;
var wavearray ;
var wavelength ;
var wavefft = 32768 ;
var wavewidth = 480.0 ;
var waveheight = 40.0 * 8 ;
var dropexponent = 4 ;
//findmixer
var loudsquares = [ [ 1 / 8 , 1 / 8 ] , [ 1 / 8 , 1 / 8 ] , [ 6 / 16 , 6 / 24 ] , [ 5 / 12 , 0 / 16 ] , [ 0 , 2 / 8 ] ] ;
var justdrums = [ [ 1 / 4 , 1 / 4 ] , [ 0 / 8 , 0 / 8 ] , [ 0 / 12 , 0 / 16 ] , [ 0 / 16 , 0 / 6 ] , [ 0 , 0 / 8 ] ] ;
var drumnbass = [ [ 0 / 8 , 0 / 8 ] , [ 0 / 8 , 0 / 8 ] , [ 0 / 12 , 0 / 16 ] , [ 0 / 16 , 0 / 6 ] , [ 0 , 2 / 8 ] ] ;
var anomalygain = loudsquares ;
var anomalyshift = [
[ 0 , 0 ] , //DRUMBEAT
[ 0 , 0 ] , //DRUMFILL
[ - 24 , 36 ] , //LEFTHAND
[ - 12 , 24 ] , //RIGHTHAND
[ 12 , 12 ] //BASSLINE
] ;
var drumvals = [ //pitched percussion sounds
//high,low,bend,fade
[ 47 , 23 , 1 / 12 , 1 , 1 ] , //kickdrum
[ 42 , 23 , 2 , 2 , 0 ] , //lowtom
[ 47 , 30 , 1 , 1 , 0 ] , //midtom
[ 54 , 35 , 1 / 2 , 1 / 2 , 0 ] , //hitom
[ 59 , 42 , 1 / 16 , 1 / 16 , 1 ] , //lowsnare
[ 66 , 47 , 1 / 4 , 1 / 4 , 0 ] , //midsnare
[ 71 , 54 , 1 / 8 , 1 / 8 , 0 ] , //hisnare
[ 78 , 59 , 1 / 16 , 1 / 16 , 0 ] //openhat
] ;
var percvals = [ //nonpitched percussion sounds
//filter,fade
[ 35 , 1 / 2 , 1 ] , //snarenoise
[ 95 , 1 / 32 , 2 ] , //closedhatnoise
[ 83 , 1 / 8 , 2 ] //openhatnoise
] ;
var draw = function ( ) {
drawvisual = requestAnimationFrame ( draw ) ;
waveform . getByteTimeDomainData ( wavearray ) ;
vcontext . fillStyle = 'rgb(0,0,0)' ;
vcontext . fillRect ( 0 , 0 , 480 , 320 ) ;
vcontext . fillStyle = 'rgb(192,192,192)' ;
vcontext . fillRect ( 0 , 0 , wavewidth , waveheight ) ;
vcontext . fillStyle = 'rgb(100,100,192)' ;
vcontext . fillRect ( 0 , waveheight / 4 ,
wavewidth * anomalyleft * 0.1 ,
waveheight / 2 ) ;
vcontext . lineWidth = 1 ;
vcontext . strokeStyle = 'rgb(0,0,0)' ;
vcontext . beginPath ( ) ;
var slicewidth = wavewidth / wavelength ;
var wavex = 0 ;
for ( var index = 0 ; index < wavelength ; index ++ ) {
var wavev = wavearray [ index ] / 128.0 ;
var wavey = wavev * waveheight / 2 ;
if ( index === 0 ) vcontext . moveTo ( wavex , wavey ) ;
else vcontext . lineTo ( wavex , wavey ) ;
wavex += slicewidth ;
}
vcontext . lineTo ( wavewidth , waveheight / 2 ) ;
vcontext . stroke ( ) ;
} ;
var SHIFT = function ( ) {
if ( selected === upper ) { selected = lower ; return ; }
if ( selected === middle ) { selected = upper ; return ; }
if ( selected === lower ) { selected = middle ; return ; }
} ;
var CTRL = function ( ) {
if ( selected === upper ) { selected = middle ; return ; }
if ( selected === middle ) { selected = lower ; return ; }
if ( selected === lower ) { selected = upper ; return ; }
} ;
var OM = function ( ) {
for ( var x = 0 ; x < 256 ; x ++ ) notes [ x ] = 440 * Math . pow ( 2 , ( x - 69 ) / 12 ) ; console . log ( notes ) ; //generate notes, print to console because why not
chrome . app . window . minWidth = 480 ;
chrome . app . window . minHeight = 320 ;
chrome . app . window . maxWidth = 480 ;
chrome . app . window . maxHeight = 320 ;
vcanvas = document . getElementById ( 'vcanvas' ) ; //grab canvas reference from HTML
vcontext = vcanvas . getContext ( '2d' ) ;
acontext = new window . AudioContext ( ) ; //grab WebAudio context from browser
samplerate = acontext . sampleRate ; //grab sample rate from audio context
//DELAY UNIT
delay = acontext . createDelay ( steptime * 32 ) ;
feedback = acontext . createGain ( ) ; feedback . gain . value = delaygain ;
delay . delayTime . value = ( delaytime ) ;
delay . connect ( feedback ) ; feedback . connect ( delay ) ;
delay . connect ( acontext . destination ) ;
//LOWPASS BOOST
lowpass = acontext . createBiquadFilter ( ) ;
lowpass . type = "lowpass" ;
lowpass . frequency . value = notes [ lowpassnote ] ;
lpgain = acontext . createGain ( ) ;
lpgain . gain . value = lowpassgain ;
lowpass . connect ( lpgain ) ; lpgain . connect ( acontext . destination ) ;
//HIGHPASS BOOST
highpass = acontext . createBiquadFilter ( ) ;
highpass . type = "highpass" ;
highpass . frequency . value = notes [ highpassnote ] ;
hpgain = acontext . createGain ( ) ;
hpgain . gain . value = highpassgain ;
highpass . connect ( hpgain ) ; hpgain . connect ( acontext . destination ) ;
//WAVEFORM DISPLAY
waveform = acontext . createAnalyser ( ) ;
waveform . fftSize = wavefft ;
wavelength = waveform . frequencyBinCount ;
wavearray = new Uint8Array ( waveform . fftSize ) ;
waveform . getByteTimeDomainData ( wavearray ) ;
//MASTER CHANNEL
masterchannel = acontext . createGain ( ) ;
masterchannel . gain . value = 1 ;
masterchannel . connect ( feedback ) ;
masterchannel . connect ( lowpass ) ;
masterchannel . connect ( highpass ) ;
masterchannel . connect ( waveform ) ;
masterchannel . connect ( acontext . destination ) ;
noiseclip = acontext . createBuffer ( 1 , samplerate , samplerate ) ; //create buffer for noise
var noisedata = noiseclip . getChannelData ( 0 ) ; //grab reference to noise buffer data
for ( x = 0 ; x < noisedata . length ; x ++ ) noisedata [ x ] = Math . random ( ) * 2 - 1 ; //randomize contents
samplesleft = drumvals . length + percvals . length ; //count how many samples need rendering
var drumcallback = function ( indexcalled ) { //create function for drumsample callbacks
return function ( outputclip ) {
drumsamples [ indexcalled ] = outputclip ;
samplesleft -- ; console . log ( samplesleft ) ;
if ( samplesleft === 0 ) renderanomaly ( ) ;
} ;
} ;
for ( var drumindex = 0 ; drumindex < drumvals . length ; drumindex ++ ) { //create each drum sample
var drumnode = drumvals [ drumindex ] ;
var drumhigh = notes [ drumnode [ 0 ] ] ; //initial pitch
var drumlow = notes [ drumnode [ 1 ] ] ; //final pitch
var drumbend = steptime * drumnode [ 2 ] ; //pitchdown time
var drumfade = steptime * drumnode [ 3 ] ; //fadeout time
var drumcontext = new OfflineAudioContext ( 1 , samplerate * drumfade * 16 , samplerate ) ; //spawn a buffer generator
var drumosc = drumcontext . createOscillator ( ) ; //spawn an oscillator
var drumgain = drumcontext . createGain ( ) ; //spawn a volume node
drumgain . gain . setValueAtTime ( drumnode [ 4 ] , 0 ) ; //set initial volume
drumgain . gain . setTargetAtTime ( 0 , 0 , drumfade ) ; //set fadeout
drumosc . frequency . value = drumhigh ; //set initial pitch
drumosc . frequency . setTargetAtTime ( drumlow , 0 , drumbend ) ; //set final pitch
drumosc . connect ( drumgain ) ; drumgain . connect ( drumcontext . destination ) ; //connect the dots
drumosc . start ( 0 ) ; drumosc . stop ( drumfade * 8 ) ; //set endpoints for oscillator
drumcontext . startRendering ( ) . then ( drumcallback ( drumindex ) ) ; //link to drum bank when finished
}
var perccallback = function ( indexcalled ) { //create linking callback generator
return function ( outputclip ) {
percsamples [ indexcalled ] = outputclip ;
samplesleft -- ; console . log ( samplesleft ) ;
if ( samplesleft === 0 ) renderanomaly ( ) ; } ;
} ;
for ( var percindex = 0 ; percindex < percvals . length ; percindex ++ ) { //create each perc sample
var percnote = notes [ percvals [ percindex ] [ 0 ] ] ; //filter pitch
var percfade = steptime * percvals [ percindex ] [ 1 ] ; //fade time
var perccontext = new OfflineAudioContext ( 1 , samplerate * steptime * 12 , samplerate ) ; //spawn a buffer generator
var percnoise = perccontext . createBufferSource ( ) ; //spawn a buffer node
percnoise . buffer = noiseclip ; //link noise to buffer node
var percgain = perccontext . createGain ( ) ; //spawn a volume node
var percfilter = perccontext . createBiquadFilter ( ) ; //spawn a filter node
percfilter . type = "highpass" ; //set to highpass filter
percfilter . frequency . value = percnote ; //set frequency of filter
percgain . gain . setValueAtTime ( percvals [ percindex ] [ 2 ] , 0 ) ; //set initial volume
percgain . gain . setTargetAtTime ( 0 , 0 , percfade ) ; //set fadeout time
percnoise . connect ( percgain ) ; percgain . connect ( percfilter ) ; //connect the dots
percfilter . connect ( perccontext . destination ) ; //connect to renderer
percnoise . start ( 0 ) ; percnoise . stop ( steptime * 8 ) ; //set buffer playback
perccontext . startRendering ( ) . then ( perccallback ( percindex ) ) ; //link to perc bank when finished
}
} ;
var renderanomaly = function ( ) {
var typeindex ; //create type index for anomaly bank
var songindex ; //create song index for anomaly bank
var anomalycallback = function ( typecalled , songcalled ) { //create anomaly linker callback generator
return function ( outputclip ) {
anomaly [ typecalled ] [ songcalled ] = outputclip ;
anomalyleft -= 1 ; console . log ( anomalyleft ) ;
if ( anomalyleft === 0 ) OM . playscene ( ) ;
} ;
} ;
for ( songindex = 0 ; songindex < 2 ; songindex ++ ) {
var pattern ;
for ( typeindex = 0 ; typeindex < 5 ; typeindex ++ ) {
pattern = identity [ typeindex ] [ songindex ] ; //grab current pattern to render
switch ( typeindex ) {
case 0 :
case 1 : { //DRUMBEAT+DRUMFILL
var dbsteps = 32 ;
if ( typeindex === 0 ) dbsteps = 64 ;
var dbcontext = new OfflineAudioContext ( 1 , samplerate * steptime * dbsteps , samplerate ) ; //create drumbeat anomaly renderer
for ( var dbindex = 0 ; dbindex < pattern . length ; dbindex ++ ) { //schedule buffers at each note
var dbnote = pattern [ dbindex ] ; //grab current note
switch ( dbnote [ 0 ] ) { //check what note to play
case 0 :{ //if note is kick:
var dbkick = dbcontext . createBufferSource ( ) ; //create kick node
dbkick . buffer = drumsamples [ 0 ] ; dbkick . connect ( dbcontext . destination ) ; //connect the dots
dbkick . start ( steptime * dbnote [ 1 ] ) ; dbkick . stop ( steptime * ( dbnote [ 1 ] + dbnote [ 2 ] ) ) ; //schedule kick sound
} break ;
case 4 :{ //if note is snare:
var dbdrum = dbcontext . createBufferSource ( ) ; //create snare drum node
var dbperc = dbcontext . createBufferSource ( ) ; //create snare perc node
dbdrum . buffer = drumsamples [ 4 ] ; dbperc . buffer = percsamples [ 0 ] ; //connect the buffers
dbdrum . connect ( dbcontext . destination ) ; dbperc . connect ( dbcontext . destination ) ; //connect the dots
dbdrum . start ( steptime * dbnote [ 1 ] ) ; dbdrum . stop ( steptime * ( dbnote [ 1 ] + dbnote [ 2 ] ) ) ; //schedule drum sound
dbperc . start ( steptime * dbnote [ 1 ] ) ; dbdrum . stop ( steptime * ( dbnote [ 1 ] + dbnote [ 2 ] ) ) ; //schedule perc sound
} break ;
case 8 :
case 9 :{ //if note is hihat:
var dbhihat = dbcontext . createBufferSource ( ) ; //create hihat node
if ( dbnote [ 0 ] == 8 ) dbhihat . buffer = percsamples [ 1 ] ; //if closed, set closed hihat
else dbhihat . buffer = percsamples [ 2 ] ; //otherwise, set open hihat
dbhihat . connect ( dbcontext . destination ) ; //connect the dots
if ( dbnote [ 0 ] == 8 ) {
dbhihat . loop = true ; dbhihat . loopStart = 0 ; dbhihat . loopEnd = steptime ;
}
dbhihat . start ( steptime * dbnote [ 1 ] ) ;
dbhihat . stop ( steptime * ( dbnote [ 1 ] + dbnote [ 2 ] ) ) ; //schedule hihat sound
} break ;
default :break ;
}
}
dbcontext . startRendering ( ) . then ( anomalycallback ( typeindex , songindex ) ) ;
} break ;
case 2 : //LEFTHAND
case 3 : //RIGHTHAND
case 4 : { //BASSLINE
var squaresteps = 64 ;
if ( typeindex == 3 ) squaresteps = 128 ;
squarecontext = new OfflineAudioContext ( 1 , samplerate * steptime * squaresteps , samplerate ) ;
for ( var squareindex = 0 ; squareindex < pattern . length ; squareindex ++ ) {
squarenote = pattern [ squareindex ] ;
squareosc = squarecontext . createOscillator ( ) ;
squaregain = squarecontext . createGain ( ) ; squaregain . gain . value = anomalygain [ typeindex ] [ songindex ] ;
squareosc . type = "square" ; squareosc . connect ( squaregain ) ;
squaregain . connect ( squarecontext . destination ) ;
squareosc . frequency . value = notes [ squarenote [ 0 ] + anomalyshift [ typeindex ] [ songindex ] ] ;
squareosc . start ( steptime * squarenote [ 1 ] ) ;
squareosc . stop ( steptime * ( squarenote [ 1 ] + squarenote [ 2 ] ) ) ;
}
squarecontext . startRendering ( ) . then ( anomalycallback ( typeindex , songindex ) ) ;
} break ;
default :break ;
}
}
}
OM . listen ( ) ;
draw ( ) ;
} ;
OM . hit = function ( hittime , sourceclip ) {
var hitclip = acontext . createBufferSource ( ) ;
hitclip . buffer = sourceclip ;
var gain = acontext . createGain ( ) ; gain . gain . value = hitgain ;
hitclip . connect ( gain ) ;
gain . connect ( masterchannel ) ;
hitclip . start ( hittime ) ;
} ;
OM . prevent = function ( eX ) { eX . preventDefault ( ) ; } ;
OM . listen = function ( ) {
document . body . addEventListener ( 'touchmove' , OM . prevent , false ) ;
vcanvas . addEventListener ( 'mousedown' , OM . playscene ) ;
vcanvas . addEventListener ( 'touchstart' , OM . playscene ) ;
} ;
OM . playscene = function ( eX ) {
nowtime = acontext . currentTime ;
//OM.hit(nowtime+64*steptime,anomaly[0][0]);
//OM.hit(nowtime+96*steptime,anomaly[0][0]);
OM . hit ( nowtime + 112 * steptime , anomaly [ 1 ] [ 1 ] ) ;
//OM.hit(nowtime+96*steptime,anomaly[1][0]);
OM . hit ( nowtime + 64 * steptime , anomaly [ 0 ] [ 1 ] ) ;
OM . hit ( nowtime + 96 * steptime , anomaly [ 0 ] [ 1 ] ) ;
OM . hit ( nowtime + 32 * steptime , anomaly [ 0 ] [ 1 ] ) ;
OM . hit ( nowtime , anomaly [ 0 ] [ 1 ] ) ;
OM . hit ( nowtime , anomaly [ 3 ] [ 1 ] ) ;
OM . hit ( nowtime , anomaly [ 3 ] [ 0 ] ) ;
OM . hit ( nowtime , anomaly [ 2 ] [ 1 ] ) ;
OM . hit ( nowtime , anomaly [ 2 ] [ 0 ] ) ;
OM . hit ( nowtime + ( 64 * steptime ) , anomaly [ 2 ] [ 1 ] ) ;
OM . hit ( nowtime + ( 64 * steptime ) , anomaly [ 2 ] [ 0 ] ) ;
OM . hit ( nowtime , anomaly [ 4 ] [ 1 ] ) ;
OM . hit ( nowtime + ( 64 * steptime ) , anomaly [ 4 ] [ 1 ] ) ;
OM . hit ( nowtime , anomaly [ 4 ] [ 0 ] ) ;
OM . hit ( nowtime + ( 64 * steptime ) , anomaly [ 4 ] [ 0 ] ) ;
} ;
return OM ;
} ( ) ;
var om ;
window . onload = function ( ) {
om = new OM ( ) ;
} ;
var DRAW = function ( ) {
requestAnimationFrame ( DRAW ) ;
FBLACK ( ) ; vc . fillRect ( 0 , 0 , height , width ) ;
upper . draw ( ) ; middle . draw ( ) ; lower . draw ( ) ;
} ;
window . addEventListener ( "keydown" , function ( event ) {
if ( event . defaultPrevented ) return ;
if ( event . keyCode == 16 ) SHIFT ( ) ;
if ( event . keyCode == 17 ) CTRL ( ) ;
if ( event . keyCode == 79 ) selected . open ( ) ;
console . log ( event . keyCode + " down, " ) ; } ) ;
window . addEventListener ( "keyup" , function ( event ) {
if ( event . defaultPrevented ) return ;
console . log ( event . keyCode + " up, " ) ; } ) ;
window . onload = DRAW ;