gibber.core.lib
Version:
small set of core objects and functions for gibber
188 lines (143 loc) • 4.25 kB
JavaScript
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
}