UNPKG

22.3 kBMarkdownView Raw
1# Waveform Playlist
2
3Inspired by [Audacity](http://audacity.sourceforge.net/), this project is a multiple track playlist editor written in ES2015 using the [Web Audio API](http://webaudio.github.io/web-audio-api/).
4
5[![npm](https://img.shields.io/npm/dm/waveform-playlist.svg)](https://www.npmjs.com/package/waveform-playlist)
6
7Load tracks and set cues (track cue in, cue out), fades (track fade in, fade out) and track start/end times within the playlist.
8I've written up some demos on github for the different [audio fade types](https://github.com/naomiaro/Web-Audio-Fades) in the project.
9
10- [See examples in action](http://naomiaro.github.io/waveform-playlist)
11- [Try out the waveform editor!](http://naomiaro.github.io/waveform-playlist/web-audio-editor.html)
12
13![Screenshot](img/stemtracks.png?raw=true "stem tracks mute solo volume control")
14(code for picture shown can be found in ghpages/\_examples/04stemtracks.html)
15
16![Screenshot](img/annotations.png?raw=true "Aeneas annotations adjust alignment json export")
17(code for picture shown can be found in ghpages/\_examples/13annotations.html)
18
19## Browser Support
20
21Waveform Playlist requires webaudio in the browser to function correctly: [Can I Use?](http://caniuse.com/#search=webaudio)
22
23## Installation
24
25`npm install waveform-playlist --save`
26
27Hate npm? Check Unpkg: https://unpkg.com/browse/waveform-playlist/
28
29- If you want to download and run the already compiled website, navigate to folder `/dist` and run `python -m SimpleHTTPServer 8000`. The website will be available at `localhost:8000/waveform-playlist`.
30
31## Basic Usage
32
33https://github.com/naomiaro/waveform-playlist/blob/main/examples/basic-html/
34
35https://github.com/naomiaro/waveform-playlist/tree/main/examples/basic-express/
36
37```javascript
38import WaveformPlaylist from "waveform-playlist";
39
40var playlist = WaveformPlaylist({
41 samplesPerPixel: 3000,
42 mono: true,
43 waveHeight: 70,
44 container: document.getElementById("playlist"),
45 state: "cursor",
46 colors: {
47 waveOutlineColor: "#E0EFF1",
48 timeColor: "grey",
49 fadeColor: "black",
50 },
51 controls: {
52 show: false,
53 width: 150,
54 },
55 zoomLevels: [500, 1000, 3000, 5000],
56});
57
58playlist
59 .load([
60 {
61 src: "media/audio/Vocals30.mp3",
62 name: "Vocals",
63 gain: 0.5,
64 },
65 {
66 src: "media/audio/BassDrums30.mp3",
67 name: "Drums",
68 start: 8.5,
69 fadeIn: {
70 duration: 0.5,
71 },
72 fadeOut: {
73 shape: "logarithmic",
74 duration: 0.5,
75 },
76 },
77 {
78 src: "media/audio/Guitar30.mp3",
79 name: "Guitar",
80 start: 23.5,
81 fadeOut: {
82 shape: "linear",
83 duration: 0.5,
84 },
85 cuein: 15,
86 },
87 ])
88 .then(function () {
89 // can do stuff with the playlist.
90 });
91```
92
93### Playlist Options
94
95```javascript
96var options = {
97 // webaudio api AudioContext
98 ac: new (window.AudioContext || window.webkitAudioContext)(),
99
100 // DOM container element REQUIRED
101 container: document.getElementById("playlist"),
102
103 // sample rate of the project. (used for correct peaks rendering)
104 sampleRate: new (
105 window.AudioContext || window.webkitAudioContext
106 ).sampleRate(),
107
108 // number of audio samples per waveform peak.
109 // must be an entry in option: zoomLevels.
110 samplesPerPixel: 4096,
111
112 // whether to draw multiple channels or combine them.
113 mono: true,
114
115 // enables "exclusive solo" where solo switches between tracks
116 exclSolo: false,
117
118 // default fade curve type.
119 fadeType: "logarithmic", // (logarithmic | linear | sCurve | exponential)
120
121 // whether or not to include the time measure.
122 timescale: false,
123
124 // control panel on left side of waveform
125 controls: {
126 // whether or not to include the track controls
127 show: false,
128
129 // width of controls in pixels
130 width: 150,
131
132 // whether to render the widget or not in the controls panel.
133 widgets: {
134 // Mute & solo button widget
135 muteOrSolo: true,
136
137 // Volume slider
138 volume: true,
139
140 // Stereo pan slider
141 stereoPan: true,
142
143 // Collapse track button
144 collapse: true,
145
146 // Remove track button
147 remove: true,
148 },
149 },
150
151 colors: {
152 // color of the wave background
153 waveOutlineColor: "white",
154
155 // color of the time ticks on the canvas
156 timeColor: "grey",
157
158 // color of the fade drawn on canvas
159 fadeColor: "black",
160 },
161
162 // height in pixels of each canvas element a waveform is on.
163 waveHeight: 128,
164
165 // width in pixels of waveform bars.
166 barWidth: 1,
167
168 // spacing between of waveform bars.
169 barGap: 0,
170
171 // interaction state of the playlist
172 // (cursor | select | fadein | fadeout | shift)
173 state: "cursor",
174
175 // (line | fill)
176 seekStyle: "line",
177
178 // Array of zoom levels in samples per pixel.
179 // Smaller numbers have a greater zoom in.
180 zoomLevels: [512, 1024, 2048, 4096],
181
182 // Whether to automatically scroll the waveform while playing
183 isAutomaticScroll: false,
184
185 // configuration object for the annotations add on.
186 annotationList: {
187 // Array of annotations in [Aeneas](https://github.com/readbeyond/aeneas) JSON format
188 annotations: [],
189
190 // Whether the annotation texts will be in updateable contenteditable html elements
191 editable: false,
192
193 // User defined functions which can manipulate the loaded annotations
194 controls: [
195 {
196 // class names for generated <i> tag separated by '.'
197 class: "fa.fa-minus",
198
199 // title attribute for the generated <i> tag
200 title: "Reduce annotation end by 0.010s",
201
202 // function which acts on the given annotation row
203 // when the corresponding <i> is clicked.
204 action: (annotation, i, annotations, opts) => {
205 // @param Object annotation - current annotation
206 // @param Number i - index of annotation
207 // @param Array annotations - array of annotations in the playlist
208 // @param Object opts - configuration options available
209 // - opts.linkEndpoints
210 },
211 },
212 ],
213
214 // If false when clicking an annotation id segment
215 // playback will stop after segment completion.
216 isContinuousPlay: false,
217
218 // If true annotation endpoints will remain linked when dragged
219 // if they were the same value before dragging started.
220 linkEndpoints: false,
221 },
222};
223```
224
225### Track Options
226
227```javascript
228{
229 // a media path for XHR, a Blob, a File, or an AudioBuffer object.
230 src: 'media/audio/BassDrums30.mp3',
231
232 // name that will display in the playlist control panel.
233 name: 'Drums',
234
235 // volume level of the track between [0-1]
236 gain: 1,
237
238 // whether the track should initially be muted.
239 muted: false,
240
241 // whether the track should initially be soloed.
242 soloed: false,
243
244 // time in seconds relative to the playlist
245 // ex (track will start after 8.5 seconds)
246 // DEFAULT 0 - track starts at beginning of playlist
247 start: 8.5,
248
249 // track fade in details
250 fadeIn: {
251 // fade curve shape
252 // (logarithmic | linear | sCurve | exponential)
253 shape: 'logarithmic',
254
255 // length of fade starting from the beginning of this track, in seconds.
256 duration: 0.5,
257 },
258
259 // track fade out details
260 fadeOut: {
261 // fade curve shape
262 // (logarithmic | linear | sCurve | exponential)
263 shape: 'logarithmic',
264
265 //length of fade which reaches the end of this track, in seconds.
266 duration: 0.5,
267 }
268
269 // where the waveform for this track should begin from
270 // ex (Waveform will begin 15 seconds into this track)
271 // DEFAULT start at the beginning - 0 seconds
272 cuein: 15,
273
274 // where the waveform for this track should end
275 // ex (Waveform will end at 30 second into this track)
276 // DEFAULT duration of the track
277 cueout: 30,
278
279 // custom class for unique track styling
280 customClass: 'vocals',
281
282 // custom background-color for the canvas-drawn waveform
283 waveOutlineColor: '#f3f3f3',
284
285 // interaction states allowed on this track.
286 // DEFAULT - all true
287 states: {
288 cursor: true,
289 fadein: true,
290 fadeout: true,
291 select: true,
292 shift: true,
293 },
294
295 // pre-selected section on track.
296 // ONLY ONE selection is permitted in a list of tracks, will take most recently set if multiple passed.
297 // This track is marked as 'active'
298 selected: {
299 // start time of selection in seconds, relative to the playlist
300 start: 5,
301
302 // end time of selection in seconds, relative to the playlist
303 end: 15,
304 },
305
306 // value from -1 (full left pan) to 1 (full right pan)
307 stereoPan: 0
308}
309```
310
311### Playlist Events
312
313Waveform Playlist uses an instance of [event-emitter](https://www.npmjs.com/package/event-emitter) to send & receive messages from the playlist.
314
315```javascript
316import EventEmitter from "event-emitter";
317import WaveformPlaylist from "waveform-playlist";
318
319var playlist = WaveformPlaylist(
320 {
321 container: document.getElementById("playlist"),
322 },
323
324 // you can pass your own event emitter
325 EventEmitter()
326);
327
328// retrieves the event emitter the playlist is using.
329var ee = playlist.getEventEmitter();
330```
331
332An example of using the event emitter to control the playlist can be found in [/dist/js/examples/emitter.js](https://github.com/naomiaro/waveform-playlist/blob/main/dist/waveform-playlist/js/emitter.js)
333
334#### Events to Invoke
335
336| event | arguments | description |
337| --------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
338| `play` | `start:optional, end:optional` | Starts playout of the playlist. Takes optional Number parameters in seconds `start` and `end` to play just an audio segment. `start` can be passed without an `end` to play to the end of the track. |
339| `pause` | _none_ | Pauses playout of the playlist. |
340| `stop` | _none_ | Stops playout of the playlist. |
341| `rewind` | _none_ | Stops playout if playlist is playing, resets cursor to the beginning of the playlist. |
342| `fastforward` | _none_ | Stops playout if playlist is playing, resets cursor to the end of the playlist. |
343| `clear` | _none_ | Stops playout if playlist is playing, removes all tracks from the playlist. |
344| `record` | _none_ | Starts recording an audio track. Begins playout of other tracks in playlist if there are any. |
345| `zoomin` | _none_ | Changes zoom level to the next smallest entry (if one exists) from the array `zoomLevels`. |
346| `zoomout` | _none_ | Changes zoom level to the next largest entry (if one exists) from the array `zoomLevels`. |
347| `trim` | _none_ | Trims currently active track to the cursor selection. |
348| `statechange` | `cursor` / `select` / `fadein` / `fadeout` / `shift` | Changes interaction state to the state given. |
349| `fadetype` | `logarithmic` / `linear` / `sCurve` / `exponential` | Changes playlist default fade type. |
350| `newtrack` | `File` | Loads `File` object into the playlist. |
351| `volumechange` | `volume, track` | Set volume of `track` to `volume` (0-100) |
352| `mastervolumechange` | `volume` | Set a new master volume `volume` (0-100) |
353| `select` | `start, end, track:optional` | Seek to the start time or start/end selection optionally with active track `track`. |
354| `startaudiorendering` | `wav` / `buffer` | Request for a downloadable file or web Audio buffer that represent the current work |
355| `automaticscroll` | `true`/`false` | Change property `isAutomaticScroll`. |
356| `continuousplay` | `true`/`false` | Change property `isContinuousPlay`. |
357| `linkendpoints` | `true`/`false` | Change property `linkEndpoints`. |
358| `annotationsrequest` | _none_ | Requests to download the annotations to a json file. |
359| `stereopan` | `panvalue, track` | Set pan value of `track` to `panvalue` (-1-1) |
360
361#### Events to Listen to
362
363| event | arguments | description |
364| ------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
365| `select` | `start, end, track` | Cursor selection has occurred from `start` to `end` with active Track `track`. |
366| `timeupdate` | `playbackPosition` | Sends current position of playout `playbackPosition` in seconds. |
367| `scroll` | `scrollLeft` | Sends current position of scroll `scrollLeft` in seconds. |
368| `statechange` | `state` | Sends current interaction state `state`. |
369| `shift` | `deltaTime, track` | Sends `deltaTime` in seconds change for Track `track` |
370| `mute` | `track` | Mute button has been pressed for `track` |
371| `solo` | `track` | Solo button has been pressed for `track` |
372| `removeTrack` | `track` | Remove button has been pressed for `track` |
373| `changeTrackView` | `track, opts` | Collapse button has been pressed for `track` |
374| `volumechange` | `volume, track` | Volume of `track` has changed to `volume` (0-100) |
375| `mastervolumechange` | `volume` | Master volume of the playlist has changed to `volume` (0-100) |
376| `audiorequeststatechange` | `state, src` | Loading audio `src` (`string` or `File`) is now in state [`state`](https://github.com/naomiaro/waveform-playlist/wiki/Track-Loading-States) (Number) |
377| `loadprogress` | `percent, src` | Loading audio `src` has loaded percent `percent` (0-100) |
378| `audiosourcesloaded` | _none_ | Audio decoding has finished for all tracks |
379| `audiosourcesrendered` | _none_ | Tracks are rendered to the playlist |
380| `audiosourceserror` | `err` | Error thrown while loading tracks |
381| `finished` | _none_ | Event fired when cursor ( while playing ) reaches the end (maximum duration) |
382| `audiorenderingfinished` | `type, data` | Return the result of the rendering in the desired format. `type` can be `buffer` or `wav` and can be used to dertermine the `data` type. When `type` is `wav`, data is a `blob` object that represent the wav file. |
383| `stereopan` | `panvalue, track` | Pan value of `track` has been changed to `panvalue` |
384
385## Tests
386
387`npm test`
388
389## Development without example changes
390
391`npm install && npm start`
392
393This will install dependencies and start the webpack server.
394
395## Development with example changes
396
397`gem install jekyll`
398
399Jekyll is needed if changes to the example pages will be done.
400
401`npm install && npm run dev`
402
403This will build and watch the jekyll site and startup the webpack dev server.
404
405## Credits
406
407Originally created for the [Airtime](https://www.sourcefabric.org/software/airtime/) project at [Sourcefabric](https://www.sourcefabric.org/)
408
409The annotation plugin has been sponsored by a fond Italian TED volunteer transcriber, hoping to make easier and more fun the transcription process of TEDx talks.
410
411## License
412
413[MIT License](http://doge.mit-license.org)