UNPKG

gibber.core.lib

Version:

small set of core objects and functions for gibber

188 lines (143 loc) 4.25 kB
module.exports = function( Gibber ) { let Pattern = Gibber.Pattern // taken from https://github.com/mkontogiannis/euclidean-rhythms const getPattern = (pulses, steps) => { if (pulses < 0 || steps < 0 || steps < pulses) { return []; } let first = new Array(pulses).fill([1]); let second = new Array(steps - pulses).fill([0]); let firstLength = first.length; let minLength = Math.min(firstLength, second.length); let loopThreshold = 0; while (minLength > loopThreshold) { if (loopThreshold === 0) { loopThreshold = 1; } for (var x = 0; x < minLength; x++) { first[x] = Array.prototype.concat.call(first[x], second[x]); } if (minLength === firstLength) { second = Array.prototype.slice.call(second, minLength); } else { second = Array.prototype.slice.call(first, minLength); first = Array.prototype.slice.call(first, 0, minLength); } firstLength = first.length; minLength = Math.min(firstLength, second.length); } let pattern = []; first.forEach(f => { pattern = Array.prototype.concat.call(pattern, f); }); second.forEach(s => { pattern = Array.prototype.concat.call(pattern, s); }); return pattern; }; let Euclid = function( ones, length, time, rotation=0 ) { let count = 0, onesAndZeros onesAndZeros = getPattern( ones,length ) let pattern = Gibber.Pattern( ...onesAndZeros ) if( isNaN( time ) || time === null ) time = 1 / onesAndZeros.length pattern.onrender = function( rendered ) { rendered.type = 'Euclid' rendered.time = time rendered.output = { time, shouldExecute: 0 } rendered.addFilter( ( args, ptrn ) => { let val = args[ 0 ] ptrn.output.time = Gibberish.Clock.time( ptrn.time ) ptrn.output.shouldExecute = val args[ 0 ] = ptrn.output return args }) } pattern.reseed = ( ...args )=> { let n, k if( Array.isArray( args[0] ) ) { k = args[0][0] n = args[0][1] }else{ k = args[0] n = args[1] } if( n === undefined ) n = 16 out = createStartingArray( n,k ) let _onesAndZeros = Inner( n,k ) pattern.set( _onesAndZeros ) pattern.time = 1 / n // this.checkForUpdateFunction( 'reseed', pattern ) return pattern } //Gibber.addSequencingToMethod( pattern, 'reseed' ) if( rotation !== 0 ) pattern.rotate( rotation ) return pattern } // E(5,8) = [ .25, .125, .25, .125, .25 ] let calculateRhythms = function( values, dur ) { let out = [] if( typeof dur === 'undefined' ) dur = 1 / values.length let idx = 0, currentDur = 0 while( idx < values.length ) { idx++ currentDur += dur if( values[ idx ] == 1 || idx === values.length ) { out.push( currentDur ) currentDur = 0 } } return out } let answers = { '1,4' : '1000', '2,3' : '101', '2,5' : '10100', '3,4' : '1011', '3,5' : '10101', '3,7' : '1010100', '3,8' : '10010010', '4,7' : '1010101', '4,9' : '101010100', '4,11': '10010010010', '5,6' : '101111', '5,7' : '1011011', '5,8' : '10110110', '5,9' : '101010101', '5,11': '10101010100', '5,12': '100101001010', '5,16': '1001001001001000', '7,8' : '10111111', '11,24': '100101010101001010101010' } Euclid.test = function( testKey ) { let failed = 0, passed = 0 if( typeof testKey !== 'string' ) { for( let key in answers ) { let expectedResult = answers[ key ], result = Euclid.apply( null, key.split(',').map( v => parseInt(v) ) ).values.join('') console.log( result, expectedResult ) if( result === expectedResult ) { console.log("TEST PASSED", key ) passed++ }else{ console.log("TEST FAILED", key ) failed++ } } console.log("*****************************TEST RESULTS - Passed: " + passed + ", Failed: " + failed ) }else{ let expectedResult = answers[testKey], result = flatten.call( Euclid.apply( null, testKey.split(',') ) ).join('') console.log( result, expectedResult ) if( result == expectedResult ) { console.log("TEST PASSED FOR", testKey) }else{ console.log("TEST FAILED FOR", testKey) } } } return Euclid }