A purpose-agnostic step sequencer implementation
$ yarn add generic-step-sequencer
see https://github.com/youpy/generic-step-sequencer/blob/main/examples/basic/index.ts
implement a step executor
import {
StepExecutor,
Sequencer,
State,
PeriodicTicker,
backward,
} from "generic-step-sequencer";
interface MyParameter {
foo: string;
}
class MyStepExecutor implements StepExecutor<MyParameter> {
execute(track: Track<MyParameter>): void {
console.log(
`executing step ${track.currentStep} on ${track.parameters.foo}`
);
}
}
create and start a sequencer
const sequencer = new Sequencer<MyParameter, MyStepExecutor>(
new MyStepExecutor()
);
const ticker = new PeriodicTicker(sequencer);
sequencer.addTrack({ foo: "track1" }, 8, [0, 2, 4, 6]);
sequencer.addTrack({ foo: "track2" }, 8, [1, 3, 5, 7]);
ticker.bpm = 250;
ticker.start();
set step direction
// backward
sequencer.setNextStepStrategy(backward);
// random
const random = <T>(track: Track<T>): number => {
return Math.floor(Math.random() * track.numberOfSteps);
};
sequencer.setNextStepStrategy(random);
- https://github.com/youpy/generic-step-sequencer/tree/main/examples/midi-sequencer
- https://twitter.com/youpy/status/1469315687999217664
type Props = {
seq: Sequencer<MyParameter, MyStepExecutor>;
ticker: PeriodicTicker;
};
funcion App(props: Props) {
const { seq, ticker } = props
const [seqState, setSeqState] = useState<State<MyParameter>>({
tracks: [],
});
useEffect(() => {
seq.onStateChange(setSeqState);
ticker.start()
});
// construct view from seqState
return ...
}
You can replace the default timer with a custom timer implementation that implements the Timer
interface
const ticker = new PeriodicTicker(sequencer, new MyTimer());