Bug 22581: Show and play musical inscripts

This patch adds musical inscripts to OPAC's detail page

To test:
1. run previous patch test plan
2. apply this patch
3. edit a the marc structure of a MARC bibliographic framework, and in tag 031 enable the following subfiels to be visible in editor: 2, g, n, o, p, u
4. search the catalog for a record that belongs to that framework, and edit tag 031 with the following:
   * 2:pe
   * g:G-2
   * n:xFCGD
   * o:3/8
   * p:'6B/{8B+(6B''E'B})({AFD})/{6.E3G},8B-/({6'EGF})({FAG})({GEB})/4F6-
   * u:http://nonexistent.org/url/of/a/midi
5. save and click in opac view
CHECK => even though you add a 031 tag there is no musical inscript shown in opac view
6. in admin module enable OPACShowMusicalInscripts preference
7. refresh opac view
SUCCESS => it takes a few seconds to load, but you see a link that says 'Audio file' pointing to the URL you placed in 'u' subfield, and below you see the musical inscript
8. in admin module enable OPACPlayMusicalInscripts preference
9. refresh opac view
SUCCESS => You see a play button below the musical inscript, and when you click, the song is played
10. sign off

Sponsored-by: Biblioteca Provincial Fr. Mamerto Esquiú (Provincia Franciscana de la Asunción)
Co-authored-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
This commit is contained in:
Agustin Moyano 2019-10-28 18:15:22 -03:00 committed by Martin Renvoize
parent 292262367e
commit 426a055a07
Signed by: martin.renvoize
GPG key ID: 422B469130441A0F
12 changed files with 998 additions and 2 deletions

View file

@ -173,7 +173,7 @@ sub get_xslt_sysprefs {
TrackClicks opacthemes IdRef OpacSuppression
OPACResultsLibrary OPACShowOpenURL
OpenURLResolverURL OpenURLImageLocation
OpenURLText / )
OpenURLText OPACShowMusicalInscripts OPACPlayMusicalInscripts / )
{
my $sp = C4::Context->preference( $syspref );
next unless defined($sp);

View file

@ -33,6 +33,9 @@
<title>[% IF ( LibraryNameTitle ) %][% LibraryNameTitle | html %][% ELSE %]Koha online[% END %] catalog &rsaquo; Details for: [% INCLUDE 'biblio-title-head.inc' %]</title>
[% INCLUDE 'doc-head-close.inc' %]
[% Asset.css("lib/emoji-picker/css/emoji.css") | $raw %]
[% IF ( Koha.Preference('OPACShowMusicalInscripts') ) %]
[% Asset.css("lib/verovio/midiplayer.css") | $raw %]
[% END %]
</head>
[% BLOCK cssinclude %][% END %]
[% INCLUDE 'bodytag.inc' bodyid='opac-detail' bodyclass='scrollto' %]
@ -1414,6 +1417,14 @@
[% Asset.js("lib/kjua/kjua.min.js") | $raw %]
[% END %]
[% IF ( Koha.Preference('OPACShowMusicalInscripts') ) %]
<script>
var interface = "[% interface | html %]";
var PREF_OPACPlayMusicalInscripts = "[% Koha.Preference('OPACPlayMusicalInscripts') | html %]";
</script>
[% Asset.js("js/verovio.js") | $raw %]
[% END %]
<script>
[% IF ( OpacHighlightedWords ) %]
var q_array = new Array(); // holds search terms if available

View file

@ -1477,6 +1477,56 @@
</xsl:if>
<!-- End of OpenURL -->
<xsl:variable name="OPACShowMusicalInscripts" select="marc:sysprefs/marc:syspref[@name='OPACShowMusicalInscripts']" />
<xsl:variable name="OPACPlayMusicalInscripts" select="marc:sysprefs/marc:syspref[@name='OPACPlayMusicalInscripts']" />
<xsl:if test="$OPACShowMusicalInscripts = 1 and marc:datafield[@tag=031]">
<xsl:for-each select="marc:datafield[@tag=031]">
<span class="results_summary musical_inscripts">
<xsl:if test="marc:subfield[@code='u']">
<span class="uri">
<a>
<xsl:attribute name="href">
<xsl:value-of select="marc:subfield[@code='u']"/>
</xsl:attribute>
<xsl:text>Audio file</xsl:text>
</a>
</span>
</xsl:if>
<xsl:if test="marc:subfield[@code='2'] and marc:subfield[@code='2']/text() = 'pe' and marc:subfield[@code='g'] and marc:subfield[@code='n'] and marc:subfield[@code='o'] and marc:subfield[@code='p']">
<div class="inscript" data-system="pae">
<xsl:attribute name="data-clef">
<xsl:value-of select="marc:subfield[@code='g']"/>
</xsl:attribute>
<xsl:attribute name="data-keysig">
<xsl:value-of select="marc:subfield[@code='n']"/>
</xsl:attribute>
<xsl:attribute name="data-timesig">
<xsl:value-of select="marc:subfield[@code='o']"/>
</xsl:attribute>
<xsl:attribute name="data-notation">
<xsl:value-of select="marc:subfield[@code='p']"/>
</xsl:attribute>
</div>
<xsl:if test="$OPACPlayMusicalInscripts = 1">
<div class="audio_controls hide">
<button class="btn play_btn">
<i id="carticon" class="fa fa-play"></i>
<xsl:text> Play this sample</xsl:text>
</button>
</div>
</xsl:if>
</xsl:if>
</span>
</xsl:for-each>
<xsl:if test="$OPACPlayMusicalInscripts = 1">
<div class="results_summary">
<span class="inscript_audio hide"></span>
</div>
</xsl:if>
</xsl:if>
</xsl:element>
</xsl:template>

View file

@ -661,6 +661,56 @@
</xsl:for-each>
</xsl:if>
<xsl:variable name="OPACShowMusicalInscripts" select="marc:sysprefs/marc:syspref[@name='OPACShowMusicalInscripts']" />
<xsl:variable name="OPACPlayMusicalInscripts" select="marc:sysprefs/marc:syspref[@name='OPACPlayMusicalInscripts']" />
<xsl:if test="$OPACShowMusicalInscripts and marc:datafield[@tag=031]">
<xsl:for-each select="marc:datafield[@tag=031]">
<span class="results_summary musical_inscripts">
<xsl:if test="marc:subfield[@code='u']">
<span class="uri">
<a>
<xsl:attribute name="href">
<xsl:value-of select="marc:subfield[@code='u']"/>
</xsl:attribute>
<xsl:text>Audio file</xsl:text>
</a>
</span>
</xsl:if>
<xsl:if test="marc:subfield[@code='2'] and marc:subfield[@code='2']/text() = 'pe' and marc:subfield[@code='g'] and marc:subfield[@code='n'] and marc:subfield[@code='o'] and marc:subfield[@code='p']">
<div class="inscript" data-system="pae">
<xsl:attribute name="data-clef">
<xsl:value-of select="marc:subfield[@code='g']"/>
</xsl:attribute>
<xsl:attribute name="data-keysig">
<xsl:value-of select="marc:subfield[@code='n']"/>
</xsl:attribute>
<xsl:attribute name="data-timesig">
<xsl:value-of select="marc:subfield[@code='o']"/>
</xsl:attribute>
<xsl:attribute name="data-notation">
<xsl:value-of select="marc:subfield[@code='p']"/>
</xsl:attribute>
</div>
<xsl:if test="$OPACPlayMusicalInscripts = 1">
<div class="audio_controls">
<button class="btn play_btn">
<i id="carticon" class="fa fa-play"></i>
<xsl:text> Play this sample</xsl:text>
</button>
</div>
</xsl:if>
</xsl:if>
</span>
</xsl:for-each>
<xsl:if test="$OPACPlayMusicalInscripts = 1">
<div class="results_summary">
<span class="inscript_audio hide"></span>
</div>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="part">

View file

@ -493,6 +493,56 @@
</xsl:if>
<!-- End of OpenURL -->
<xsl:variable name="OPACShowMusicalInscripts" select="marc:sysprefs/marc:syspref[@name='OPACShowMusicalInscripts']" />
<xsl:variable name="OPACPlayMusicalInscripts" select="marc:sysprefs/marc:syspref[@name='OPACPlayMusicalInscripts']" />
<xsl:if test="$OPACShowMusicalInscripts and marc:datafield[@tag=036]">
<xsl:for-each select="marc:datafield[@tag=031]">
<span class="results_summary musical_inscripts">
<xsl:if test="marc:subfield[@code='u']">
<span class="uri">
<a>
<xsl:attribute name="href">
<xsl:value-of select="marc:subfield[@code='u']"/>
</xsl:attribute>
<xsl:text>Audio file</xsl:text>
</a>
</span>
</xsl:if>
<xsl:if test="marc:subfield[@code='2'] and marc:subfield[@code='2']/text() = 'pe' and marc:subfield[@code='g'] and marc:subfield[@code='n'] and marc:subfield[@code='o'] and marc:subfield[@code='p']">
<div class="inscript" data-system="pae">
<xsl:attribute name="data-clef">
<xsl:value-of select="marc:subfield[@code='g']"/>
</xsl:attribute>
<xsl:attribute name="data-keysig">
<xsl:value-of select="marc:subfield[@code='n']"/>
</xsl:attribute>
<xsl:attribute name="data-timesig">
<xsl:value-of select="marc:subfield[@code='o']"/>
</xsl:attribute>
<xsl:attribute name="data-notation">
<xsl:value-of select="marc:subfield[@code='p']"/>
</xsl:attribute>
</div>
<xsl:if test="$OPACPlayMusicalInscripts = 1">
<div class="audio_controls">
<button class="btn play_btn">
<i id="carticon" class="fa fa-play"></i>
<xsl:text> Play this sample</xsl:text>
</button>
</div>
</xsl:if>
</xsl:if>
</span>
</xsl:for-each>
<xsl:if test="$OPACPlayMusicalInscripts = 1">
<div class="results_summary">
<span class="inscript_audio hide"></span>
</div>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="nameABCDQ">

View file

@ -0,0 +1,108 @@
/* global PREF_OPACPlayMusicalInscripts interface verovio */
$(document).ready(function() {
if( $(".musical_inscripts").length > 0 ){
// Check support for WebAssembly
// https://stackoverflow.com/questions/47879864/how-can-i-check-if-a-browser-supports-webassembly
var webassenbly_supported = (() => {
try {
if (typeof WebAssembly === "object"
&& typeof WebAssembly.instantiate === "function") {
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
if (module instanceof WebAssembly.Module)
return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
}
} catch (e) {
}
return false;
})();
if( webassenbly_supported ){
$.ajaxSetup({
cache: true
});
$.getScript( interface + "/lib/verovio/verovio-toolkit.js", function( data, textStatus, jqxhr ) {
$('.musical_inscripts .inscript').each(function() {
var vrvToolkit = new verovio.toolkit();
var $t = $(this);
var data = "@clef:"+$t.data('clef')+"\n@keysig:"+$t.data('keysig')+"\n@timesig:"+$t.data('timesig')+"\n@data:"+$t.data('notation')+"\n";
var svg = vrvToolkit.renderData(data, {
inputFormat: $t.data('system'),
spacingStaff: 0,
adjustPageHeight: 1,
scale: 40,
pageHeight: 300
});
$t.html(svg);
var base64midi = vrvToolkit.renderToMIDI();
var song = 'data:audio/midi;base64,' + base64midi;
var play_btn = $('.play_btn', $t.parent());
if(play_btn.length) {
play_btn.data('song', song);
play_btn.data('toolkit', vrvToolkit);
}
});
if( PREF_OPACPlayMusicalInscripts ){
$(".audio_controls").show();
var playmusic_1 = $.getScript( interface + "/lib/verovio/000_acoustic_grand_piano.js" );
var playmusic_2 = $.getScript( interface + "/lib/verovio/midiplayer.js" );
$.when( playmusic_1, playmusic_2 ).done(function () {
var ids = [];
var currentToolkit;
var player = $('.inscript_audio');
var midiUpdate = function(time) {
// time needs to - 400 for adjustment
var vrvTime = Math.max(0, time - 400);
var elementsattime = currentToolkit.getElementsAtTime(vrvTime);
if (elementsattime.page > 0) {
if ((elementsattime.notes.length > 0) && (ids != elementsattime.notes)) {
ids.forEach(function(noteid) {
if ($.inArray(noteid, elementsattime.notes) == -1) {
$("#" + noteid).attr("fill", "#000").attr("stroke", "#000");
}
});
ids = elementsattime.notes;
ids.forEach(function(noteid) {
if ($.inArray(noteid, elementsattime.notes) != -1) {
$("#" + noteid).attr("fill", "#c00").attr("stroke", "#c00");
}
});
}
}
};
var midiStop = function() {
ids.forEach(function(noteid) {
$("#" + noteid).attr("fill", "#000").attr("stroke", "#000");
});
player.hide();
};
if(player.length) {
player.midiPlayer({
locateFile: function(file) {
return interface + '/lib/verovio/'+file;
},
color: "#c00",
onUpdate: midiUpdate,
onStop: midiStop
});
}
$('.musical_inscripts .play_btn').click(function() {
var $t = $(this);
player.show();
currentToolkit = $t.data('toolkit')
player.midiPlayer.play($t.data('song'));
});
});
}
});
}
}
});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,27 @@
#midiPlayer_div{width:700px;height:36px;background:#999;}
#midiPlayer_bar{height:12px;width:500px;background:#ccc;cursor:pointer;display:inline-block;}
#midiPlayer_progress{margin:0;background:#555;width:0;height:100%;}
#midiPlayer_playingTime{width:45px;margin:8px;font-size:16px;text-align:right;font-family:arial;display:inline-block;}
#midiPlayer_totalTime{width:40px;text-align:right;margin:8px;font-size:16px;font-family:arial;display:inline-block;}
#midiPlayer_div a.icon{margin:3px;cursor:pointer;background-color:#eee;border:2px solid #ccc;display:inline-block;position:relative;vertical-align:top;display: none;}
#midiPlayer_div a.icon:after,
#midiPlayer_div a.icon:before{background:#eee;border:2px solid #ccc;content:'';position:absolute;}
#midiPlayer_div a.icon:hover,
#midiPlayer_div a.icon:hover:after,
#midiPlayer_div a.icon:hover:before{background-color:#fff;}
#midiPlayer_div a.stop{border-radius:100%;height:26px;width:26px;}
#midiPlayer_div a.stop:after{background:#ccc;height:9px;left:7px;top:7px;width:8px;}
#midiPlayer_div a.stop:hover:after{background:#ccc;}
#midiPlayer_div a.stop:before{border:none;}
#midiPlayer_div a.pause{border-radius:100%;height:26px;width:26px;}
#midiPlayer_div a.pause:after,
#midiPlayer_div a.pause:before{height:10px;top:6px;width:0;}
#midiPlayer_div a.pause:after{left:7px;}
#midiPlayer_div a.pause:before{left:15px;}
#midiPlayer_div a.play{border-radius:100%;height:26px;width:26px;}
#midiPlayer_div a.play:after,
#midiPlayer_div a.play:before,
#midiPlayer_div a.play:hover:after,
#midiPlayer_div a.play:hover:before{background:none;}
#midiPlayer_div a.play:after{border-bottom:8px solid transparent;border-left:13px solid #ccc;border-right:13px solid transparent;border-top:8px solid transparent;height:0;left:8px;top:5px;width:0;}
#midiPlayer_div a.play:before{border:none;}

View file

@ -0,0 +1,439 @@
/************************************************************************
* Circular Web Audio Buffer Queue
*/
function CircularAudioBuffer(slots) {
slots = slots || 24;
// number of buffers
this.slots = slots;
this.buffers = new Array(slots);
this.reset();
for (var i = 0; i < this.slots; i++) {
var buffer = audioCtx.createBuffer(channels, BUFFER, SAMPLE_RATE);
this.buffers[i] = buffer;
}
}
// pseudo empty all buffers
CircularAudioBuffer.prototype.reset = function () {
this.used = 0;
this.filled = 0;
};
// returns number of buffers that are filled
CircularAudioBuffer.prototype.filledBuffers = function () {
var fills = this.filled - this.used;
if (fills < 0) fills += this.slots;
return fills;
}
// returns whether buffers are all filled
CircularAudioBuffer.prototype.full = function () {
//console.debug(this.filledBuffers());
return this.filledBuffers() >= this.slots - 1;
}
// returns a reference to next available buffer to be filled
CircularAudioBuffer.prototype.prepare = function () {
if (this.full()) {
//console.log('buffers full!!')
return
}
var buffer = this.buffers[ this.filled++];
this.filled %= this.slots;
return buffer;
}
// returns the next buffer in the queue
CircularAudioBuffer.prototype.use = function () {
if (! this.filledBuffers()) return;
var buffer = this.buffers[ this.used++];
this.used %= this.slots;
return buffer;
}
/************************************************************************
* Web Audio Stuff
*/
var SAMPLE_RATE = 44100;
var BUFFER = 4096;
var channels = 2;
var audioCtx;
var source;
var scriptNode;
var circularBuffer;
var emptyBuffer;
function initAudio() {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
scriptNode = audioCtx.createScriptProcessor(BUFFER, 0, channels);
scriptNode.onaudioprocess = onAudioProcess;
source = audioCtx.createBufferSource();
circularBuffer = new CircularAudioBuffer(8);
emptyBuffer = audioCtx.createBuffer(channels, BUFFER, SAMPLE_RATE);
source.connect(scriptNode);
source.start(0);
console.debug("initAudio");
}
function startAudio() {
scriptNode.connect(audioCtx.destination);
console.debug("startAudio");
}
function pauseAudio() {
circularBuffer.reset();
scriptNode.disconnect();
console.debug("pauseAudio");
}
/************************************************************************
* Emscripten variables and callback - cannot be renamed
*/
var ULONG_MAX = 4294967295;
var _EM_signalStop = 0;
var _EM_seekSamples = ULONG_MAX;
function processAudio(buffer_loc, size) {
var buffer = circularBuffer.prepare();
var left_buffer_f32 = buffer.getChannelData(0);
var right_buffer_f32 = buffer.getChannelData(1);
// Copy emscripten memory (OpenAL stereo16 format) to JS
for (var i = 0; i < size; i++) {
left_buffer_f32[i] = MidiPlayer.HEAP16[(buffer_loc >> 1) + 2 * i + 0] / 32768;
right_buffer_f32[i] = MidiPlayer.HEAP16[(buffer_loc >> 1) + 2 * i + 1] / 32768;
}
}
function updateProgress(current, total) {
midiPlayer_currentSamples = current;
midiPlayer_totalSamples = total;
midiPlayer_progress.style.width = (current / total * 100) + '%';
midiPlayer_playingTime.innerHTML = samplesToTime(current);
midiPlayer_totalTime.innerHTML = samplesToTime(total);
var millisec = Math.floor(current * 1000 / SAMPLE_RATE / midiPlayer_updateRate);
if (midiPlayer_lastMillisec > millisec) {
midiPlayer_lastMillisec = 0;
}
if (millisec > midiPlayer_lastMillisec) {
if (midiPlayer_onUpdate != null) midiPlayer_onUpdate(millisec * midiPlayer_updateRate);
//console.log(millisec * UPDATE_RATE);
}
midiPlayer_lastMillisec = millisec;
}
function completeConversion(status) {
midiPlayer_drainBuffer = true;
console.debug('completeConversion');
midiPlayer_convertionJob = null;
// Not a pause
if (_EM_signalStop != 2) {
setTimeout(stop, 1000);
}
}
/************************************************************************
* Global player variables and functions
*/
// html elements
var midiPlayer_width;
var midiPlayer_bar;
var midiPlayer_progress;
var midiPlayer_playingTime;
var midiPlayer_play;
var midiPlayer_pause;
var midiPlayer_stop;
var midiPlayer_totalTime;
// variables
var midiPlayer_isLoaded = false;
var midiPlayer_isAudioInit = false;
var midiPlayer_input = null;
var midiPlayer_lastMillisec = 0;
var midiPlayer_midiName = ''
var midiPlayer_convertionJob = null;
var midiPlayer_currentSamples = ULONG_MAX;
var midiPlayer_totalSamples = 0;
var midiPlayer_updateRate = 50;
var midiPlayer_drainBuffer = false;
var BASE64_MARKER = ';base64,';
// callbacks
var midiPlayer_onStop = null;
var midiPlayer_onUpdate = null;
var MidiPlayer = {
noInitialRun: true,
totalDependencies: 1,
monitorRunDependencies: function(left) {
//console.log(this.totalDependencies);
//console.log(left);
if ((left == 0) && !midiPlayer_isLoaded) {
console.log("MidiPlayer is loaded");
midiPlayer_isLoaded = true;
}
}
};
function onAudioProcess(audioProcessingEvent) {
var generated = circularBuffer.use();
if (!generated && midiPlayer_drainBuffer) {
// wait for remaining buffer to drain before disconnect audio
pauseAudio();
midiPlayer_drainBuffer = false;
return;
}
if (!generated) {
//console.log('buffer under run!!')
generated = emptyBuffer;
}
var outputBuffer = audioProcessingEvent.outputBuffer;
var offset = 0;
if (outputBuffer.copyToChannel !== undefined) {
// Firefox -> about 50% faster than decoding
outputBuffer.copyToChannel(generated.getChannelData(0), 0, offset);
outputBuffer.copyToChannel(generated.getChannelData(1), 1, offset);
} else {
// Other browsers -> about 20 - 70% slower than decoding
var leftChannel = outputBuffer.getChannelData(0);
var rightChannel = outputBuffer.getChannelData(1);
var generatedLeftChannel = generated.getChannelData(0);
var generatedRightChannel = generated.getChannelData(1);
var i;
for (i = 0; i < BUFFER; i++) {
leftChannel[i] = generatedLeftChannel[i];
rightChannel[i] = generatedRightChannel[i];
}
}
}
function samplesToTime(at) {
var in_s = Math.floor(at / SAMPLE_RATE);
var s = in_s % 60;
var min = in_s / 60 | 0;
return min + ':' + (s === 0 ? '00': s < 10 ? '0' + s: s);
}
function convertDataURIToBinary(dataURI) {
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (var i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}
function convertFile(file, data) {
midiPlayer_midiName = file;
midiPlayer_input = null;
console.log('open ', midiPlayer_midiName);
MidiPlayer['FS'].writeFile(midiPlayer_midiName, data, {
encoding: 'binary'
});
play();
}
function pause() {
_EM_signalStop = 2;
circularBuffer.reset();
midiPlayer_play.style.display = 'inline-block';
midiPlayer_pause.style.display = 'none';
}
function play() {
if (!midiPlayer_isLoaded) {
console.error("MidiPlayer is not loaded yet");
return;
}
if (!midiPlayer_isAudioInit) {
initAudio();
midiPlayer_isAudioInit = true;
}
_EM_seekSamples = midiPlayer_currentSamples;
if (midiPlayer_convertionJob) {
return;
}
_EM_signalStop = 0;
midiPlayer_play.style.display = 'none';
midiPlayer_pause.style.display = 'inline-block';
midiPlayer_stop.style.display = 'inline-block';
// add small delay so UI can update.
setTimeout(runConversion, 100);
}
function stop() {
_EM_signalStop = 1;
_EM_seekSamples = 0;
circularBuffer.reset();
midiPlayer_totalSamples = 0;
midiPlayer_currentSamples = ULONG_MAX;
midiPlayer_progress.style.width = '0%';
midiPlayer_playingTime.innerHTML = "00.00";
midiPlayer_totalTime.innerHTML = "00.00";
midiPlayer_play.style.display = 'none';
midiPlayer_pause.style.display = 'none';
midiPlayer_stop.style.display = 'none';
if (midiPlayer_onStop != null) midiPlayer_onStop();
}
function runConversion() {
midiPlayer_convertionJob = {
sourceMidi: midiPlayer_midiName,
targetWav: midiPlayer_midiName.replace(/\.midi?$/i, '.wav'),
targetPath: '',
conversion_start: Date.now()
};
var sleep = 10;
circularBuffer.reset();
startAudio();
console.log(midiPlayer_convertionJob);
MidiPlayer.ccall('wildwebmidi',
null,[ 'string', 'string', 'number'],[midiPlayer_convertionJob.sourceMidi, midiPlayer_convertionJob.targetPath, sleep], {
async: true
});
}
/************************************************************************
* jQuery player plugin
*/
(function ($) {
$.fn.midiPlayer = function (options) {
var options = $.extend({
// These are the defaults.
color: "#556b2f",
backgroundColor: "white",
width: 500,
onStop: null,
onUpdate: null,
updateRate: 50,
},
options);
// width should not be less than 150
options.width = Math.max(options.width, 150);
// update rate should not be less than 10 milliseconds
options.updateRate = Math.max(options.updateRate, 10);
if(options.locateFile) MidiPlayer.locateFile = options.locateFile;
MidiModule(MidiPlayer);
$.fn.midiPlayer.play = function (song) {
if (midiPlayer_isLoaded == false) {
midiPlayer_input = song;
}
else {
var byteArray = convertDataURIToBinary(song);
if (midiPlayer_totalSamples > 0) {
stop();
// a timeout is necessary because otherwise writing to the disk is not done
setTimeout(function() {convertFile("player.midi", byteArray);}, 200);
}
else {
convertFile("player.midi", byteArray);
}
}
};
$.fn.midiPlayer.pause = function () {
pause();
};
$.fn.midiPlayer.seek = function (millisec) {
if (midiPlayer_totalSamples == 0) return;
var samples = millisec * SAMPLE_RATE / 1000;
midiPlayer_currentSamples = Math.min(midiPlayer_totalSamples, samples);
play();
};
$.fn.midiPlayer.stop = function () {
stop();
};
// Create the player
this.append("<div id=\"midiPlayer_div\"></div>");
$("#midiPlayer_div").append("<div id=\"midiPlayer_playingTime\">0:00</div>")
.append("<div id=\"midiPlayer_bar\"><div id=\"midiPlayer_progress\"></div></div>")
.append("<div id=\"midiPlayer_totalTime\">0:00</div>")
.append("<a class=\"icon play\" id=\"midiPlayer_play\" onclick=\"play()\"></a>")
.append("<a class=\"icon pause\" id=\"midiPlayer_pause\" onclick=\"pause()\"></a>")
.append("<a class=\"icon stop\" id=\"midiPlayer_stop\" onclick=\"stop()\"></a>");
$("#midiPlayer_div").css("width", options.width + 200);
$("#midiPlayer_bar").css("width", options.width);
$("#midiPlayer_progress").css("background", options.color);
// Assign the global variables
midiPlayer_onStop = options.onStop;
midiPlayer_onUpdate = options.onUpdate;
midiPlayer_updateRate = options.updateRate;
midiPlayer_bar = document.getElementById('midiPlayer_bar');
midiPlayer_progress = document.getElementById('midiPlayer_progress');
midiPlayer_playingTime = document.getElementById('midiPlayer_playingTime');
midiPlayer_play = document.getElementById('midiPlayer_play');
midiPlayer_pause = document.getElementById('midiPlayer_pause');
midiPlayer_stop = document.getElementById('midiPlayer_stop');
midiPlayer_totalTime = document.getElementById('midiPlayer_totalTime');
var pageDragStart = 0;
var barDragStart = 0;
midiPlayer_bar.addEventListener('mousedown', function (e) {
if (midiPlayer_totalSamples == 0) return;
pageDragStart = e.pageX;
barDragStart = e.offsetX;
updateDragging(e.pageX);
});
window.addEventListener('mousemove', function (e) {
if (pageDragStart != 0) {
pause();
updateDragging(e.pageX);
}
});
window.addEventListener('mouseup', function (e) {
if (pageDragStart == 0) return;
if (midiPlayer_totalSamples == 0) return;
pageDragStart = 0;
play();
});
function updateDragging(pageX) {
var posX = barDragStart + (pageX - pageDragStart);
if (posX >= 0 && posX <= options.width) {
var percent = posX / options.width;
midiPlayer_currentSamples = percent * midiPlayer_totalSamples | 0;
updateProgress(midiPlayer_currentSamples, midiPlayer_totalSamples);
}
}
return;
};
}
(jQuery));

File diff suppressed because one or more lines are too long

View file

@ -150,7 +150,9 @@ if (C4::Context->preference('OpacSuppression')) {
}
}
$template->param( biblio => $biblio );
$template->param(
biblio => $biblio
);
# get biblionumbers stored in the cart
my @cart_list;