var DEBUG = false; var audio_groups = []; // Entry point & sanitization jQuery(document).ready( function() { // Banner debug(' ___ _______ ___ _ _ _____ \n' + ' / _ \\ / / ___ \\ / _ \\ | (_) / ___| \n' + '/ /_\\ \\ / /| |_/ / / /_\\ \\_ _ __| |_ ___ \\ `--. _ _ _ __ ___ \n' + '| _ | / / | ___ \\ | _ | | | |/ _` | |/ _ \\ `--. \\ | | | \'_ \\ / __| \n' + '| | | |/ / | |_/ / | | | | |_| | (_| | | (_) | /\\__/ / |_| | | | | (__ \n' + '\\_| |_/_/ \\____/ \\_| |_/\\__,_|\\__,_|_|\\___/ \\____/ \\__, |_| |_|\\___| \n' + ' __/ | \n' + ' |___/ \n'); // Find all audio groups var groups = jQuery('.audio-sync-group'); debug('Audio groups found: ' + groups.length); jQuery.each(groups, function(gid, group) { debug('groups[' + gid + ']: ' + group); // Find the play button(s) var btnPlay = jQuery(group).find('.audio-btn-sync-play'); if( btnPlay === null || btnPlay.length <= 0 ) { debug('Group[' + gid + '] does not have a play button!'); return; } // Find the "A" button var btnA = jQuery(group).find('.audio-btn-sync-a'); if( btnA === null || btnA.length <= 0 ) { debug('Group[' + gid + '] does not have an "A" button!'); return; } // Find the "B" button var btnB = jQuery(group).find('.audio-btn-sync-b'); if( btnB === null || btnB.length <= 0 ) { debug('Group[' + gid + '] does not have a "B" button!'); return; } // Find the "A" audio track var audioA = jQuery(group).find('.audio-sync-a'); if( audioA === null || audioA.length <= 0 ) { debug('Group[' + gid + '] does not have an "A" audio track!'); return; } else if( audioA.length > 1 ) { debug('Group[' + gid + '] has too many "A" audio tracks; using the first one found'); } // Find the "B" audio track var audioB = jQuery(group).find('.audio-sync-b'); if( audioB === null || audioB.length <= 0 ) { debug('Group[' + gid + '] does not have an "B" audio track!'); return; } else if( audioB.length > 1 ) { debug('Group[' + gid + '] has too many "B" audio tracks; using the first one found'); } // Disable audio right-click context menu if( typeof audioA.data('allow-menu') === 'undefined' || audioA.data('allow-menu') === false ) { debug('Group[' + gid + '].audioA: Disabling right-click context menu'); audioA.bind('contextmenu', function() { return false; }); } if( typeof audioB.data('allow-menu') === 'undefined' || audioB.data('allow-menu') === false ) { debug('Group[' + gid + '].audioB: Disabling right-click context menu'); audioB.bind('contextmenu', function() { return false; }); } audio_groups.push({ // jQuery group object group: group, // jQuery play button object btnPlay: btnPlay, // jQuery toggle button objects btnA: btnA, btnB: btnB, // HTML audio objects audioA: audioA[0], audioA_volume: 1, audioB: audioB[0], audioB_volume: 1, audio_selected: 'A', // Counter indicating when audio is loaded audio_canplay: 0 }); }); // Check that at least one audio group exists if( audio_groups === null || audio_groups.length <= 0 ) { debug('No usable audio groups found'); return; } // Disable all audio buttons in each group debug('Disabling group play buttons'); groups.find('.audio-btn-sync-a, .audio-btn-sync-b, .audio-btn-sync-play').attr('disabled', 'true'); // Setting volumes for audio elements debug('Setting A tracks to volume=1'); groups.find('.audio-sync-a').map(function() { debug('Setting volume=1'); this.volume = 1; }); debug('Setting B tracks to volume=0'); groups.find('.audio-sync-b').map(function() { debug('Setting volume=0'); this.volume = 0; }); debug('Starting ABAudioSync()'); ABAudioSync(); }); function btnPlay_Clicked(event) { debug('audio[' + event.data.group + '].btnPlay[' + event.data.btn + '] was clicked'); var group = audio_groups[event.data.group]; if( group.audioA.paused && group.audioB.paused ) { if( typeof group.btnPlay.data('stop') !== "undefined" && group.btnPlay.data('stop') !== false ) group.btnPlay.text('Stop'); else group.btnPlay.text('Pause'); syncTime(group); group.audioA.play(); group.audioB.play(); // Restore audio state if( group.audio_selected === 'A' ) group.btnB.removeAttr('disabled'); else group.btnA.removeAttr('disabled'); } else { group.audioA.pause(); group.audioB.pause(); if( typeof group.btnPlay.data('stop') !== "undefined" && group.btnPlay.data('stop') !== false ) group.audioB.currentTime = 0; syncTime(group); group.btnPlay.text('Play'); group.btnA.attr('disabled', 'true'); group.btnB.attr('disabled', 'true'); } } function btnA_Clicked(event) { debug('audio[' + event.data.group + '].btnA[' + event.data.btn + '] was clicked'); var group = audio_groups[event.data.group]; // Preserve audio play state group.audio_selected = 'A'; // Preserve volume state group.audioB_volume = group.audioB.volume; // Switch tracks group.audioA.volume = group.audioA_volume; group.audioB.volume = 0; group.btnA.attr('disabled','true'); group.btnB.removeAttr('disabled'); } function btnB_Clicked(event) { debug('audio[' + event.data.group + '].btnB[' + event.data.btn + '] was clicked'); var group = audio_groups[event.data.group]; // Preserve audio play state group.audio_selected = 'B'; // Preserve volume state group.audioA_volume = group.audioA.volume; // Switch tracks group.audioB.volume = group.audioB_volume; group.audioA.volume = 0; group.btnA.removeAttr('disabled'); group.btnB.attr('disabled','true'); } function audio_canplay(event) { debug('audio[' + event.data.group + '].audio[' + event.data.audio + '] signaled "canplay"'); audio_groups[event.data.group].audio_canplay++; if( audio_groups[event.data.group].audio_canplay >= 2 ) { audio_groups[event.data.group].btnPlay.removeAttr('disabled'); } jQuery(this).unbind('canplay', audio_canplay); } function ABAudioSync() { jQuery.each(audio_groups, function(aid, audio) { debug('Setting Audio Group #' + aid + ' Play button click handlers'); jQuery.each(audio.btnPlay, function(bid, btn) { jQuery(btn).click({group: aid, btn: bid}, btnPlay_Clicked); }); debug('Setting Audio Group #' + aid + ' "A" button click handlers'); jQuery.each(audio.btnA, function(bid, btn) { jQuery(btn).click({group: aid, btn: bid}, btnA_Clicked); }); debug('Setting Audio Group #' + aid + ' "B" button click handlers'); jQuery.each(audio.btnB, function(bid, btn) { jQuery(btn).click({group: aid, btn: bid}, btnB_Clicked); }); debug('Setting Audio Group #' + aid + ' "canplay" handlers'); if( audio.audioA.readyState < 4 ) { jQuery(audio.audioA).bind('canplay', {group: aid, audio: 'A'}, audio_canplay); } else { debug('audio[' + aid + '].audio[A].readyState: ' + audio.audioA.readyState); audio.audio_canplay++; } if( audio.audioB.readyState < 4 ) { jQuery(audio.audioB).bind('canplay', {group: aid, audio: 'B'}, audio_canplay); } else { debug('audio[' + aid + '].audio[B].readyState: ' + audio.audioB.readyState); audio.audio_canplay++; } if( audio.audio_canplay >= 2 ) { audio.btnPlay.removeAttr('disabled'); } }); } function debug(msg) { if( DEBUG ) console.log(msg); } function syncTime(group) { var synctime = parseInt(group.audioB.currentTime); debug('Synchronizing audio to ' + synctime + 's'); group.audioA.currentTime = group.audioB.currentTime = synctime; }