0.13.14 • Published 11 months ago

@faddys/dsbltn v0.13.14

Weekly downloads
-
License
Unlicense
Repository
github
Last release
11 months ago

Faddy's Disableton Command-Line Music Production Tool

Work of Faddy Michel

In Solidarity with The People of Palestine till Their Whole Land is FREE

Prerequisites

Installation

sudo npm i -g @faddys/dsbltn

Usage

dsbltn [ ... notation ]

$root

node_modules/

/?# npm i @faddys/scenarist@latest @faddys/command@latest

index.orc

?# cat - > index.orc
//+==

sr = 44100
ksmps = 32
nchnls = 6
0dbfs = 1

instr 13, 14, beat

p3 *= 1000
SPath strget p4
strset p5, SPath

iEvent init ( int ( p1 ) % 10 ) + frac ( p1 )

kLoop metro 1/p3

if kLoop == 1 then

schedulek iEvent, 0, 1, p5, p6, p7

endif

endin

instr 3, play

SPath strget p4
p3 filelen SPath

aLeft, aRight diskin2 SPath

outs aLeft / ( p5 + 1 ), aRight / ( p6 + 1 )

endin

instr 4, recorder

SPath strget p4

SPath1 strcat SPath, ".1.2.wav"
SPath2 strcat SPath, ".3.4.wav"
SPath3 strcat SPath, ".5.6.wav"

aLeft1, aRight1 inch 1, 2
aLeft2, aRight2 inch 3, 4
aLeft3, aRight3 inch 5, 6

fout SPath1, -1, aLeft1, aRight1
fout SPath2, -1, aLeft2, aRight2
fout SPath3, -1, aLeft3, aRight3

endin

//-==

shell.mjs

?# cat - > shell.mjs
//+==
#!/usr/bin/env node

import Scenarist from '@faddys/scenarist';
import $0 from '@faddys/command';
import { createInterface } from 'node:readline';
import { stdin as input, stdout as output } from 'node:process';import dsbltn from './index.mjs';
import { parse } from 'node:path';

try {

const argv = process .argv .slice ( 2 );
const { base: location } = parse ( process .cwd () );

await Scenarist ( new dsbltn (

Symbol .for ( 'location' ), location,
... argv 

) );

const shell = createInterface ( { input, output } )
.on ( 'line', line => {

dsbltn .$ (  ... line .trim () .split ( /\s+/ ) )
.then ( async output => {

console .log ( 'OK' );

if ( [ 'string', 'number', 'boolean' ] .includes ( typeof output ) )
console .log ( output );

shell .setPrompt ( await dsbltn .$ ( 'location' ) + ': ' );

} )
.catch ( error => {

console .error ( 'Bad Request' );
console .error ( error ?.message || error );

} )
.finally ( () => shell .prompt () )

} );

shell .setPrompt ( await dsbltn .$ ( 'location' ) + ': ' );
shell .prompt ();

} catch ( issue ) {

console .error ( 'Failed to start dsbltn:', issue ?.message || issue );

}

//-==

index.mjs

?# cat - > index.mjs
//+==

import File from './file.mjs';
import Sound from './sound.mjs';

