Giter Club home page Giter Club logo

fillmaster's Introduction

Introduction

This project has been created to inspire ideas for drummers by enforcing rules to use whilst practicing the improvisation of drum beats, particularly fills. It can help beginner improvisers practice playing fills on time and can help any level of player get out of their comfort zone by playing things outside their usual style.

The project is Open Source under GNU GENERAL PUBLIC LICENSE Version 3.

Getting started

Clone the repo and run npm i

Available Scripts

In the project directory, you can run:

npm start

Runs the app in the development mode.
Open http://localhost:3000 to view it in the browser. Open http://yourip:3000 on your mobile to view on mobile.

The page will reload if you make edits.

npm test

Runs the tests. Code must be compiled first using npm run compile.

npm run compile

If you need to compile the code to JavaScript. The files will be in the dist folder.

npm run build

Builds the app for production to the build folder.
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.
Your app is ready to be deployed!

npm run serve

Builds the app and runs the server so that you can then go to: http://yourip:3000 on your mobile to view the built app (i.e. not the slower, dev environment app).

About the project:

Small, single-function components (e.g. a custom button) live in the 'elements' folder. All other components including those you may class as a container live in the 'components' folder.

This project uses the react-pro-metronome (RPM) library. It has been imported into the source as the npm version is no longer maintained and has missing audio files. The audio files would have been replaced regardless, as a special tone is used for the fill start. RPM works perfectly as it uses howler.js (which implements the Web Audio API) for a stable tempo. RPM is also easy to interact with, using strings to abstract interaction with the metronome pulses. Metronome.tsx handles interaction with RPM.

RPM is written in javascript and at some point in the future we may update this to typescript and strip out any unused code, but its not a priority as it works perfectly right now. It should remain isolated at least until we have plenty of UI tests in place. This will allow us to focus on implementing new features to FillMaster. The test file in the RPM directory 'tests/index.js' should be named 'tests/index.test.js'; this was changed as there was conflicts with Jest when ts-jest was added so it was renamed so that the test skips. Before any changes to RPM happen, this test must be reinstated and compatibility issues fixed.

Music Counting Basics (and the Metronome Interface)

This will hopefully help non-musicians working on the project or musicians who don't know much theory. It's also a guide for how we communicate with the metronome part of the app.

Musicians often count music to help them keep in time. 4/4 is the most common time signature used in music. See glossary (below) for an explanation of time signatures.

  • If you decide to play quarter notes (beats) in 4/4. You may count 1, 2, 3, 4, 1, 2, 3, 4.

  • If you decide to play eighth notes (two notes per beat) in 4/4. You may count 1 and 2 and 3 and 4 and. This can be called the first subdivision.

  • If you decide to play sixteenth notes (four notes per beat) in 4/4. You may count 1 e & a 2 e & a 3 e & a 4 e & a. This can be called the second subdivision.

If all of these are played at 100 bpm (beats per minute). The numbers would fall in the same place and the subdivisions would fall in between.

If we were to play in 4/8. It would sound identical to 4/4 (its just a naming convention). The first subdivision will now be called 16th notes (as you now are using 8ths as your beat) and the second subdivision will be called 32nd notes.

When making music you can go between beats and subdivisions as much as you want, otherwise the song would be pretty boring. But for the purpose of a metronome we tend to stick to one division at a time.

Exercise:

This is of course completely optional, but if you really want to understand why we count in music. Do the following.

  • Count out loud 1, 2, 3, 4 (and repeat)
  • Maintain the same speed but add and in between each number. 1 and 2 and 3 and 4 and.
  • Now add e (pronounced ee) and a (pronounced ah) on either side of the and. 1 e & a 2 e & a 3 e & a 4 e & a
  • Now clap your hands on only the beats (the numbers) whilst continuing to count the subdivisions.
  • Now ALSO clap on the and of 3.
  • Now ALSO clap on the e and and and a of 4.

You should now be counting like this (with the claps highlighted) 1 e & a 2 e & a 3 e & a 4 e & a.

This is why musicians count. To learn rhythms and to communicate rhythms. Where is that note you are playing? - It's on the 'a' of 3.

How does this translate to the metronome in the app?

The metronome in the app takes a string of numbers.

  • 0 = No sound
  • 1 = Accented click sound to emphasise beginning of the bar.
  • 2 = Regular click sound.
  • 3 = Helper sound. This is what makes Fill Master unique. We can place a helper sound on any sub beat to help the user pick out a certain part of the bar.

In 4/4 timing:

Count: 1 e & a 2 e & a 3 e & a 4 e & a
Quarter Notes: the beat 1 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0
Eighth Notes: first subdivision 1 0 2 0 2 0 2 0 2 0 2 0 2 0 2 0
16th Notes: second subdivision 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
Eighth Notes: Helper sound on Beat 4 1 0 2 0 2 0 2 0 2 0 2 0 3 0 2 0

Note: The above diagram is based on the metronome subdivision setting of 4. i.e. There can be up to 4 notes per beat. We actually default to 8 which allows for a third subdivision. The result is essentially the same but with extra 0s between each beat. If you look at the 'pattern' folder in 'tests' this may help you break down what's happening inside our interface with the metronome.

In 5/4 timing. The above diagram would look the same but the count would go up to 5.

In 4/8 timing. The above diagram would look the same but the beat would be called Eighth Notes, the first subdivision 16ths and the second subdivision would be 32nd notes.

GLOSSARY

Time signature:

Examples: 4/4 , 7/8 , 9/16

  • The first number is the number of beats per bar (a section of music).
  • The second number is the beat value.

4/4 = 4 beats per bar. Each beat is worth a quarter note.

7/8 = 7 beats per bar. Each beat is worth an 8th note.

9/16 = 9 beats per bar. Each beat is worth a 16th note.

Note: 4/4, 4/8 and 4/16 all sound identical. Whoever transcribes the music may favour one over the other for legibility.

bpm

Beats Per Minute.

Whether you are in 4/4 or 5/8 at 100bpm, you are playing 100 beats per minute. If you are simply playing a click track, they would sound identical. Musically though they would differ as you would (for example) put an accent on (i.e. hit a bit harder) the first beat of each bar, so every 4 notes or every 5 notes respectively would have an emphasis. You would also perhaps have a guitar riff that loops every 4 notes or every 5 notes. These will sound pretty different.

Of course 50bpm would be half the speed and 200bpm twice the speed. But it is also possible to stay at 100bpm but just play twice as many notes in the same space and it will sound twice as fast.

For example. If you count the beats in 4/4 as 1, 2, 3, 4. If you then put an AND between them and count the numbers at the same bpm. 1 AND 2 AND 3 AND 4 AND, your music will now sound twice as fast but you have not changed the BPM because the beats are only where you count the numbers. This is called subdivision.

Subdivision

See BPM explanation above.

fillmaster's People

Contributors

dcallus avatar kristersd avatar loeffeldude avatar ricci2511 avatar safin-sys avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

fillmaster's Issues

Add ability to use offline (potentially through local storage)

Currently (at least on iphone) when you save the app to your mobile desktop and attempt to use offline, the app works, except for the sounds.

I think the solution would be to store the sounds in local storage which there is information about on stack overflow. But perhaps there are other solutions.

sounds files are inside react-pro-metronome library in the source. It's okay to modify this library, it already is.

Add a settings button.

Settings button will open a settings box.

Add one basic setting that works to test functionality.

Remove the two 'any's from Metronome.tsx

Not a bug per se.

