added recorder script tha also uploads the audio files

master
Angeliki 6 years ago
parent 103945c341
commit 031e5a23bf

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 icatcher.at
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,102 @@
# MP3RecorderJS #
Record MP3 (and WAV) files in the browser using JavaScript and HTML.
## General ##
### Why? ###
The whole project got kicked off by using [Recordmp3js](https://github.com/nusofthq/Recordmp3js) - discovered in [this wonderful article by Remus](http://nusofthq.com/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/) -
and discovering that my needs were not entirely met. I needed the possibility to have multiple recorders on one site. Also, since the original code was being altered to only reflect the MP3 changes and changing
it from stereo to mono, I had the feeling that a lot of unused code has been left in there and I found it difficult to actually see what's going on.
### Fork? ###
My first idea was to fork the original project, but I soon discovered that I'm going more for a rewrite than a fork. Hence I ended up writing it anew in a different style.
## Requirements ##
* [jQuery (>= v1.11.1)](http://jquery.com/)
* [libmp3lame.js](https://github.com/akrennmair/libmp3lame-js)
* A browser that supports `navigator.getUserMedia`
* [WC3 specification](http://dev.w3.org/2011/webrtc/editor/getusermedia.html)
* [Supported Browsers](http://caniuse.com/#search=getUserMedia)
For easy use `jQuery` and `libmp3lame.js` are included in this project.
## Usage ##
### Creation ###
// create an audio context
var audio_context = new AudioContext;
// tell the browser you want to get some audio user media
navigator.getUserMedia({audio: true}, function(stream) {
// create an MP3Recorder object supplying the audio context and the stream
var recorderObject = new MP3Recorder(audio_context, stream);
}, function(e) {
// some error occured
});
### Start recording ###
On a given `MP3Recorder` object you can simply call `start()` to start recording.
recorderObject.start();
### Stop recording ###
On a given `MP3Recorder` object you can simply call `stop()` to stop recording.
recorderObject.stop();
### Retrieving recorded data ###
On a given `MP3Recorder` object you can call 3 methods to get the recorded data, depending on which type you need.
#### As Blob data ####
recorderObject.exportBlob(function(blobData) {
// blobData is a Blob object
});
#### As WAV data ####
recorderObject.exportWAV(function(wavData) {
// wavData is a base64 encoded Uint8Array
});
#### As MP3 data ####
recorderObject.exportMP3(function(mp3Data) {
// mp3Data is a base64 encoded Uint8Array
});
### Logging ###
If you create the `MP3Recorder` object with a third parameter you can specify a container and a method to log to.
var recorderObject = new MP3Recorder(audio_context, stream,
{ statusContainer: $('#status'), statusMethod: 'replace' }
);
* `statusContainer` must be a jQuery object that responds to the [`text()`](http://api.jquery.com/text/) function.
* `statusMethod` can be `'append'` to append the status text or anything else to replace it.
## Example ##
For a complete example, using multiple recorders on a page, see the `index.html` file.
## Known issues ##
As mentioned in [the article by Remus](http://nusofthq.com/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/) the resulting mp3 recording will be longer by approximately 50%,
which is an issue of the lame library that's being used.
A possible fix for this is mentioned [by Nicholas in the comment section](https://nusofthq.com/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/#comment-674).
## Disclaimer ##
For the purpose of this project, [libmp3lame.js](https://github.com/akrennmair/libmp3lame-js) was used which was not developed by me.
Using LAME in your project may result in requiring a special patent license for your country. For more information see the [LAME project site](http://lame.sourceforge.net/links.php#Patents).

@ -10,12 +10,23 @@
--> -->
</head> </head>
<body> <body>
<h4 align="right">This is (the unfloding of) an<span style="font-size:50"> audio zine</span> on amplification of female and collective voices.</h4> <h4 align="right">This is (the unfolding/overlayering of) an<span style="font-size:50"> audio zine</span> on amplification of female and collective voices. Author/Narrator: Angeliki Diakrousi</h4>
<div class="tab">
<button class="tablinks" style="position: absolute;font-size: 28px;margin-right: 90%; padding: 8px !important; border: none !important; margin-top: 0% !important;" onclick="openCity(event, 'about')">About</button>
</div>
<div id="about" class="tabcontent" style="font-size: 28px !important; left: 5px !important; top: 300px !important; width: 1000px !important;padding: 0px !important;">
<span onclick="this.parentElement.style.display='none'" class="topleft">&times</span>
It is a collection of audio recordings coming from meetings I co-organised, internet sources, podcasts and soundwalks. 'Revisiting podcasts' questions the establishment of authoritative/male voices that create exclusive speech platforms, along the assumption that voices have to be rational, authoritative (voice of expertise) etc. The intervention that changes the paradigm becomes <div class="tooltip-wrap" style="display: inline;text-decoration:underline;">a set of podcasts <div class="tooltip-content-right" ><div>what conflicts or frictions the technical aspect provokes?</div></div></div>that revisit the sound material produced in situated amplification meetings and soundwalks. Every podcast includes the previous one, on a way that creates repetetive layers of the same material. Creating presence by repetetion.'Revisiting podcasts' are upsetting binaries such as male/female, expert/amateur, rational/irrational
</div>
<!-- for about --> <!-- for about -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
<div style="top: 10px;"> <div style="top: 10px;">
<a style="font-size: 28px;margin-right: 90%;" href="#" title="It is a collection of audio recordings coming from meetings I co-organised, internet sources, podcasts and soundwalks. 'Revisiting podcasts' questions the establishment of authoritative/male voices that create exclusive speech platforms, along the assumption that voices have to be rational, authoritative (voice of expertise) etc. The intervention that changes the paradigm becomes a set of podcasts that revisit the sound material produced in situated amplification meetings and soundwalks. Every podcast includes the previous one, on a way that creates repetetive layers of the same material. Creating presence by repetetion.'Revisiting podcasts' are upsetting binaries such as male/female, expert/amateur, rational/irrational">About</a></div> <a style="font-size: 28px;margin-right: 90%;" href="#" title="It is a collection of audio recordings coming from meetings I co-organised, internet sources, podcasts and soundwalks. 'Revisiting podcasts' questions the establishment of authoritative/male voices that create exclusive speech platforms, along the assumption that voices have to be rational, authoritative (voice of expertise) etc. The intervention that changes the paradigm becomes a set of podcasts that revisit the sound material produced in situated amplification meetings and soundwalks. Every podcast includes the previous one, on a way that creates repetetive layers of the same material. Creating presence by repetetion.'Revisiting podcasts' are upsetting binaries such as male/female, expert/amateur, rational/irrational">About</a></div> -->
<!-- menu --> <!-- menu -->
@ -48,10 +59,10 @@
<div class="tab"> <div class="tab">
<button class="tablinks" style="position: absolute;font-size: 28px;margin-right: 90%; padding: 8px !important;" onclick="openCity(event, 'menu')">Dive Into</button> <button class="tablinks" style="position: absolute;font-size: 28px !important;margin-right: 90%; padding: 8px !important;margin-top: 4% !important;" onclick="openCity(event, 'menu')">Dive Into</button>
</div> </div>
<div id="menu" class="tabcontent" style="left: 5px !important; top: 300px !important; width: 1400px !important;padding: 0px 0px 0px 0px !important;"> <div id="menu" class="tabcontent" style="font-size: 28px !important; left: 5px !important; top: 300px !important; width: 1000px !important;padding: 0px !important;">
<span onclick="this.parentElement.style.display='none'" class="topright">&times</span> <span onclick="this.parentElement.style.display='none'" class="topleft">&times</span>
<ul> <ul>
<li class="list" style="border-top: none !important;"> <li class="list" style="border-top: none !important;">
<a href="podcast1.php" target="_blank">Podcasts <div class="description">AUDIO MOMENTS</div></a> <a href="podcast1.php" target="_blank">Podcasts <div class="description">AUDIO MOMENTS</div></a>
@ -69,7 +80,7 @@
</li> </li>
<li class="list"> <li class="list">
<a href="player.html" target="_blank">Player <div class="description">ARCHIVE</div></a> <a href="player.html" target="_blank">Player <div class="description">AUDIO ARCHIVE</div></a>
</li></ul></div> </li></ul></div>
</div> </div>
@ -77,7 +88,7 @@
<div align="right" ><div style="background-color: pink;width: 300px;">questions arisen:<br> how to approach the gender of voice in matter of terminology?<br>how the community outside of institution interacts with the inside of institution?<br>what conflicts or frictions the technical aspect provokes</div></div>
</section> </section>

4
js/jquery.min.js vendored

File diff suppressed because one or more lines are too long

1446
js/libmp3lame.min.js vendored

File diff suppressed because it is too large Load Diff

@ -0,0 +1,41 @@
importScripts('libmp3lame.min.js');
var mp3codec;
this.addEventListener('message', function(e) {
switch (e.data.cmd) {
case 'init':
if (!e.data.config) {
e.data.config = { };
}
mp3codec = Lame.init();
Lame.set_mode(mp3codec, e.data.config.mode || Lame.JOINT_STEREO);
Lame.set_num_channels(mp3codec, e.data.config.channels || 2);
Lame.set_num_samples(mp3codec, e.data.config.samples || -1);
Lame.set_in_samplerate(mp3codec, e.data.config.samplerate || 44100);
Lame.set_out_samplerate(mp3codec, e.data.config.samplerate || 44100);
Lame.set_bitrate(mp3codec, e.data.config.bitrate || 128);
Lame.init_params(mp3codec);
// console.log('Version :', Lame.get_version() + ' / ',
// 'Mode: '+Lame.get_mode(mp3codec) + ' / ',
// 'Samples: '+Lame.get_num_samples(mp3codec) + ' / ',
// 'Channels: '+Lame.get_num_channels(mp3codec) + ' / ',
// 'Input Samplate: '+ Lame.get_in_samplerate(mp3codec) + ' / ',
// 'Output Samplate: '+ Lame.get_in_samplerate(mp3codec) + ' / ',
// 'Bitlate :' +Lame.get_bitrate(mp3codec) + ' / ');
// 'VBR :' + Lame.get_VBR(mp3codec));
break;
case 'encode':
var mp3data = Lame.encode_buffer_ieee_float(mp3codec, e.data.buf, e.data.buf);
self.postMessage({cmd: 'data', buffer: mp3data.data});
break;
case 'finish':
var mp3data = Lame.encode_flush(mp3codec);
self.postMessage({cmd: 'end', buffer: mp3data.data});
Lame.close(mp3codec);
mp3codec = null;
break;
}
});

@ -0,0 +1,157 @@
(function(window){
var RECORDER_WORKER_PATH = 'js/recorderWorker.js';
var ENCODER_WORKER_PATH = 'js/mp3Worker.js';
var MP3Recorder = function(context, stream, cfg) {
var config = cfg || { statusContainer: null, statusMethod: 'append' }
var bufferLen = 4096;
var recording = false;
this.source = context.createMediaStreamSource(stream);
this.node = (context.createScriptProcessor || context.createJavaScriptNode).call(context, bufferLen, 1, 1);
var recorderWorker = new Worker(RECORDER_WORKER_PATH);
var encoderWorker = new Worker(ENCODER_WORKER_PATH);
var exportCallback;
// initialize the Recorder Worker
recorderWorker.postMessage({ cmd: 'init', sampleRate: context.sampleRate });
// the recording loop
this.node.onaudioprocess = function(e) {
if(!recording) return;
recorderWorker.postMessage({ cmd: 'record', buffer: e.inputBuffer.getChannelData(0) });
}
this.start = function() {
recording = true;
this.logStatus('recording...');
}
this.stop = function() {
recording = false;
this.logStatus('stopping...');
}
this.destroy = function() { recorderWorker.postMessage({ cmd: 'destroy' }); }
this.logStatus = function(status) {
if(config.statusContainer) {
if(config.statusMethod == 'append') {
config.statusContainer.text(config.statusContainer.text + "\n" + status);
} else {
config.statusContainer.text(status);
}
}
}
this.exportBlob = function(cb) {
exportCallback = cb;
if (!exportCallback) throw new Error('Callback not set');
recorderWorker.postMessage({ cmd: 'exportBlob' });
}
this.exportWAV = function(cb) {
// export the blob from the worker
this.exportBlob(function(blob) {
var fileReader = new FileReader();
// read the blob as array buffer and convert it
// to a base64 encoded WAV buffer
fileReader.addEventListener("loadend", function() {
var resultBuffer = new Uint8Array(this.result);
cb(encode64(resultBuffer));
});
fileReader.readAsArrayBuffer(blob);
});
}
this.exportMP3 = function(cb) {
this.logStatus('converting...');
// export the blob from the worker
this.exportBlob(function(blob) {
var fileReader = new FileReader();
fileReader.addEventListener("loadend", function() {
var wavBuffer = new Uint8Array(this.result);
var wavData = parseWav(wavBuffer);
encoderWorker.addEventListener('message', function(e) {
if (e.data.cmd == 'data') {
cb(encode64(e.data.buffer));
}
});
encoderWorker.postMessage({ cmd: 'init', config: { mode: 3, channels: 1, samplerate: wavData.sampleRate, bitrate: wavData.bitsPerSample } });
encoderWorker.postMessage({ cmd: 'encode', buf: Uint8ArrayToFloat32Array(wavData.samples) });
encoderWorker.postMessage({ cmd: 'finish' });
});
fileReader.readAsArrayBuffer(blob);
});
}
// event listener for return values of the recorderWorker
recorderWorker.addEventListener('message', function(e) {
switch(e.data.from) {
case 'exportBlob':
exportCallback(e.data.blob);
break;
};
});
// HELPER FUNCTIONS
function encode64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for(var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
function parseWav(wav) {
function readInt(i, bytes) {
var ret = 0, shft = 0;
while(bytes) {
ret += wav[i] << shft; shft += 8;
i++; bytes--;
}
return ret;
}
if(readInt(20, 2) != 1) throw 'Invalid compression code, not PCM';
if(readInt(22, 2) != 1) throw 'Invalid number of channels, not 1';
return { sampleRate: readInt(24, 4), bitsPerSample: readInt(34, 2), samples: wav.subarray(44) };
}
function Uint8ArrayToFloat32Array(u8a){
var f32Buffer = new Float32Array(u8a.length);
for (var i = 0; i < u8a.length; i++) {
var value = u8a[i<<1] + (u8a[(i<<1)+1]<<8);
if (value >= 0x8000) value |= ~0x7FFF;
f32Buffer[i] = value / 0x8000;
}
return f32Buffer;
}
this.source.connect(this.node);
this.node.connect(context.destination); // this should not be necessary
}
window.MP3Recorder = MP3Recorder;
})(window);

@ -0,0 +1,130 @@
var recordingLength = 0,
recordingBuffer = [],
bits = 16,
sampleRate = 0;
this.addEventListener('message', function(e) {
switch (e.data.cmd) {
case 'init':
init(e.data.sampleRate);
break;
case 'start':
start();
break;
case 'stop':
stop();
break;
case 'destroy':
destroy();
break;
case 'record':
record(e.data.buffer);
break;
case 'exportBlob':
exportBlob();
break;
}
});
function init(sr) {
sampleRate = sr;
}
function start() {
}
function stop() {
}
function destroy() {
recordingLength = 0;
recordingBuffer = [];
sampleRate = 0;
}
function record(buffer) {
recordingBuffer.push(buffer);
recordingLength += buffer.length;
}
function exportBlob() {
var audioBlob = new Blob([encodeWAV(mergeBuffer(recordingBuffer, recordingLength))]);
this.postMessage({ from: 'exportBlob', blob: audioBlob });
}
// HELPER FUNCTIONS
function mergeBuffer(buf, len){
var result = new Float32Array(len);
var offset = 0;
for (var i = 0; i < buf.length; i++){
result.set(buf[i], offset);
offset += buf[i].length;
}
return result;
}
function encodeWAV(samples){
var buffer = new ArrayBuffer(44 + samples.length * 2);
var view = new DataView(buffer);
/* RIFF identifier */
writeString(view, 0, 'RIFF');
/* file length */
view.setUint32(4, 32 + samples.length * 2, true);
/* RIFF type */
writeString(view, 8, 'WAVE');
/* format chunk identifier */
writeString(view, 12, 'fmt ');
/* format chunk length */
view.setUint32(16, 16, true);
/* sample format (raw) */
view.setUint16(20, 1, true);
/* channel count */
//view.setUint16(22, 2, true); /*STEREO*/
view.setUint16(22, 1, true); /*MONO*/
/* sample rate */
view.setUint32(24, sampleRate, true);
/* byte rate (sample rate * block align) */
//view.setUint32(28, sampleRate * 4, true); /*STEREO*/
view.setUint32(28, sampleRate * 2, true); /*MONO*/
/* block align (channel count * bytes per sample) */
//view.setUint16(32, 4, true); /*STEREO*/
view.setUint16(32, 2, true); /*MONO*/
/* bits per sample */
view.setUint16(34, 16, true);
/* data chunk identifier */
writeString(view, 36, 'data');
/* data chunk length */
view.setUint32(40, samples.length * 2, true);
floatTo16BitPCM(view, 44, samples);
return view;
}
function floatTo16BitPCM(output, offset, input){
for (var i = 0; i < input.length; i++, offset+=2){
var s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
function writeString(view, offset, string){
for (var i = 0; i < string.length; i++){
view.setUint8(offset + i, string.charCodeAt(i));
}
}

@ -22,8 +22,8 @@
</div> </div>
<div id="utterance" class="tabcontent"> <div id="utterance" class="tabcontent">
<span onclick="this.parentElement.style.display='none'" class="topright">&times</span> <span onclick="this.parentElement.style.display='none'" class="topright">&times</span>
<p>How can we engage politically with the exclusion of specific (female) voices from the public sphere through our own voice? Here I document my attempts to create a safe common space of discussing that topic in Leeszaal, that I consider a diverse public space, where we can explore our public voices in situ, and trying out vocal performances. I am doing that together with Christina Karagianni, who is also from Greece and with whom I share similar experiences of silencing. We combine our practices -her practice lies on choreography and mine on social interaction and sound- and try vocal exercises and reading in moments of Leeszaal. Structure of the meetings: reading extracts in random order, discuss peronal associations, warm up, say a personal sentence in any language, transcribe only the vowels, read back the vowels, sing all together the score of vowels. How can we engage politically with the exclusion of specific (female) voices from the public sphere through our own voice? Here I document my attempts to create a safe common space of discussing that topic in Leeszaal, that I consider a diverse public space, where we can explore our public voices in situ, and trying out vocal performances. I am doing that together with Christina Karagianni, who is also from Greece and with whom I share similar experiences of silencing. We combine our practices -her practice lies on choreography and mine on social interaction and sound- and try vocal exercises and reading in moments of Leeszaal.<div class="tooltip-wrap" style="display: inline;text-decoration:underline;">We invite <div class="tooltip-content-right" ><div>how we should approch the gender terminology and false association with voice when inviting people? Should it be about femme sounding? Female voice? </div></div></div>women from Leeszaal. Structure of the meetings: reading extracts in random order, <div class="tooltip-wrap" style="display: inline;text-decoration:underline;">discuss <div class="tooltip-content-right" ><div>what conflicts or frictions the technical aspect provokes?</div></div></div>personal associations and experiences with voice in public, warm up, say a personal sentence in any language, transcribe only the vowels, read back the vowels, sing all together the score of vowels.
</p></div> </div>
</div> </div>
@ -78,6 +78,8 @@
<!-- recordings --> <!-- recordings -->
<section> <section>
<div style="position:absolute; top:15%; left:41%;"> <div style="position:absolute; top:15%; left:41%;">
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>warming up @Leeszaal <audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>warming up @Leeszaal
@ -374,6 +376,175 @@ Oh, I hear children in the background crying</div>
</section> </section>
<div class="container">
<div class="rowcircle">
<span>
<div class="tooltip-wrap">
<audio controls src="audio/finearts-meeting-discussion.mp3"></audio>discussing about voice in public @Fine Arts
<div class="tooltip-content-down">
<table>
<tr>
<td><img src="images/meeting-20190329-finearts-1.JPG" width="500px" />
</td>
</tr>
</table>
</div>
</div>
</span>
<span><audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>warming up @Leeszaal</audio></span>
</div>
<div class="rowcircle">
<span><audio controls src="audio/leeszaal-meetings-warming.mp3"></audio></span>
<span><audio controls src="audio/leeszaal-meetings-warming.mp3"></audio></span>
<span><audio controls src="audio/leeszaal-meetings-warming.mp3"></audio></span>
</div>
<div class="rowcircle">
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
</div>
<div class="rowcircle">
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
</div>
<div class="rowcircle">
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>
</div>
<section>
<div style="position:absolute; top:15%; left:41%;">
<audio controls src="audio/leeszaal-meetings-warming.mp3"></audio>warming up @Leeszaal
</div>
<div class="tooltip-wrap" style="position:absolute; top:12%; left:51%;">
<audio controls src="audio/leeszaal-meetings-choir.mp3"></audio>singing vowels @Leeszaal
<div class="tooltip-content-down">
<div class="row">
<div class="column"><img src="images/vowels-20190328-leeszaal.jpg" width="500px">
</div>
<!-- <div class="column"><img src="images/meeting-20190328-leeszaal-5.JPG" width="500px">
</div> -->
</div>
</div>
</div>
<div style="position:absolute; top:20%; left:63%;">
<audio controls src="audio/description-alex2.mp3"></audio>describing/annotating
</div>
<div class="tooltip-wrap" style="position:absolute; top:30%; left:70%;">
<audio controls src="audio/finearts-meeting-discussion.mp3"></audio>discussing about voice in public @Fine Arts
<div class="tooltip-content-down">
<table>
<tr>
<td><img src="images/meeting-20190329-finearts-1.JPG" width="500px" />
</td>
</tr>
</table>
</div>
</div>
<div class="tooltip-wrap" style="position:absolute; top:42%; left:75%;">
<audio controls src="audio/leeszaal-meetings-transcribing.mp3"></audio>transcribing vowels @Leeszaal
<div class="tooltip-content-down">
<div class="row">
<div class="column"><img src="images/meeting-20190328-leeszaal-1.JPG" width="500px" />
</div>
</div>
</div>
</div>
<div class="tooltip-wrap" style="position:absolute; top:55%; left:69%;">
<audio controls src="audio/finearts-meeting-choir.mp3"></audio>singing vowels @Fine Arts
<div class="tooltip-content-down">
<div class="row">
<div class="column"><img src="images/vowels-20190329-finearts.jpg" width="500px" />
</div>
</div>
</div>
</div>
<div class="tooltip-wrap" style="position:absolute; top:65%; left:63%;">
<audio controls src=""></audio>
<div class="tooltip-content-up">
<table>
<tr>
</tr>
</table>
</div>
</div>
<div style="position:absolute; top:70%; left:53%;">
<audio controls src=""></audio>
</div>
<div style="position:absolute; top:57%; left:33%;;">
<audio controls src="audio/finearts-meeting-choirhigh.mp3"></audio>singing vowels (high) @Fine Arts
</div>
<div style="position:absolute; top:33%; left:26%;;">
<audio controls src=""></audio>
</div>
<div class="tooltip-wrap" style="position:absolute; top:46%; left:28%;">
<audio controls src="audio/leeszaal-meetings-discussion.mp3"></audio>discussing about voice in public @Leeszaal
<div class="tooltip-content-up">
<table>
<tr>
<td><img src="images/meeting-20190328-leeszaal-2.JPG" width="500px" />
</td>
</tr>
</table>
</div>
</div>
<div style="position:absolute; top:66%; left:41%;;">
<audio controls src="audio/finearts-meeting-warming.mp3"></audio>warming up @Fine Arts
</div>
<div class="tooltip-wrap" style="position:absolute; top:23%; left:32%;">
<audio controls src="audio/finearts-meeting-transcribing.mp3"></audio>transcribing vowels @Fine Arts
<div class="tooltip-content-down">
<table>
<tr>
<td><img src="images/meeting-20190329-finearts-2.JPG" width="500px" />
</td>
</tr>
</table>
</div>
</div>
<div class="tooltip-wrap" style="position:absolute; top:27%; left:29%;">
<audio controls src="audio/finearts-meeting-extracts.mp3"></audio>reading extracts @Fine Arts
<div class="tooltip-content-down">
<table>
<tr>
<td><img src="images/carson-extract.jpg" width="500px" />
</td>
<td><img src="images/fresh1.jpg" width="500px" />
</td>
<td><img src="images/fresh2.jpg" width="500px" />
</td>
</tr>
</table>
</div>
</div>
</section>

@ -2,6 +2,9 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/mp3recorder.js"></script>
<link href="styles/stylesheet.css" rel="stylesheet" type="text/css"> <link href="styles/stylesheet.css" rel="stylesheet" type="text/css">
</head> </head>
<body> <body>
@ -18,6 +21,8 @@
"Mediating speech" "Mediating speech"
</h3> </h3>
This podcast is a series of episodes of moments of an online audio archive overlayered by my voice as a narrator.
<table><tr> <table><tr>
<?php <?php
$files = glob("podcasts/podcast1/*.mp3"); $files = glob("podcasts/podcast1/*.mp3");
@ -35,7 +40,8 @@ echo '</p></div></td>'; } ?>
<div align="center"> <div align="center">
<div style="width: 500px;border:1px red;border-style: dashed;padding: 10px;"> <div style="width: 500px;border:1px red;border-style: dashed;padding: 10px;">
<p>Dear listener,</p> <p>Dear listener,</p>
<p>you are invited to amplify parts of the podcasts that you find interesting by repeating them or annotate them with your vocal messages. You can listen to the podcasts with headphones... </p> <p>you are invited to amplify parts of the podcasts that you find interesting by repeating them or annotate them with your vocal messages. You can listen to the podcasts with headphones and record with any microphone. </p>
<!-- keep the time of file limited -->
</div> </div>
<!-- https://github.com/mdn/web-dictaphone/ --> <!-- https://github.com/mdn/web-dictaphone/ -->
@ -52,27 +58,26 @@ echo '</p></div></td>'; } ?>
</div> </div>
</div> </div>
<section style="float:right;"> <div class="recorder">
<input type="button" class="start" value="Record" />
<input type="button" class="stop" value="Stop" />
<pre class="status"></pre>
</div>
<div><button onclick="upload()">Upload</button></div>
<div id="playerContainer"></div>
<div id="dataUrlcontainer" hidden></div>
<!-- save the new recordings -->
<!-- <?php
if(!is_dir("recordings")){
$res = mkdir("recordings",0777);
}
// pull the raw binary data from the POST array <pre id="log"></pre>
$data = substr($_POST['data'], strpos($_POST['data'], ",") + 1);
$filename = urldecode($_POST['fname']);
// write the data out to the file <audio controls="true" id="audio" src=""></audio>
$fp = fopen('recordings/'.$filename, 'wb');
fwrite($fp, $decodedData);
fclose($fp);
?> -->
<div id="dataUrlcontainer" hidden></div>
<section style="float:right;">
<!-- scripts for dictaphone --> <!-- scripts for dictaphone -->
@ -81,6 +86,10 @@ fclose($fp);
<!-- Below is your custom application script --> <!-- Below is your custom application script -->
<script src="scripts/app.js"></script> <script src="scripts/app.js"></script>
<script> <script>
function saveAudio(){ function saveAudio(){
var req = null; var req = null;
@ -125,32 +134,10 @@ if(($type == 'audio/x-wav' || $type == 'application/octet-stream') && preg_match
?> ?>
</script> </script>
<!-- save recordings -->
<!-- <script>
function uploadAudio(mp3Data){
var reader = new FileReader();
reader.onload = function(event){
var fd = new FormData();
var mp3Name = encodeURIComponent('audio_recording_' + new Date().getTime() + '.mp3');
console.log("mp3name = " + mp3Name);
fd.append('fname', mp3Name);
fd.append('data', event.target.result);
$.ajax({
type: 'POST',
url: 'upload.php',
data: fd,
processData: false,
contentType: false
}).done(function(data) {
//console.log(data);
log.innerHTML += "\n" + data;
});
};
reader.readAsDataURL(mp3Data);
}
</script> -->
<!-- script for subs and sound --> <!-- script for subs and sound -->
<script> <script>
@ -177,6 +164,94 @@ if(($type == 'audio/x-wav' || $type == 'application/octet-stream') && preg_match
; ;
</script> </script>
<!-- scripts for recorder -->
<script type="text/javascript">
var audio_context;
function __log(e, data) {
log.innerHTML += "\n" + e + " " + (data || '');
}
$(function() {
try {
// webkit shim
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
window.URL = window.URL || window.webkitURL;
var audio_context = new AudioContext;
__log('Audio context set up.');
__log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
} catch (e) {
alert('No web audio support in this browser!');
}
$('.recorder .start').on('click', function() {
$this = $(this);
$recorder = $this.parent();
navigator.getUserMedia({audio: true}, function(stream) {
var recorderObject = new MP3Recorder(audio_context, stream, { statusContainer: $recorder.find('.status'), statusMethod: 'replace' });
$recorder.data('recorderObject', recorderObject);
recorderObject.start();
}, function(e) { });
});
$('.recorder .stop').on('click', function() {
$this = $(this);
$recorder = $this.parent();
recorderObject = $recorder.data('recorderObject');
recorderObject.stop();
recorderObject.exportWAV(function(base64_wav_data) {
var url = 'data:audio/wav;base64,' + base64_wav_data;
var au = document.createElement('audio');
document.getElementById("playerContainer").innerHTML = "";
//console.log(url)
var duc = document.getElementById("dataUrlcontainer");
duc.innerHTML = url;
au.controls = true;
au.src = url;
//$recorder.append(au);
$('#playerContainer').append(au);
recorderObject.logStatus('');
});
});
});
</script>
<script>
function upload(){
var dataURL = document.getElementById("dataUrlcontainer").innerHTML;
$.ajax({
type: "POST",
url: "scripts/uploadWav.php",
data: {
wavBase64: dataURL
}
}).done(function(o) {
console.log('saved');
});
}
</script>

@ -85,68 +85,54 @@ if (navigator.mediaDevices.getUserMedia) {
console.log("recorder stopped"); console.log("recorder stopped");
// fetch(audioURL)
// .then(response => response.blob())
// .then(blob => {
// // do stuff with `blob`: `Blob`
// console.log(blob);
// });
// var file = new File([blob], 'filename.ogg', {type: 'audio/ogg; codecs=opus', lastModified: Date.now()});
// var url = (window.URL || window.webkitURL).createObjectURL(blob);
// console.log(url);
// var filename = <?php echo $filename;?>;
// var data = new FormData();
// data.append('file', blob);
// $.ajax({
// url : "vocal.php",
// type: 'POST',
// data: data,
// contentType: false,
// processData: false,
// success: function(data) {
// alert("boa!");
// },
// error: function() {
// alert("not so boa!");
// }
// });
// var xhr = new XMLHttpRequest(); function upload(){
// xhr.open('POST', 'audio/', true);
// xhr.onload = function(e) {
// console.log('Sent'); $.ajax({
// }; type: "POST",
// xhr.send(blob) url: "scripts/uploadWav.php",
data: {
wavBase64: audioURL
// request blob }
// var xhr = new XMLHttpRequest(); }).done(function(o) {
// xhr.open('GET', audioURL, true); console.log('saved');
// xhr.responseType = 'blob';
// xhr.onload = function(e) { });
// if (this.status == 200) {
// var myBlob = this.response; }
// // myBlob is now the blob that the object URL pointed to.
// } upload();
// #2
// var audioControl = document.getElementById('audio');
// // 2: Serialize the data to localStorage and read it back then play...
// var base64FileData = audioURL.toString();
// var mediaFile = {
// fileUrl: audioURL,
// size: blob.size,
// type: blob.type,
// src: base64FileData
// }; // };
// xhr.send();
// // save the file info to localStorage
// let file = await fetch(audioURL).then(r => r.blob()).then(blobFile => new File([blobFile], "audio/", { type: "audio/ogg; codecs=opus" }) // localStorage.setItem('myTest', JSON.stringify(mediaFile));
// // read out the file info from localStorage again
// var xhr = new XMLHttpRequest(); // var reReadItem = JSON.parse(localStorage.getItem('myTest'));
// xhr.open('GET',
// audioURL, // audioControl.src = reReadItem.src;
// true);
// xhr.responseType = "blob";
// xhr.onload = function(e){ //Stringify blob...
// //reload the icon from storage
// var fr = new FileReader();
// fr.onload =
// function(e) {
// localStorage['audio/'] = e.target.result;
// document.getElementById("myicon").src = localStorage['audio/'];
// }
// fr.readAsDataURL(xhr.response);
// }
// xhr.send(null);
deleteButton.onclick = function(e) { deleteButton.onclick = function(e) {
evtTgt = e.target; evtTgt = e.target;

@ -0,0 +1,12 @@
<?php
// requires php5
define('UPLOAD_DIR', '../uploads/');
$img = $_POST['wavBase64'];
$img = str_replace('data:audio/wav;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . uniqid() . '.wav';
$success = file_put_contents($file, $data);
print $success ? $file : 'Unable to save the file.';
?>

@ -1,6 +1,6 @@
body {font-family: "Old Standard TT"; font-size: 20px; line-height: 2.5; letter-spacing: 1px;} body {font-family: "Old Standard TT"; font-size: 20px; line-height: 2.5; letter-spacing: 1px;}
section {margin-bottom: 50px;margin-top: 20px;} section {margin-bottom: 50px;margin-top: 20px;}
a {font-weight: bold; text-decoration: none; } a {font-weight: normal; text-decoration: none; }
.navbar { .navbar {
letter-spacing: 4px; letter-spacing: 4px;
@ -43,6 +43,7 @@ display: block;
.list { .list {
padding-top: 10px; padding-top: 10px;
padding-bottom: 10px; padding-bottom: 10px;
padding-left: 0;
list-style: none; list-style: none;
border-top: 1px solid #47505e; border-top: 1px solid #47505e;
} }
@ -304,9 +305,23 @@ cursor: pointer;
border-style:solid; border-style:solid;
border-color:black; border-color:black;
text-align: left; text-align: left;
}
.tooltip-wrap .tooltip-content-right {
display: none;
position: absolute;
z-index:1;
top: 100%;
/*bottom: 100%;*/
left: 2%;
/*right: 100%;*/
padding: .2em;
background-color: pink;
border:none;
text-align: left;
min-width: 400px;}
}
.tooltip-wrap .tooltip-content-up { .tooltip-wrap .tooltip-content-up {
display: none; display: none;
position: absolute; position: absolute;
@ -330,6 +345,10 @@ cursor: pointer;
display: block; display: block;
} }
.tooltip-wrap:hover .tooltip-content-right {
display: block;
}
/*.tooltip-wrap:hover { /*.tooltip-wrap:hover {
background-color: pink; background-color: pink;
} }
@ -434,15 +453,26 @@ cursor: pointer;
border: 1px solid black; border: 1px solid black;
float: left; float: left;
position: absolute; position: absolute;
width: 600px; width: 800px;
z-index: 1; z-index: 1;
background-color: white; background-color: white;
top: 5px; top: 5px;
} }
/* Style the close button */ /* Style the close button */
.topright { .topleft {
float: right; float: left;
cursor: pointer; cursor: pointer;
font-size: 28px; font-size: 28px;
} }
.container .rowcircle {
margin: 25px;
text-align: center;
}
.container .rowcircle span {
margin: 0 200px;
/*margin-right: 90px;*/
}

@ -0,0 +1,41 @@
<!DOCTYPE html>
<style type="text/css">
body {font-family: "Old Standard TT"; font-size: 20px; line-height: 1.4; letter-spacing: 1px;}
h2 {
text-align: center;
letter-spacing: 4px;
font-size: 28px;}
section {margin-bottom: 100px; margin-top: 50px;}
table, th, td {vertical-align: top; border-collapse: separate; padding: 6px;}
button {width: 100px;}
.short-description{
margin-left: 40%;
margin-right: 40%;
text-align: center;
}
a {
text-decoration:none;
}
</style>
<html>
<head>
<section>
<h2 >Extracts</h2>
<div class="short-description">
<p>"Nusra considered their voices shameful, a form of nakedness" </p>
<p>
<a href="../index.html">Utterance</a>
</p>
</div>
</section>
<img src="texts/fresh1.jpg" width="35%"></img>
<img src="texts/fresh2.jpg" width="35%"></img>
<img src="texts/carson-extract.jpg" width="28%"></img>
<img src="http://pzwiki.wdka.nl/mw-mediadesign/images/1/13/Extracts-reading.jpg" width="100%" style="margin-top: 150px;"></img>
</head>
<body>
</body>
</html>

Binary file not shown.

@ -0,0 +1 @@
nZ†Ûiÿùhq©a¢ËoZm¦ßá¯8á­»÷¦º×^¼íÎv}ý
Loading…
Cancel
Save