export default class dsbltn {

#argv

constructor ( ... argv ) { this .#argv = argv }

#player

async $_producer ( $, { player, location } ) {

this .#player = player;
this .#location = location;

await $ ( Symbol .for ( 'file' ), 'list' );

if ( ! this .#player ) return ( dsbltn .$ = $ ) ( ... this .#argv );

await $ ( ... this .#argv );

}

$_director ( $, ... argv ) {

if ( argv .length )
throw 'Unknown argument ' + ( typeof argv [ 0 ] === 'string' ? argv [ 0 ] : argv [ 0 ] .toString () );

}

#location
get $location () { return [ dsbltn .location, ... this .#location ] .join ( ' ' ) }
$_location ( $, ... argv ) { return dsbltn .location = argv .shift (), $ ( ... argv ) }

get $dsbltn () { return dsbltn }

#file = new File
get $_file () { return this .#file }

#sound = new Sound
get $sound () { return this .#sound }

[ '$.' ] ( $, ... argv ) { return ( dsbltn .$ = $ ) ( ... argv ) }
[ '$..' ] ( $, ... argv ) { return ( dsbltn .$ = this .#player || $ ) ( ... argv ) }

async $_parameter ( $, ... argv ) {

const name = argv .shift ();

if ( ! argv .length )
return this .#parameter [ name ] || ( this .#player ? await this .#player ( name ) : dsbltn .parameter [ name ] );

let value = parseFloat ( argv .shift () );

if ( isNaN ( value ) )
throw `The provided ${ name } value is not a number`;

$ ( Symbol .for ( 'file' ), 'write', name, this .#parameter [ name ] = value );

return $ ( ... argv );

}

#parameter = {}
static parameter = {

tempo: 105,
measure: 4,
divisions: 8,
step: 0,
left: 1,
right: 1

}

$tempo ( $, ... argv ) { return $ ( Symbol .for ( 'parameter' ), 'tempo', ... argv ) }
$measure ( $, ... argv ) { return $ ( Symbol .for ( 'parameter' ), 'measure', ... argv ) }
$divisions ( $, ... argv ) { return $ ( Symbol .for ( 'parameter' ), 'divisions', ... argv ) }
$step ( $, ...argv ) { return $ ( Symbol .for ( 'parameter' ), 'step', ... argv ) }
$left ( $, ... argv ) { return $ ( Symbol .for ( 'parameter' ), 'left', ... argv ) }
$right ( $, ... argv ) { return $ ( Symbol .for ( 'parameter' ), 'right', ... argv ) }

async $delete ( $, ... argv ) {

if ( ! argv .length )
throw 'Name of the dsbltn to be deleted is missing';

const name = argv .shift ();
const $name = '$' + name;

if ( ! ( this [ $name ] instanceof dsbltn ) )
throw `${ name } cannot be deleted`;

await $ ( Symbol .for ( 'file' ), 'delete', name );
delete this [ $name ];

return $ ( ... argv );

}

};

//-==

sound.mjs

?# cat - > sound.mjs
//+==

import $0 from '@faddys/command';
import { parse } from 'node:path';

export default class Sound {

$_producer ( $, { player } ) { this .dsbltn = player }

#instance = 0
get instance () { return this .#instance = ++this .#instance % 10 === 0 ? ++this .#instance : this .#instance }

instrument = 'play'

$record ( $, ... argv ) { return this .instrument = 'record', $ ( ... argv ) }
$play ( $, ... argv ) { return this .instrument = 'play', $ ( ... argv ) }

loop = false
$loop ( $, ... argv ) { return this .loop = ! this .loop, $ ( ... argv ) }

async $score ( $, instrument = 'play', time = 0 ) {

const { dsbltn } = this;

return [

'i',
`[ ${ this .loop ? 1 : '' }${ this .instrument } + .${ this .instance } ]`,
await dsbltn ( 'measure' ) * ( time + await dsbltn ( 'step' ) / await dsbltn ( 'divisions' ) ),
1,
`"${ await dsbltn ( 'audio' ) }"`,
await dsbltn ( 'left' ), await dsbltn ( 'right' )

] .join ( ' ' );

}

static number = {

play: 3,
record: 4

}

};

//-==

file.mjs

?# cat - > file.mjs
//+==

import $0 from '@faddys/command';

export default class File {

async $_producer ( $, { player, location } ) {

this .player = player;
this .$directory = [ '.', ... location .slice ( 0, -1 ) ] .join ( '/' ) + '/';

await $0 ( 'mkdir -p', this .$directory );

}

async $list ( $ ) {

for ( const direction of await $0 ( 'ls --file-type -1' ) .then ( $ => $ ( Symbol .for ( 'output' ) ) ) )

if ( direction .endsWith ( '.ds/' ) )
try {

await this .player ( 'dsbltn', direction );

} catch ( error ) {

await this .player ( 'delete', direction .name );

} else if ( direction .endsWith ( '.ds' ) )
await $ ( 'read', direction .slice ( 0, -3 ) );

}

async $read ( $, direction ) {

await this .player (

direction,
... await $0 ( 'cat', this .$directory + direction + '.ds' ) .then ( $ => $ ( Symbol .for ( 'output' ) ) )

);

}

async $write ( $, direction, ... argv ) {

if ( ! argv .length )
throw 'Nothing to write';

const write = await $0 ( 'cat - >', this .$directory + direction + '.ds' )

for ( const value of argv )
await write ( value );

return write ( Symbol .for ( 'end' ) );

}

$delete ( $, direction ) {

return $0 ( 'rm -rf', this .$directory + direction );

}

};

//-==