But line 118 of Metronome.tsx has the line:
render={(props: any, state: any) => ( because it refers to the ProMetronome library (in source) which is javascript. I think I got one of them working at one point but not the other.

Please figure out what types belong here.

Add local storage for time signature and reset option

Please add local storage options for time signatures so that the user's preference is saved.
Follow practices in PR#25#25

Rename the RESET TO DEFAULTS button in the settings menu to 'RESET ALL SETTINGS' and make it apply to the play settings (as well as those already reset in the settings menu). i.e.
make sure it also:

  1. Resets tempo slider to 60 - 120
  2. Resets time signature to 4/4

Change tests to typescript

The current tests in the test folder are in JavaScript as mocha is a js framework. Find an alternative as it sucks to lose type safety. Perhaps use chai with mocha?

Restart CountIn on stop

When you stop the metronome during a countIn - pressing play will continue from where you left off (in the countin). It's probably makes more sense just to restart.

Probably just need to conditionally make the play stop button reset during isCountin.

Bug: No error handling for setCustomSettingsForPattern

setCustomSettingsForPattern in the patternMaker.ts file needs error handling.

  1. When you have a beat higher than the beatsPerBar
  2. When you have a subBeat higher than the current subdivision -1.
    The -1 is necessary because [0, 1, 2, 3] would be your options for ['1', 'e', '&', 'a'] with a subdivision of 4.

Add some tests to make sure an error is being thrown.

Epic: Exact tempo & Tap Tempo

  • Tap tempo is going to need an audio preview. Other things in the app are going to need previews too without interfering with the patternMaker. The best approach would be to try and create a parent class for PatternMaker called PatternMakerBase. Probably most features will be moved up to the parent class (with exception of things like countins and fills). PatternMaker class will have the singleton logic. PatternMakerBase class will allow multiple instances. The preview could be done in the base class, but probably best to make a new child class called TempoPreviewMaker.
  • #56

FOR NINAD

  • Add a basic tap tempo button on section 1 (slider section). A temporary ugly button will do.
  • Have a look at the following for inspiration: https://github.com/classicwfl/React-Metronome-With-Tap-Tempo/blob/master/src/Metronome.js and try here too https://github.com/Pickup-Music/metronome
  • optional: See comments below for an example of a pro phone app using tap tempo
  • Implement your own tap tempo and add it to the button. It should register a tempo after ~3 taps.
  • Once a tap tempo has been established it should then play a preview sound (with the new tempoPreview class) which will have to be put into a new component reference.
  • Allow updating of tempo as the preview sound is playing. So if you keep clicking/tapping during preview playback, the tempo will update (this does not necessarily need another three clicks, whatever feels most stable and intuitive)
  • const MIN_TEMPO = 20; const MAX_TEMPO = 300; // put me in a new file in constants folder called tempoLimits.ts
  • Make sure tap tempo does not exceed these values.
  • Bonus: Write some tests, perhaps using a separate timer to simulate button presses and make sure the calculated tempo is correct (it probably doesn't need to be exact. Allow for a 2-3% leeway).

UI stuff for Dan

  • Move the labels (from section 1) showing the current tempo to elsewhere so that they do not overlap when the minimum distance is taken off.
  • Remove minimum distance between lower and upper tempo
  • Add a toggle switch to toggle between 'tempo range' and 'exact tempo'.
  • Implement tap tempo correctly into UI. Shift temporary button into a nice looking one in 'exact tempo mode'
  • When exact tempo is on it says 'choose a tempo' instead of 'choose a tempo range'. Also update section 5 so that it now says 'your chosen tempo' with a stationary number instead of a randomised tempo - or simply remove step 5. See which looks better.
  • Add logic so that when in 'tempo range' mode and the two tempos are on top of each other it will switch to 'exact tempo', i.e. one disappears and the toggle changes.
  • Slider value should move accordingly
  • Add visual feedback that the 3 clicks/taps have registered. A white flash of the screen or a lit up button etc.

Stretch goal 1. Try having two tap tempo buttons lowest tempo and highest tempo on tempo range mode. See if it looks okay or is too convoluted.
Stretch goal 2. Have an audio preview of the tempo on slider drag.
Stretch goal 3. Add Italian tempo names depending on the chosen tempo or tempo range.
Stretch goal 4. Add currently chosen settings to local storage.
Stretch goal 5: A dial knob on the metronome to adjust tempo during playback.

Add 'first note only option'.

In the metronome division section. As well as having 8ths, 16ths etc, there should be a 'first note of bar only' option.
This will not have a preview icon as there is no note in music for this.

It will only be shown when there is a need for it.
i.e. all odd time signatures should have this as an option.
But some even time divisions this option may already be available as 'whole notes' or 'half notes' for example, depending on time signature.

Improve Randomiser logic

The way the randomisation is done is quite convoluted.

It works well, but not super easy to understand (for a developer) and it would be preferable if it was time-based (currently it cycles through an array and you choose the array length to increase time, as well as how many milliseconds to pause on each number). It would be good if e.g. a parameter of 1000 could be sent to make the animation last 1 second. This way when doing something such as a refresh button, this number could be reduced easily so that the refresh time is quicker or it could be made faster in the user settings.

All logic is in components/Randomiser.tsx and utils/randomFucntions.ts

Add ability to change sounds.

Any sound for now will do, just use placeholders, I can find appropriate sounds.

The sounds are in the react-pro-metronome library (in source). I'm not sure why they are mp3, aac, ogg and wav for each sound, I assume for browser compatibility.

I got sounds from freesounds.com or something similar to this and used online converters to get multiples.

Extra sounds would be changed in the menu.
Perhaps 3 dropdown menus.
Change sound for:
1st beat sound[ sound 1, sound 2, sound 3]
standard beat sound [ soundX, soundY, soundZ]
fill highlight sound [ping1, ping2, ping3]

Make a refresh button for each randomly generated screen.

Make a refresh button to choose a different option on each randomly generated screen (screens 2 - 5).

Consider making the refresh button take less time than the initial generation.

Also add a 'Refresh All' button on the 'Play' screen. Split into two issues if it's too much.

UI bug: Bar disappears from screen on desktop

the word Bar (and subsequent bar number and total bar number) disappear off the screen when used in a wide desktop.

Resize the window from min to max width and you will see it disappearing.

Not sure if it's related but max-width: 580px; in the body (index.css) is not quite right as when you click the menu it comes in from the far right of the screen whereas it should be coming in from the edge of the app (580px from left). I've tried it in on html as well and it won't work.

Would like to have both of these fixed, but if someone can just short the 'bar' text as that's much more important and I'll raise a separate issue for the other issue if they can't be solved together.

Set up playwright

Set up playwright UI testing

The main things to test are:

  • When going through the screens. When the randomisers stop moving, take note of what they are and make sure they are the same as the current states (and states at the end).

  • Make sure when changing from quarter notes to eighth notes (etc), the change in the sound is instant.

  • Make sure stop / restart work as expected

  • Make sure chosen tempo is in the right range.

  • Make sure pattern string matches beat start point (if can access this)

Improve styling on play screen.

You currently have to scroll down (depending on phone size) to use the play screen correctly and see all the buttons. Stop this from happening by moving stuff up a little and potentially disabling scroll.

Test at different sizes.

Also make it generally a bit nicer to look at, using Mui buttons (instead of standard html buttons) for restart etc, so it looks consistent. Make the buttons nicely laid out, right now stuff has just been placed there.

Display visual metronome hints in lead up to fill sound.

Presently Every 4 (or 2 if you set it this way in settings) bars we have a fill (helper) sound playing on the metronome.

It would be nice if we had a visual queue that the helper sound is coming up.

For example.

If the helper sound is on beat 4 of bar 4. We should have beat 2 be red (instead of blue), beat 3 will be amber and beat 4 will be green.

As well as changing the colour we should change the border (in case somebody is colour blind).
The red beat would be e.g. twice as much border (make sure it's an internal border)
The amber beat would have a border that takes up a quarter of the box size
The green will take up, say 2 /3rds of the box size.

If the helper sound is on beat 1 of bar 4, then the 'countdown colours' would need to start on bar 3.

The (possibly) hard bit is this: In the near future we will allow for helper sounds to appear on the '&' or 'e' or 'a' of the beat (in between beats). This is already programmed in, but not called yet. They're called subdivisions.

So we need to account for this. So basically make sure subBeats are in the equation. So that if we have a beat on the & of 4. We would have the 'countdown colours' appear on the & of 2, the & of 3 and finally the & of 4. This is despite the fact that the notes would appear (blue) on beat.

Feel free to get in touch if this doesn't make much sense.

There should also be an option to remove this option from the settings as this may be distracting for some.

  • Change colour and style of the metronome blocks starting 2 before the helper sound. e.g. red, amber then green on the helper sound (then back to blue).
  • Make sure to account for subdivisions. To test this. Change line 58 (in the useEffect) of Metronome.tsx to playFillOn: { beat: fillStart as BeatPosition, subBeat: '4' }, - this will play the helper sound half a beat later. The 'countdown colours' should sync up to this. Please revert the subBeat back to 0 after you're done testing.
  • Add an option in the menu to remove this setting. Should be directly under the 'disable helper sound'. Call it 'disable helper visuals' or something.

This should all be possible (as far as I'm aware) in Metronome.tsx, mostly in the render function of the

Make tempoPreview class

Let me know @ninad-d if you can think of a better implementation before continuing. We can have a call if you like.

Here are my thoughts.

I've turned pattern.ts into an abstract class, mostly because I want to enforce the method getMetronomeString(). But we may want to use pattern directly at some point, so maybe it's not a great idea.

I think it's probably best to put a new abstract class ABOVE pattern. An abstract class called something like MetronomeStringBuilder with a single abstract method getMetronomeString(). This method is necessary on all classes related to the metronome so it must be enforced.

Currently it would need no other methods.

From this (MetronomeStringBuilder) we could make a new child class (on the same level as pattern) called tempoPreview or some such.

It would basically just need to return '1000100010001000' when the getMetronomeString() is called. That's all it would do for now. It could even be hard coded in.

This class is necessary for previewing tempos.

But the question is, does it make sense to use inheritance in this case? Or would some sort of composition be better? It's certainly not breaking any rules to do inheritance because the new parent will have less functionality,
but maybe it's overkill.

What do you think?

So the inheritance would look like this:
image

Bug: Slider functionality

The slider in step one is not as responsive as it should be, sometimes the handles slide to the wrong place (when used on an iphone13 mini, I'm not sure how many iphone types it affects).

This is actually an issue with the mui library. So it might worth replacing with something else until they fix this issue.

Extend patternMaker class

assigned to ninad

patternMaker class needs a parent class where most of the logic will live.
We also need a new child class.

  • Create parent class for patternMaker called patternMakerBase
  • Remove logic relating to countIn (from patternMakerBase) so it's only present in patternMaker
  • Remove logic relating to fills (from patternMakerBase) so it's only present in patternMaker
  • Remove singleton logic (so that multiple instances are possible) from patternMakerBase, but keep it in patternMaker, if possible. Let me know if it's not.
  • Make a new child (of patternMakerBase) called TempoPreviewMaker.
    The main issue:
  • Change the logic somehow so that the numbers used in the metronome strings (i.e. 1, 2, 3) are less fixed. Probably start by putting the defaults in the constructor instead of at the top of the class. Then do something else with the logic. Not sure what yet. Please see if you can come up with something. For example, the implementation of createMetronomeString includes a flag for isCountIn. I think the isCountIn should be separated and its own method. The result should be the same, an output string of only 1s and 0s. The TempoPreviewMaker should only output 1s and 0s when calling createMetronomeString, but of course it's currently hardcoded to output 1s 2s and 0s. Hope this makes sense. If not just ask

Add an option to change fill type every 4 bars

There should be an on/off switch (or similar, see mui libary) to enable/disable, regeneration of the fill type, every 4 bars.

It is currently disabled as the feature is not present.

When enabled, the fill type (e.g. more hats, less hats) will change every 4 bars or 8 bars for example.

tests.. more tests - EASY

If you love testing. Please write some more. Particularly for the patternMaker. I haven't yet thoroughly tested the different time sigs, except one or two and all of them manually.

Let's get the tests much more comprehensive.

Style for landscape mode

In the future we may consider adding "orientation": "portrait" to the manifest to block landscape mode, but it is not currently supported by Safari. So to keep it consistent between environments we should keep landscape as an option.

For this reason we should make landscape mode look better as there should be no need for scrolling etc, there is plenty of space for everything on the one screen. If it looks good we could even keep it long term (it may be handy for some folks too).

Refactor PatternMaker

Refactor the PatternMaker class so it uses create functions that are separate from the getters and setters, so it's clearer to follow the flow of logic and easier to build upon.

Also make it easier to transition to non 4/4 timings.

Add a time signature changer

Add ability to change time signature.

  • #2
  • Add Time Signature to patternMaker
  • Edit react-pro-metronome library to allow for different time signatures
  • Add tests for basic time sigs
  • Create custom dropdown menus so defaults are clear
  • Add dropdown menus for note divisions, timeSig top and bottom
  • Make time sig persist when restarting metronome.
  • Calculate and select PlayNotes defaults when changing bottom (edit: or top) half of time sig
  • Hide invalid options (e.g. quarters in 5/8)
  • Have correct number of red blocks per beats per bar
  • Add centered parameter for buttons which defaults to true. turn off for playNotes
  • Add highlight default parameter. Default to off (and use for the time signature halves, too confusing but very useful for subdivision).
  • Fix logic so that defaults are enforced on the string level (i.e. 5/8 should not be faster than 5/4)
  • Force default PlayNotes on countIn
  • Basic layout change. Hide steps after complete. max width 580. centered (so buttons display better) - and have PlayNotes on right hand side of timeSig
  • #18
  • Calculate Advice e.g. (first note only, half-time, double-time)
  • Fix stop reset bug

Block landscape orientation on phones

This is easy to do in the manifest, but it does not work for safari (and maybe not opera)?

But you can use media queries to detect orientation change. Until this is supported we should just have a blank screen with the text 'landscape mode not supported'.

Create a Splash Screen

A splash screen is needed for slower devices to display (instead of a blank screen) before the app has loaded.

I've noticed some times it even says 'react app' or something similar very quickly before the app loads (android).

Use the logo inside the assets folder as the splash screen.

If you need to assign a background colour. Use #076AE0 as it matches the logo.

Check this guide for android:
https://www.simicart.com/blog/pwa-splash-screen/#:~:text=The%20case%20for%20splash%20screens%20in%20PWAs,-When%20unconfigured%2C%20users&text=This%20should%20be%20fine%20on,initial%20perception%20of%20your%20app.

and for iphone:
https://appsco.pe/developer/splash-screens

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.