Name: peaks.js
Owner: BBC
Description: JavaScript UI component for interacting with audio waveforms
Created: 2013-10-14 12:53:33.0
Updated: 2018-01-16 19:41:51.0
Pushed: 2018-01-16 17:25:20.0
Homepage: http://waveform.prototyping.bbc.co.uk
Size: 94145
Language: JavaScript
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
A browser based audio waveform visualisation frontend component from BBC R&D.
Peaks.js is a modular client-side JavaScript component designed for the display of and interaction with audio waveforms in the browser.
Peaks.js was developed by BBC R&D to allow users to make accurate clippings of audio content in the browser, using a backend API that serves the waveform data.
Peaks.js uses HTML5 canvas technology to display waveform at different zoom levels and provides some basic convenience methods for interacting with waveforms and creating time-based visual sections for denoting content to be clipped or for reference, eg: distinguishing music from speech or identifying different music tracks.
You can read more about the project here.
npm install --save peaks.js
bower install --save peaks.js
http://wzrd.in/standalone/peaks.js
https://cdnjs.com/libraries/peaks.js
Peaks.js can be included in any web page by following these steps:
id="peaks-container"></div>
io>
ource src="test_data/sample.mp3" type="audio/mpeg">
ource src="test_data/sample.ogg" type="audio/ogg">
dio>
ipt src="bower_components/requirejs/require.js" data-main="app.js"></script>
AMD modules work out of the box without any optimiser.
n app.js
onfigure peaks path
irejs.config({
ths: {
peaks: 'bower_components/peaks.js/src/main',
EventEmitter: 'bower_components/eventemitter2/lib/eventemitter2',
Konva: 'bower_components/konvajs/konva',
'waveform-data': 'bower_components/waveform-data/dist/waveform-data.min'
equire it
ire(['peaks'], function(Peaks) {
r p = Peaks.init({
container: document.querySelector('#peaks-container'),
mediaElement: document.querySelector('audio'),
dataUri: 'test_data/sample.json'
;
on('peaks.ready', function() {
// do something when the waveform is displayed and ready
;
A working example is provided in index.html
.
This works well with systems such as Meteor, webpack and browserify (with babelify transform).
rt Peaks from 'peaks.js';
t p = Peaks.init({ ? });
This works well with systems such as Meteor, webpack and browserify.
Peaks = require('peaks.js');
p = Peaks.init({ ? });
ipt src="node_modules/peaks.js/peaks.js"></script>
ipt>
ction(Peaks) {
r p = Peaks.init({ ? });
eaks);
ript>
Peaks.js uses waveform data files produced by audiowaveform. These can be generated in either binary (.dat) or JSON format. Binary format is preferred because of the smaller file size, but this is only compatible with browsers that support Typed Arrays.
You should also use the -b 8
option when generating waveform data files, as Peaks.js does not currently support 16-bit waveform data files, and also to minimise file size.
To generate a binary waveform data file:
owaveform -i sample.mp3 -o sample.dat -b 8
To generate a JSON format waveform data file:
owaveform -i sample.mp3 -o sample.json -b 8
Refer to the man page audiowaveform(1) for full details of the available command line options.
Since 0.3.0
, Peaks.js can use the Web Audio API to generate waveforms, which means you would not have to pre-generate a dat
or json
file beforehand.
To do so, omit the dataUri
option and make sure you pass in a valid AudioContext
instance as the audioContext
option. You may also want to make sure your browser is compatible with Web Audio.
myAudioContext = new AudioContext();
p = Peaks.init({
ntainer: document.querySelector('#peaks-container'),
diaElement: document.querySelector('audio'),
dioContext: myAudioContext
('peaks.ready', function() {
do something when the waveform is displayed and ready
Notice: be aware it can be CPU intensive if your audio file has a long duration.
The available options for configuration of the viewer are as follows:
options = {
* REQUIRED OPTIONS **/
Containing element
ntainer: document.getElementById('peaks-container'),
HTML5 Media element containing an audio track
diaElement: document.querySelector('audio'),
* Optional config with defaults **/
URI to waveform data file in binary or JSON
taUri: {
arraybuffer: '../test_data/sample.dat',
json: '../test_data/sample.json',
If true, peaks will send credentials with all network requests
i.e. when fetching waveform data.
thCredentials: false,
A Web Audio AudioContext instance which can be used
to render the waveform if dataUri is not provided
dioContext: new AudioContext(),
async logging function
gger: console.error.bind(console),
default height of the waveform canvases in pixels
ight: 200,
Array of zoom levels in samples per pixel (big >> small)
omLevels: [512, 1024, 2048, 4096],
Bind keyboard controls
yboard: false,
Keyboard nudge increment in seconds (left arrow/right arrow)
dgeIncrement: 0.01,
Colour for the in marker of segments
MarkerColor: '#a0a0a0',
Colour for the out marker of segments
tMarkerColor: '#a0a0a0',
Colour for the zoomed in waveform
omWaveformColor: 'rgba(0, 225, 128, 1)',
Colour for the overview waveform
erviewWaveformColor: 'rgba(0,0,0,0.2)',
Colour for the overview waveform rectangle
that shows what the zoom view shows
erviewHighlightRectangleColor: 'grey',
Colour for segments on the waveform
gmentColor: 'rgba(255, 161, 39, 1)',
Colour of the play head
ayheadColor: 'rgba(0, 0, 0, 1)',
Colour of the play head text
ayheadTextColor: '#aaa',
Show current time next to the play head
(zoom view only)
owPlayheadTime: false,
the color of a point marker
intMarkerColor: '#FF0000',
Colour of the axis gridlines
isGridlineColor: '#ccc',
Colour of the axis labels
isLabelColor: '#aaa',
Random colour per segment (overrides segmentColor)
ndomizeSegmentColor: true,
Zoom view adapter to use. Valid adapters are:
'animated' (default) and 'static'
omAdapter: 'animated',
Array of initial segment objects with startTime and
endTime in seconds and a boolean for editable.
See below.
gments: [{
startTime: 120,
endTime: 140,
editable: true,
color: "#ff0000",
labelText: "My label"
startTime: 220,
endTime: 240,
editable: false,
color: "#00ff00",
labelText: "My Second label"
,
Array of initial point objects
ints: [{
time: 150,
editable: true,
color: "#00ff00",
labelText: "A point"
time: 160,
editable: true,
color: "#00ff00",
labelText: "Another point"
The marker and label Konva.js objects may be overridden to give the segment markers or label your own custom appearance (see main.js / waveform.mixins.js, Konva Polygon Example and Konva Text Example):
gmentInMarker: mixins.defaultInMarker(p.options),
gmentOutMarker: mixins.defaultOutMarker(p.options),
gmentLabelDraw: mixins.defaultSegmentLabelDraw(p.options)
The top level Peaks
object exposes a factory function to create new Peaks
instances.
Peaks.init(options)
Returns a new Peaks
instance with the assigned options. You can create and manage several Peaks
instances within a single page with one or several configurations.
peaksInstance = Peaks.init({ ? });
secondPeaksInstance = Peaks.init({ ? });
instance.player.play()
Starts media playback, from the current time position.
instance = Peaks.init({ ? });
ole.log(instance.player.play());
instance.player.pause()
Pauses media playback.
instance = Peaks.init({ ? });
ole.log(instance.player.pause());
instance.player.getCurrentTime()
Returns the current time from the associated media element, in seconds.
instance = Peaks.init({ ? });
ole.log(instance.player.getCurrentTime()); // -> 0
instance.player.seek(time)
Seeks the media element to the given time, in seconds.
instance = Peaks.init({ ? });
ance.player.seek(5.85);
ole.log(instance.player.getCurrentTime()); // -> 5.85
instance.player.playSegment(segment)
Plays a given segment of the media.
instance = Peaks.init({ ? });
segment = instance.segments.add({
artTime: 5.0,
dTime: 15.0,
itable: true
lays from 5.0 to 15.0, then stops.
ance.player.playSegment(segment);
instance.zoom.zoomOut()
Zooms in the waveform zoom view by one level.
instance = Peaks.init({ ?, zoomLevels: [512, 1024, 2048, 4096] });
ance.zoom.zoomOut(); // zoom level is now 1024
instance.zoom.zoomIn()
Zooms in the waveform zoom view by one level.
instance = Peaks.init({ ?, zoomLevels: [512, 1024, 2048, 4096] });
ance.zoom.zoomIn(); // zoom level is still 512
ance.zoom.zoomOut(); // zoom level is now 1024
ance.zoom.zoomIn(); // zoom level is now 512 again
instance.zoom.setZoom(index)
Sets the zoom level to the element in the options.zoomLevels
array at index index
.
instance = Peaks.init({ ?, zoomLevels: [512, 1024, 2048, 4096] });
ance.zoom.setZoom(3); // zoom level is now 4096
instance.zoom.getZoom()
Returns the current zoom level, as an index into the options.zoomLevels
array.
instance = Peaks.init({ ?, zoomLevels: [512, 1024, 2048, 4096] });
ance.zoom.zoomOut();
ole.log(instance.zoom.getZoom()); // -> 1
Segments give the ability to visually tag timed portions of the audio media. This is a great way to provide visual cues to your users.
instance.segments.add({startTime, endTime, editable, color, labelText, id})
instance.segments.add(segment[])
Adds a segment to the waveform timeline. Accepts the following parameters:
startTime
: the segment start time (seconds)endTime
: the segment end time (seconds)editable
: (optional) sets whether the segment is user editable (boolean, defaults to false
)color
: (optional) the segment color. If not specified, the segment is given a default color (see the segmentColor
and
randomizeSegmentColor
options).labelText
: (option) a text label which is displayed when the user hovers the mouse pointer over the segment.id
: (optional) the segment identifier. If not specified, the segment is automatically given a unique identifier.instance = Peaks.init({ ? });
dd non-editable segment, from 0 to 10.5 seconds, with a random color
ance.segments.add({startTime: 0, endTime: 10.5});
Alternatively, provide an array of segment objects to add all those segments at once.
instance = Peaks.init({ ? });
ance.segments.add([
startTime: 0,
endTime: 10.5,
labelText: '0 to 10.5 seconds non-editable demo segment'
startTime: 3.14,
endTime: 4.2,
color: '#666'
instance.segments.getSegments()
Returns an array of all segments present on the timeline.
instance.segments.getSegment(id)
Returns the segment with the given id, or null
if not found.
instance.segments.removeByTime(startTime[, endTime])
Removes any segment which starts at startTime
(seconds), and which optionally ends at endTime
(seconds).
The return value indicates the number of deleted segments.
instance = Peaks.init({ ? });
ance.segments.add([{ startTime: 10, endTime: 12 }, { startTime: 10, endTime: 20 }]);
emove both segments as they start at `10`
ance.segments.removeByTime(10);
emove only the first segment
ance.segments.removeByTime(10, 12);
instance.segments.removeById(segmentId)
Removes segments with the given identifier.
instance = Peaks.init({ ? });
ance.segments.removeById('peaks.segment.3');
instance.segments.removeAll()
Removes all segments.
instance = Peaks.init({ ? });
ance.segments.removeAll();
Points give the ability to visually tag points in time of the audio media.
instance.points.add({time, editable, color, labelText, id})
instance.points.add(point[])
Adds one or more points to the waveform timeline. Accepts the following parameters:
time
: the point time (seconds)editable
: (optional) sets whether the point is user editable (boolean, defaults to false
)color
: (optional) the point color. If not specified, the point is given a default color (see the pointMarkerColor
option).labelText
: (optional) a text label which is displayed next to the segment. If not given, the point's time is displayed.id
: (optional) the point identifier. If not specified, the point is automatically given a unique identifier.instance = Peaks.init({ ? });
dd non-editable point, with a random color
ance.points.add({ time: 3.5 });
Alternatively, provide an array of point objects to add several at once.
instance = Peaks.init({ ? });
ance.points.add([
time: 3.5,
labelText: 'Test point',
color: '#666'
time: 5.6,
labelTect: 'Another test point',
color: '#666'
instance.points.getPoints()
Returns an array of all points present on the timeline.
instance.points.getPoint(id)
Returns the point with the given id, or null
if not found.
instance.points.removeByTime(time)
Removes any point at the given time
(seconds).
instance = Peaks.init({ ? });
ance.points.removeByTime(10);
instance.points.removeById(pointId)
Removes points with the given identifier.
instance = Peaks.init({ ? });
ance.points.removeById('peaks.point.3');
instance.points.removeAll()
Removes all points.
instance = Peaks.init({ ? });
ance.points.removeAll();
instance.destroy()
Releases resources used by an instance. This can be useful when reinitialising Peaks.js within a single page application.
instance = Peaks.init({ ? });
ater:
ance.destroy();
Peaks instances emit events to enable you to extend its behaviour according to your needs.
| Event name | Arguments |
| ————————- | ————— |
| error
| Error err
|
| Event name | Arguments |
| —————————– | ————- |
| peaks.ready
| (none) |
| segments.ready
(deprecated) | (none) |
| user_seek.overview
| Number time
|
| user_seek.zoomview
| Number time
|
| Event name | Arguments |
| ————————- | —————————————————– |
| zoom.update
| Number currentZoomLevel
, Number previousZoomLevel
|
| Event name | Arguments |
| ————————- | ————————- |
| segments.add
| Array<Segment> segments
|
| segments.remove
| Array<Segment> segments
|
| segments.remove_all
| (none) |
| segments.dragged
| Segment segment
|
| Event name | Arguments |
| ————————- | ——————— |
| points.add
| Array<Point> points
|
| points.remove
| Array<Point> points
|
| points.remove_all
| (none) |
| points.dragged
| Point point
|
You might want to build a minified standalone version of Peaks.js, to test a contribution or to run additional tests. The project bundles everything you need to do so.
clone git@github.com:bbc/peaks.js.git
eaks.js
install
This command will produce a UMD-compatible minified standalone version of Peaks.js, which allows you to use it with AMD or CommonJS module loaders, or even as vanilla JavaScript.
run build
The output of the build is a file named peaks.js
, alongside its associated source map.
This command will serve a local demo page containing a single Peaks instance. Look at the file index.html to see an example of Peaks.js in use.
start
Then open http://localhost:9000 in a Web browser.
npm test
should work for simple one time testing.
If you are developing and want to repeatedly run tests in a browser on your machine simply launch npm run test-watch
.
See COPYING.
This project includes sample audio from the radio show Desert Island Discs, used under the terms of the Creative Commons 3.0 Unported License.
Copyright 2017 British Broadcasting Corporation