Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change tempo to be in beats per minute #1

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

kasbah
Copy link

@kasbah kasbah commented Sep 21, 2016

I am using this to make a nice step sequencer out of my old Novation Launchpad. Thanks very much!

To me it makes more sense to have the tempo be beats per minute and independant of the number of divisions, so I adapted it. What do you think?

Copy link
Owner

@freitagbr freitagbr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for contributing!

@@ -45,10 +45,10 @@ function setTempo(tempo) {

function setSequence(division, sequence) {
if (typeof division !== 'number') throw new TypeError('Division must be a number');
if (!(sequence instanceof Array)) throw new TypeError('Sequence must be an array');
if (sequence && !(sequence instanceof Array)) throw new TypeError('Sequence must be an array');
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you're here, let's change sequence instanceof Array to Array.isArray(sequence).

@@ -20,9 +20,9 @@ function loop() {
}

function advance() {
if (this.step >= this.division) this.step = 0;
Copy link
Owner

@freitagbr freitagbr Sep 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I think this makes more sense as well.

Though, I think this should be:

if (this.step >= this.sequence.length) this.step = 0;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I am working under the assumption that the sequence can be empty because that's the way I have been using this. If we init it the way you describe below then it's different.

function calcTimeout(tempo, division) {
return Math.floor((60 / tempo * division) * 10e8) + 'n';
function calcTimeout(tempo) {
return Math.floor((60 / tempo) * 10e8) + 'n';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I had it initially, you could have multiple subdivisions per beat, i.e. you could say the tempo is 120, and the division is 4, and you would get 4 emits per beat. This is useful if you want eighth, sixteenth, half notes, etc.

This new way only emits once per beat. I guess you could change the tempo to get the effect of having subdivisions, but I would prefer to have subdivisions.

Thoughts?

@@ -49,11 +49,11 @@ function setSequence(division, sequence) {

this.division = division;
this.sequence = sequence;
this.timeout = calcTimeout(this.tempo, this.division)
this.timeout = calcTimeout(this.tempo)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semicolon.

@@ -66,7 +66,7 @@ function StepSequencer(tempo, division, sequence) {
this.sequence = sequence || [];
this.step = 0;
this.timer = new NanoTimer();
this.timeout = calcTimeout(this.tempo, this.division)
this.timeout = calcTimeout(this.tempo)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semicolon.


this.division = division;
this.sequence = sequence;
this.sequence = sequence || [];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we could make the sequence optional. But maybe we should default to an Array that is the same length as the number of subdivisions (or maybe 16, typical step-sequencer length)

this.sequence = sequence || Array(divisions);
// or
this.sequence = sequence || Array(16);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I copied the initialization from the constructor.

@kasbah
Copy link
Author

kasbah commented Sep 24, 2016

Thanks for reviewing! There are two features mixed together on this branch now because I have been using my fork in my project and needed all these changes. I should have sent separate PRs from feature branches. Sorry about that.

This could be split into the following, maybe you could comment on both.

  1. Change tempo to always be steps per minute and remove dependency on the number of divisions
  2. Make the sequence argument optional in all cases

To quote what you said about 1. already.

The way I had it initially, you could have multiple subdivisions per beat, i.e. you could say the tempo is 120, and the division is 4, and you would get 4 emits per beat. This is useful if you want eighth, sixteenth, half notes, etc.

This new way only emits once per beat. I guess you could change the tempo to get the effect of having subdivisions, but I would prefer to have subdivisions.

In my step sequencer I have 3 arguments: tempo, numberOfSteps and stepsPerBeat. I am not sure if I could change all three independently if it works the way you are describing. Currently I change the tempo according to the number of beats, like you say:

stepSequencer = new StepSequencer(tempo * stepsPerBeat, numberOfSteps)

If I change one of those variables I do:

stepSequencer.setTempo(tempo * stepsPerBeat)
stepSequencer.setSequence(numberOfSteps)
stepSequencer.removeAllListeners()
registerAllListeners() //loops through range numberOfSteps to register all the event handlers

I found this way easier to reason about and I am still not sure I could do it if tempo was tied to divisions.

@kasbah
Copy link
Author

kasbah commented Sep 24, 2016

Would you be happy to change the constructor to?

StepSequencer(tempo, stepsPerBeat, numberOfSteps [, sequence])

Though I am not quite sure what to do about checking the size of the sequence array if we allow people to setStepsPerBeat and setNumberOfSteps. Frankly I don't understand the use for the sequence array 😆 .

@kasbah
Copy link
Author

kasbah commented Sep 29, 2016

I fixed the semi-colons. Any thoughts on this? If I can't get this merged in some way I'll have to release a fork as I'd like to put my Launchpad step sequencer up on NPM.

@freitagbr
Copy link
Owner

Hey @kasbah, I'll take a look at this when I get home from work. Hopefully we can get this merged in the next day or two.

@freitagbr
Copy link
Owner

Looking at the constructor you posted earlier:

StepSequencer(tempo, stepsPerBeat, numberOfSteps [, sequence])

I like this. stepsPerBeat is more descriptive than division, so let's go with that. numberOfSteps is sort of the same as sequence.length, so let me explain what I was using sequence for.

I wrote this project while trying to create a little step sequencer for a Raspberry Pi/Teenage Engineering Pocket Operator thing. In the sequence array, I stored true (on) or false (off). On your launchpad, true would mean the pad is lit up, false would mean the pad is off. So, creating a 4-on-the-floor beat might look like this:

var sequence = [
    true, false, false, false,
    true, false, false, false,
    true, false, false, false,
    true, false, false, false
];
var sequencer = new StepSequencer(120, 4, 16, sequence);
// On you launchpad:
// [X] [ ] [ ] [ ] [X] [ ] [ ] [ ]
// [X] [ ] [ ] [ ] [X] [ ] [ ] [ ]

Of course, you could keep the sequence outside of the StepSequencer itself, and just let it handle the timing. Anyways, that's what I used sequence for.

Anyways, you can change the constructor as you suggested. There would need to be an assert or something to make sure numberOfSteps === sequence.length.

@kasbah
Copy link
Author

kasbah commented Sep 30, 2016

Yes, that does make sense. In my application I prefer to keep the sequence
outside of this module as I need to change it all the time and it is part
of my application state (which I manage with redux).

We could make use of dynamic typing and make the last argument either
numberOfSteps or sequence so you specify one but never both. What do
you think?

On 30 September 2016 at 15:43, Brandon Freitag [email protected]
wrote:

Looking at the constructor you posted earlier:

StepSequencer(tempo, stepsPerBeat, numberOfSteps [, sequence])

I like this. stepsPerBeat is more descriptive than division, so let's go
with that. numberOfSteps is sort of the same as sequence.length, so let
me explain what I was using sequence for.

I wrote this project while trying to create a little step sequencer for a
Raspberry Pi/Teenage Engineering Pocket Operator thing. In the sequence
array, I stored true (on) or false (off). On your launchpad, true would
mean the pad is lit up, false would mean the pad is off. So, creating a
4-on-the-floor beat might look like this:

var sequence = [
true, false, false, false,
true, false, false, false,
true, false, false, false,
true, false, false, false
];var sequencer = new StepSequencer(120, 4, 16, sequence);// On you launchpad:// [X] [ ] [ ] [ ] [X] [ ] [ ] [ ]// [X] [ ] [ ] [ ] [X] [ ] [ ] [ ]

Of course, you could keep the sequence outside of the StepSequencer
itself, and just let it handle the timing. Anyways, that's what I used
sequence for.

Anyways, you can change the constructor as you suggested. There would need
to be an assert or something to make sure numberOfSteps ===
sequence.length.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#1 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAMoBoRK3NGBf93gu0Z5MSh89b-P4u9zks5qvSAXgaJpZM4KDTIZ
.

@freitagbr
Copy link
Owner

Ok, so if the last argument is a number, treat it as numberOfSteps, but if it is an array, treat it as sequence, deriving the number of steps from the length of the array. Sounds good to me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants