this negation needs parens.
[mediagoblin.git] / mediagoblin / static / js / audio.js
CommitLineData
a9d84d4c
JW
1/**
2 * GNU MediaGoblin -- federated, autonomous media hosting
3 * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19var audioPlayer = new Object();
20
21(function (audioPlayer) {
22 audioPlayer.init = function (audioElement) {
23 audioPlayer.audioElement = audioElement;
97e40b52 24
a9d84d4c 25 console.log(audioElement);
97e40b52 26
a9d84d4c 27 attachEvents();
97e40b52 28
a9d84d4c
JW
29 $(audioElement).hide();
30 };
31
32 function attachEvents () {
97e40b52
JW
33 audioPlayer.audioElement.addEventListener(
34 'durationchange', audioPlayer.durationChange, true);
35 audioPlayer.audioElement.addEventListener(
36 'timeupdate', audioPlayer.timeUpdate, true);
37 audioPlayer.audioElement.addEventListener(
38 'progress', audioPlayer.onProgress, true);
39 audioPlayer.audioElement.addEventListener(
40 'ended', audioPlayer.onEnded, true);
41
a9d84d4c 42 $(document).ready( function () {
97e40b52
JW
43 $('.audio-spectrogram').delegate(
44 '.seekbar', 'click', audioPlayer.onSeek);
45 $('.audio-spectrogram').delegate(
46 '.audio-control-play-pause', 'click', audioPlayer.playPause);
47 $('.audio-spectrogram').delegate(
48 '.audio-volume', 'change', audioPlayer.onVolumeChange);
49 $('.audio-media').delegate(
50 '.audio-spectrogram', 'attachedControls',
51 audioPlayer.onControlsAttached);
a9d84d4c
JW
52 });
53 }
54
97e40b52
JW
55 audioPlayer.onVolumeChange = function(e) {
56 console.log('volume change', e);
57 audioPlayer.audioElement.volume = e.target.value;
58 }
59
60 audioPlayer.onControlsAttached = function(e) {
61 console.log('Controls attached', e);
62 $('.audio-spectrogram .audio-volume').val(
63 Math.round(audioPlayer.audioElement.volume, 2));
64 }
65
66 audioPlayer.onProgress = function(e) {
67 /**
68 * Handler for file download progress
69 */
70 console.log(e);
71
72 var buffered = audioPlayer.audioElement.buffered;
a9d84d4c
JW
73
74 ranges = new Array();
75
97e40b52
JW
76 var indicators = $('.audio-spectrogram .buffered-indicators div');
77
78 for (var i = 0; i < buffered.length; i++) {
79 if (!(i in indicators)) {
80 $('<div style="display: none;"></div>')
81 .appendTo($('.audio-spectrogram .buffered-indicators'))
82 .fadeIn(500);
83 indicators = $('.audio-spectrogram .buffered-indicators div');
84 }
85 var posStart = ((buffered.start(i) / audioPlayer.audioElement.duration)
86 * audioPlayer.imageElement.width());
87 var posStop = ((buffered.end(i) / audioPlayer.audioElement.duration)
88 * audioPlayer.imageElement.width());
89 console.log('indicators', indicators);
90
91 var indicator = $(indicators[i]);
92
93 indicator.css('left', posStart);
94 indicator.css('width', posStop - posStart);
95 }
96
97 /*
98 * Clean up unused indicators
99 */
100 if (indicators.length > buffered.length) {
101 for (var i = buffered.length; i < indicators.length; i++) {
102 $(indicators[i]).fadeOut(500, function () {
103 this.remove();
104 });
105 }
a9d84d4c 106 }
a9d84d4c
JW
107 };
108
109 audioPlayer.onSeek = function (e) {
97e40b52
JW
110 /**
111 * Callback handler for seek event, which is a .click() event on the
112 * .seekbar element
113 */
a9d84d4c 114 console.log('onSeek', e);
97e40b52
JW
115
116 var im = audioPlayer.imageElement;
117 var pos = (e.offsetX || e.originalEvent.layerX) / im.width();
118
a9d84d4c
JW
119 audioPlayer.audioElement.currentTime = pos * audioPlayer.audioElement.duration;
120 audioPlayer.audioElement.play();
121 audioPlayer.setState(audioPlayer.PLAYING);
122 };
123
97e40b52
JW
124 audioPlayer.onEnded = function (e) {
125 audioPlayer.setState(audioPlayer.PAUSED);
126 }
127
a9d84d4c
JW
128 audioPlayer.playPause = function (e) {
129 console.log('playPause', e);
130 if (audioPlayer.audioElement.paused) {
131 audioPlayer.audioElement.play();
132 audioPlayer.setState(audioPlayer.PLAYING);
133 } else {
134 audioPlayer.audioElement.pause();
135 audioPlayer.setState(audioPlayer.PAUSED);
136 }
137 };
138
139 audioPlayer.NULL = null;
140 audioPlayer.PLAYING = 2;
141 audioPlayer.PAUSED = 4;
142
143 audioPlayer.state = audioPlayer.NULL;
144
145 audioPlayer.setState = function (state) {
146 if (state == audioPlayer.state) {
147 return;
97e40b52
JW
148 } else {
149 audioPlayer.state = state;
a9d84d4c
JW
150 }
151
152 switch (state) {
153 case audioPlayer.PLAYING:
154 $('.audio-spectrogram .audio-control-play-pause')
155 .removeClass('paused').addClass('playing')
97e40b52 156 .text('▮▮');
a9d84d4c
JW
157 break;
158 case audioPlayer.PAUSED:
159 $('.audio-spectrogram .audio-control-play-pause')
160 .removeClass('playing').addClass('paused')
161 .text('▶');
162 break;
163 }
164 };
165
166 audioPlayer.durationChange = function () {
97e40b52 167 // ???
a9d84d4c
JW
168 };
169
170 audioPlayer.timeUpdate = function () {
97e40b52
JW
171 /**
172 * Callback handler for the timeupdate event, responsible for
173 * updating the playhead
174 */
175 var currentTime = audioPlayer.audioElement.currentTime;
176 var playhead = audioPlayer.imageElement.parent().find('.playhead');
177 playhead.css('width', (currentTime / audioPlayer.audioElement.duration)
178 * audioPlayer.imageElement.width());
179 var time = formatTime(currentTime);
180 var duration = formatTime(audioPlayer.audioElement.duration);
181 audioPlayer.imageElement.parent()
182 .find('.audio-currentTime')
183 .text(time + '/' + duration);
a9d84d4c
JW
184 };
185
186 function formatTime(seconds) {
97e40b52
JW
187 /**
188 * Format a time duration in (hh:)?mm:ss manner
189 */
a9d84d4c
JW
190 var h = Math.floor(seconds / (60 * 60));
191 var m = Math.floor((seconds - h * 60 * 60) / 60);
192 var s = Math.round(seconds - h * 60 * 60 - m * 60);
193 return '' + (h ? (h < 10 ? '0' + h : h) + ':' : '') + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
194 }
195
97e40b52
JW
196 audioPlayer.formatTime = formatTime;
197
a9d84d4c
JW
198 audioPlayer.attachToImage = function (imageElement) {
199 /**
200 * Attach the player to an image element
201 */
202 console.log(imageElement);
97e40b52
JW
203
204 var im = $(imageElement);
205
a9d84d4c 206 audioPlayer.imageElement = im;
97e40b52 207
a9d84d4c 208 $('<div class="playhead"></div>').appendTo(im.parent());
97e40b52 209 $('<div class="buffered-indicators"></div>').appendTo(im.parent());
a9d84d4c
JW
210 $('<div class="seekbar"></div>').appendTo(im.parent());
211 $('<div class="audio-control-play-pause paused">▶</div>').appendTo(im.parent());
212 $('<div class="audio-currentTime">00:00</div>').appendTo(im.parent());
1d83cf8a
JW
213 $('<input type="range" class="audio-volume"'
214 +'value="1" min="0" max="1" step="0.001" />').appendTo(im.parent());
97e40b52 215 $('.audio-spectrogram').trigger('attachedControls');
a9d84d4c
JW
216 };
217})(audioPlayer);
218
219$(document).ready(function () {
deea3f66
JW
220 if (!$('.audio-media').length) {
221 return;
222 }
223
224 console.log('Initializing audio player');
225
a9d84d4c
JW
226 audioElements = $('.audio-media .audio-player');
227 audioPlayer.init(audioElements[0]);
228 audioPlayer.attachToImage($('.audio-spectrogram img')[0]);
229});