This is a list of things that we hope to accomplish with p5.sound. If you want to work on one of these, or discuss an idea, feel free to make a github issue. Got something to add to the list? We'd love to hear it!
- Incorporate the new Stereo Panner Node, with a fallback to the existing panner for browsers that don't yet support StereoPanner.
- p5.Amplitude normalize method should be dynamic. It can accept a parameter that determins how fast it decays.
- Figure out a way to keep track of connections between objects. From there, .disconnect() can accept a specific object rather than disconnecting all output.
- Make sure all methods that should be modular can accept a Number, AudioParam, p5.Envelope, p5.Oscillator or p5.Signal as input.
- Log a message to the console if a user calls FFT methods like getEnergy without first calling .analyze() in either the draw loop, or in the method in which they call getEnergy. Maybe log the time that .analyze was last called, and compare it to the current time, and if it is a big gap, then log the message?
- SoundFile.playMode('untilDone') would play a sound if not already playing, but if it is already playing, it would not play again until it is done. Feel free to re-open this Github Issue if you want to work on this.
- Improve p5.Pulse (PWM)
- What additional features/analysis would be useful for visualization / analysis? Look into handling these with an offline audio context, and/or scripts that could analyze a file and then save the result to JSON.
- Peak Detect https://github.com/processing/p5.js-sound/issues/12
- Beat Detect -- here's an example handled by an offline audio context
- Pitch detect -- here's an example.
- Enhance the examples from p5 music viz workshop repo and make these more accessible, perhaps as a section of p5js.org. Some useful examples to add:
- Creating and working w/ lyric files (LRC) or other timestamped data
- Synthesizing musical patterns (i.e. with p5.Part) and mapping these to visuals
- Using the p5.dom library to add a drag-and-drop area for mp3s (examples currently use custom dragfile.js)
- Loading music to p5.SoundFile from external API’s
- Build a prototype for a p5.Synth.
- Pubilsh a spec for how synths should behave that enables people to add/share their own instruments.
- Figure out how to handle voice allocation.
- Including some nice sounding custom oscillator periodicwaves
- Build out current effects and develop new ones.
- Publish a spec so that people can easily share/add custom effects
- How best to apply an effect like p5.Reverb to all sound in the sketch? Perhaps p5.soundOut gets a wet/dry effects bus.
- Mixer and Wet/Dry
- Prepare to implement the AudioWorker, because ScriptProcessor will soon be depricated. We'll likely need a fallback during this transition.
-
Write tests and benchmark performance.
-
Custom callbacks for error in getUserMedia when it is not available (i.e. in Safari)
-
Documentation:
- Make sure there are no looping sounds in the reference examples.
- Lower amplitude on all examples
-
Update p5.FFT API to reflect changes in the Processing Sound FFT API
-
Add option to p5.FFT that returns data in decibels (from Float32Array)
-
p5.Envelope should be able to connect to multiple
-
p5.Envelope takes no action on triggerRelease unless currently playing
-
Add a logarithmic scaling option for p5.FFT
-
p5.SoundFile.getPeaks should be able to return stereo peaks. Like this
-
Add the ability to decode audio buffer data from a FileReader and add it to a p5.SoundFile buffer, like this
-
Add ability to map a soundfile playback rate to a pitch ratio, like this
-
when a soundFile is reversed, reverse currentTime as well for accurate playback position
-
add an 'onended' function to SoundFile.bufferSourceNode that toggles _playing to false when done playing
AFTER HERE, COPIED FROM WIKI PAGE ON 2023-02-18
- Clone this repo and navigate to within the
p5.js-sound
folder. You can typecd
(change directory) and then drag the folder into the terminal window to copy the address of the folder. - Install the following dependencies:
- Run
npm install
from the command line. This downloads the node modules that we use to build thep5.sound.js
file from the source files in the/src
folder, as well as modules used for running tests and other tasks. - Run
grunt
from the command line to compile the library. This will update the p5.sound.js and p5.sound.min.js files in the/lib
directory with any changes from the/src
directory.
-
lib/
Contains the concatenated p5.sound.js and p5.sound.min.js libraries, generated by Grunt. -
src/
Contains all the source code for the library. The code is broken up into folders and files corresponding with the Processing reference page. Additionally, there is a core folder that holds constants, and internal helper functions and variables. -
tests/
Contains unit testing files. -
examples/
Contains code examples including a port of all of Dan Shiffman's Learning Processing, as well as an empty-empty example that demonstrates setting up a sketch, and examples related to specific tutorials.
Once you are set up, you can make changes in a variety of ways:
-
Adding features Simply find the module you want to edit by looking for its files in the
/src
folder. Then, re-build the library by callinggrunt
from the command line when you are ready to try out your changes. -
Writing documentation
p5.js-sound
uses inline documentation. A good example for how to format and write inline documentation can be seen in p5.Oscillator. -
Writing automatic tests More information below.
Ideally, all new functions will be implemented with unit tests and inline documentation. Examples of unit tests can be found in the tests directory. Directions for adding your own tests and including them are below.
The testing is done with the mocha test framework and by running the tests in a browser window.
To get started:
- Install dependencies.
cd p5.js-sound/ npm install
- Add test files corresponding to files in
src
(more info about Chai assert style TDD phrasing here). - Register your new test files by adding their names to the
allTests
array intest.js
. - Run the tests in the browser (see below).
It is useful to run tests in the browser, especially when trying to debug test failures on different browsers. To run the tests in the browser:
- Run the connect server.
grunt serve
orpython -m SimpleHTTPServer
- Open
localhost:8000/test
in your favourite web browser, or multiple browsers.
We use eslint to help with code styling and conventions. The goal is to have some consistent styles that nudge all contributors towards good standards/best practices without the need to get nitpicky in code review. It is optional for now, but should be helpful for developers who choose to use it.
Linting rules are in this file: src/.eslintrc
.
- Install eslint:
npm install -g eslint
. If necessary, update dependencies usingnpm install
. - Run
grunt lint
to lint the entiresrc/
directory (displays linting errors in the directory). - You can auto-fix errors on the terminal, with the optional
--fix
flag that will fix some (but not all) linting errors. For example, to fix the errors insrc/audioin.js
, runeslint src/audioin.js --fix
which will fix all the auto-fixable errors in that file. - Alternatively (or for the non-auto-fixable errors), you can open those files and fix those errors manually.
- Install System Tools:
- Fork, Clone, Configure Remotes, Install Dependencies
- Fork https://github.com/processing/p5.js-sound to your github account.
- Clone your fork of the repo from Terminal:
git clone --depth=50 https://github.com/<your-username>/p5.js-sound
- Navigate to the newly cloned directory:
cd p5.js-sound
- Add a reference to the original repo as a remote called "upstream":
git remote add upstream https://github.com/processing/p5.js-sound
- Install Dependencies:
npm install
--> This creates a folder called "node_modules" with all the dependencies listed in "package.json"
- Get Latest Changes ^
- If you cloned a while ago, get the latest changes from upstream:
git checkout main
--> switch to your "main" branchgit pull upstream main
--> pull changes from the "main" branch of the remote repo we called "upstream"
- If you cloned a while ago, get the latest changes from upstream:
- Create a new branch ^
git checkout -b <topic-branch-name>
-b
creates the branchcheckout
makes this your current branch. Updates all the files to reflect whatever’s in that branchcheckout -b
does both at the same time.- This is a good idea in case your PR is not accepted right away, and you want to work on something else in the meantime. Because any commits you make to a branch with an unresolved pull requests will be added to the pull request.
- Make Some Edits...
- p5.sound.js and p5.sound.min.js are built from the modules in the /src folder. Edit your module(s)
grunt
--> builds new version of the library. Also runs a bunch of other tasks defined in Gruntfile.js, including jshint which enforces these style guidelines.grunt watch
--> every time you save, grunt re-builds the library- Recommended: create an example in the /examples folder to manually test whatever you're working on if it is a bug fix or new feature. You may consider adding this as an example, or leave it out when you commit changes.
- Write Automated Tests ^
- Tests live in "test/unit/<unit_name>" and are linked via "test/test.html"
- More info on Testing with p5.js
- Document Changes ^ Info here
- Commit Your Changes
git add <files you want to include>
git commit -m <your short commit message>
- Commit messages should explain what change(s) you made in the imperitive tense, i.e. "fix bug with ellipse"
- If you have a messy commit history, you can use git rebase to tidy up before sending the pull request.
- Locally Merge (or rebase) Upstream Changes ^
git pull upstream main
--> merge your changes with upstream changes- Or,
git pull --rebase upstream main
--> applies your changes ontop of the upstream changes
- Push To Your Fork
git push origin <topic-branch-name>
- Open Pull Request to p5.sound main branch
- GitHub info on Creating & Using Pull Requests
- Clear description of changes, clear title, imperative tense (i.e. "fix bug")
- Discuss & Amend Pull Request
- Pull Requests can be discussed, just like issues example
- Pull Requests are not static snapshots of your repo. They update whenever you add more commits to the branch, until the PR is accepted.
^ These are optional, but recommended, and sometimes these things (like adding documentation) encompass your entire contribution.
git remote -v
List all your remotes "verbosely"git pull <name_of_the_remote> <branch_name>
git push <name_of_the_remote> <branch_name>
git checkout -b <topic-branch-name>
Create a new branch and check it outgit stash
Stash all uncommitted changes you’ve made to the branch. You can get them back later.git commit --amend
Amend your previous commit rather than creating a new commit
DOCUMENTATION
The documentation that appears at https://p5js.org/reference/#/libraries/p5.sound is all generated automatically from inline comments. This happens once a new version of the p5.sound library is merged into the p5.js repo and included in a release.
-
Clone the p5.js-sound repo and install all packages.
-
Build a new version of
p5.sound.js
by runninggrunt
in the p5.js-sound repo. -
Move that file to your local p5.js repo, replacing
p5.js/lib/addons/p5.sound.js
-
Now that the p5.sound.js file is in the p5.js repo, follow the instructions here for generating documentation in the p5.js repo:
Run
grunt yui:build
once first to generate all local files neededTo preview it locally, run
grunt yui:dev
and view it as http://localhost:9001/docs/reference/.(p5.js-sound documentation will appear at http://127.0.0.1:9001/docs/reference/#/libraries/p5.sound)
--OR-- use this node.js script that attempts to automate ^.
--OR-- use this node.js script if you want to bring in the p5.js-website repo, too.
Releasing a new version of p5.sound library
Here's how to release a new version of the p5.sound library
-
Compile new versions of the library and set the new version number according to semver
- Version can be updated in package.json before compiling
-
Verify that Reference web pages look ok on the p5.js-website when using the newly compiled library (instructions here)
-
Draft a new release https://github.com/processing/p5.js-sound/releases
- Mention all relevant fixes and changes that are included since the last release (with links to PR’s and shoutouts to contributors as applicable) - use this filter to figure out what has happened since the most recent release: https://github.com/processing/p5.js-sound/pulls?q=is%3Apr+is%3Amerged
- Example: https://github.com/processing/p5.js-sound/releases/tag/0.3.12
- Attach p5.sound.js and p5.sound.min.js files with the new version numbers
-
Make a PR to p5.sound with the newly compiled /lib directory and the description of the release
-
Publish the release!
-
Make a PR to p5.js replacing with the newly compiled p5.sound.js and p5.sound.min.js files. Include a description of the release in the PR
-
Make a PR to p5.js-website replacing with the newly compiled p5.sound.js and p5.sound.min.js files. Include a description of the release in the PR
-
...wait for a new release of p5.js to include our updated version (see https://github.com/processing/p5.js/blob/main/contributor_docs/release_process.md )
Unit Testing in p5.js sound
Unit test is a way of testing a unit - the smallest piece of code that can be logically isolated in a system. Unit tests are vital to a codebase as they ensure that individual components work as intended. They not only make the code more consistent but also ensures that any addition of new code won’t break the existing one.
You can refer to this article for a good intro to unit testing.
In this page, you will learn about the unit testing architecture of this library and also about how to run the tests. You will also learn how to contribute to the library's testing by adding new unit tests.
To run the tests, you need to clone the library into your local computer. You can follow these instructions to setup.
Once the setup is done, open the terminal and go to the root directory
cd p5.js-sound
Once you are in the repo's root, use the following command to run the tests in your terminal
grunt test
You can learn about the different types of testing environments here.
While writing your own tests, testing only one test case or only one suite will come in handy.
To run only a single test or suite, you can append .only
to the function.
For example,
to test only one suite, say delay.js
, you can change the describe statement in test/tests/p5.Delay.js
from
describe('p5.Delay', function () {
// some test cases
});
to
describe.only('p5.Delay', function () {
// some test cases
});
Similarly to run only one test, you can change the it
function of that test to
it.only('', function () {});
You can read more about this here
This feature is the inverse of .only()
.
Some times, when you are unsure of a test case or a suite, you can skip that test/suite by using skip
.By appending .skip()
, you may tell Mocha to ignore test case(s)
You can read more about this here
You can see the file structure of the testing folder below :
-
Everything related to the testing is located in the
/test
folder. -
All the tests are located in the
/test/tests
folder.- If you are trying to add a new test file, make sure it follows the existing conventions.
For example, if you want to write tests for/src/audiocontext.js
, the test file should be named asp5.AudioContext.js
(except main.js), - keep in mind that file name should follow CamelCasing
- If you are trying to add a new test file, make sure it follows the existing conventions.
-
All the audio samples, that are used in testing are located in the
/test/testAudio
folder. -
All the grunt tasks need for test automation are located in the
/test/tasks
folder. -
The setup and some configuration options to run the tests are created in
/test/setup.js
file. -
All the test files are added to the
spec
array in/test/tests.js
file.
- We use mocha for structuring and running our unit tests.
- We use chai's assert (and expect) to write individual statements about how code should behave.
- We use puppeteer to run headless tests.
- We also use karma-js to run headless tests.
We can run the tests in 3 environments.
It is useful to run tests in the browser, especially when trying to debug test failures on different browsers. To run the tests in the browser:
- Run the connect server.
grunt serve
orpython -m SimpleHTTPServer
- Open
localhost:8000/test
in your favourite web browser, or multiple browsers.
Optionally, you can also run npm run dev
so that the library is updated while you are coding and also the server stay connected.
The code for the testing in browser can be found in test/index.html
You can learn more about running mocha in browser here
You can run tests in the terminal using headless chrome so that you do not have to open a browser. You can also see the status of the tests being run in the terminal.
To run the tests in headless chrome, you can use the following command in the terminal:
grunt test
The code for testing in headless chrome can be found in test/tasks/mocha-chrome.js
which is loaded as a grunt test and test/headless-test.html
You can also run tests in the terminal using karma-js. The difference between this environment and the headless chrome is that the test files are bundled using webpack while using karma. So, the tests are more consistent while run using karma. Hence, we can use this method to automate in github continuous integration in future.
You cannot see the status of tests while running the tests in this method.
To run the tests using karma, you can use the following command in the terminal:
npm run karma
The code for testing in headless chrome can be found in root folder, karma.conf.js
.
If you want to write new unit tests to the library, check if there already exists a test file for the file you want to test.
For example, if you want to write tests for a function in src/fft.js
, check if there is a file in the test/tests
folder called p5.FFT.js
. If not, you can add the file and be the first to test that file.
If you have added a new file for testing, you also have to add that file in the spec
array in test/tests.js
file for it to run with all other tests.
If you are adding a new file for testing, another point to keep in mind is that you have to follow the existing conventions of writing tests to maintain consistency across the library, which are:
- You have to include the file name in the
describe
function. - You have to include the expected behaviour of the test behaviour in
it
function.- You have to write the behaviour so that the sentence makes sense when reading it together with 'it'.
- For example, if you are testing if a function can start and stop an audio node, the
it
function should be
it('can be started and stopped', function () {});
- As you can see the sentence 'it can be started and stopped' makes sense
- If you are testing a Class, you can add another level of suite which tests all the methods of that class, which can be found in almost all the files
To demonstrate, let's take the file src/effect.js
. To add tests to this file, we first check the test/tests
folder if there is a file for effect.js
. If not, we create a file called p5.Effect.js
in this folder. We should also remember to add this file in the spec
array in test/tests.js
.
Now, lets add tests to a function called drywet
in this file. To do that, we need to understand the functionality of that function.
Expected Behaviour: It takes one argument, the desired dry/wet value. If the value is passed, it sets the dry/wet value and returns the value set. If value is not passed, it simply returns the existing dry/wet value. The initial value of dry/wet is 1.
So, the possible test cases can be:
- Initially when no argument is passed, it should return 1
- If a value is passed, it should set the value to that value.
- If dry/wet value is set and no argument is passed, it should return that value.
- If you can think of more, go ahead and add tests for them!
Now, to test these functions,
We can create a test suite in p5.Effect.js
to test this method. So, after adding these tests, the test file may look like this:
describe('p5.Effect', function () {
describe('drywet', function () {
it('should have an initial value of 1', function () {
// write test here
});
it('can set the drywet value', function () {
// write test here
});
it('can return the drywet value', function () {
// write test here
});
})
)}