Hinzufügen der Empfangs-Funktionalität
(EN google-translate)
(PL google-translate)
03_empfangen.zip - Projektdateien.
function Audiotransfer()
{
const TONDAUER_PROZ_ZYKLEN = 20; //Hiervon hängt die Geschwindigkeit der Datenübertragung ab.
const SCHWELLE = 5; //Faktor zwischen kennzahlen von gefundenem und nicht gefundenem Ton
const AUDIO_PUFFER_GROESSE = 2048;
const TOENE = [500,63,42,28];
var audiopuffer = new Array(AUDIO_PUFFER_GROESSE);
var DATA_IN = null;
var ZAEHLER = 0;
var DURCHLAUF = 0; // Anzahl Durchläaufe von prozess(e) wg. tonwechsel()
var DZ = TOENE[0];
var kennzahl = [0,0,0];
var kennzahl_phase = [63,42,28];
var signal_nummer = 0; //0==kein Signal, 1==Ton 1, 2==Ton2, 3==Ton3
var sendepuffer = new Array();
var merker = new Array(8); //Hilfsvariable für sendeZahl()
//**********************************************************************************
//Variablen im Zusammenhang mit dem Empfang von Zeichen:
var zahl_empfangen = 0; //Wert der aktuell empfangenen Zahl
var empfangspuffer = new Array(); //Puffer mit empfangenen Zahlen
var EMPFANGSZUSTAND = 0; //0==KEIN TON,
//1==1. Teil von Bit 7, 2==2. Teil von Bit 7,
//3==erster Teil von Bit 6 usw.
//erlaubt: 0, 1,2, 3,4 5,6, 7,8, 9,10, 11,12, 13,14, 15,16
const TIMEOUT_PROZ_ZYKLEN = TONDAUER_PROZ_ZYKLEN; //nach so vielen process(e)-Zyklen muß der jeweils nächste Zustand erreicht sein.
var WARTE_ZYKLUS = 0; //so oft wurde bereits auf den nächsten erwarteten Zustand gewartet.
var EMPFANG_OK = true; //Bei Timeout auf false setzen!
var NULL_PHASE=0;
//BESONDERHEIT: Es wird immer nur auf dasjenige ereignis gewartet, das zu erwarten ist.
//BESONDERHEIT2: läuft auch bei Fehler alle Bits durch, jedoch in halbem Tempo!
//Darum sollte der KEIN TON Bereich 2x so lange sein, wie der Sendebereich
//**********************************************************************************
//*************************************
//*** Funktionen zu Wartungszwecken ***
//*************************************
//Um den Audiopuffer zu visualiseren:
this.holeAudiopuffer = function()
{
if(DATA_IN!=null && DATA_IN.length==AUDIO_PUFFER_GROESSE)
{
for(var i=0;i<DATA_IN.length;i++)
audiopuffer[i] = DATA_IN[i];
}
return audiopuffer;
}
//..um bei langsamem Verlauf den aktuell erkannten Ton anzeigen zu können.
this.holeSignalnummer = function()
{
return signal_nummer;
}
//..Empfangszustand abrufen
this.holeEMPFANGSZUSTAND = function()
{
return EMPFANGSZUSTAND;
}
//..Empfangszustand abrufen
this.holeZAHLEMPFANGEN = function()
{
return zahl_empfangen;
}
//**************************
//*** Private Funktionen ***
//**************************
function tonwechsel()
{
//Falls mehr als 0 Einträge in sendepuffer,
//Dann ersten Toneintrag übernehmen und löschen.
//andernfalls KEIN TON senden.
if(sendepuffer!=null && sendepuffer.length>0)
{
DZ = sendepuffer[0];
sendepuffer.shift(); //entfernt erstes Element, vergl. http://www.w3schools.com/jsref/jsref_shift.asp
}
else
{
DZ = TOENE[0]; //KEIN (DEFINIERTER) TON
}
}
function prozess(e)
{
var data_in = e.inputBuffer.getChannelData(1);
var data_out = e.outputBuffer.getChannelData(1);
//Um den Audiopuffer zu visualiseren:
DATA_IN = data_in;
for (var i = 0; i < data_out.length; ++i)
{
if(ZAEHLER<14)
data_out[i] = 0.5;
else
data_out[i] = 0.0;
ZAEHLER++;
ZAEHLER%=DZ;
}
//Berechnung der drei Kennzahlen:
for(var k=0;k<kennzahl.length;k++)
{
kennzahl[k]=0;
var phase = kennzahl_phase[k];
var wert = 0;
for(var i=0;i<data_in.length;i++)
{
wert = data_in[i] - data_in[(i+phase)%data_in.length];
wert = wert*wert;
kennzahl[k]+=wert;
}
}
//Signalnummer aus Kennzahl bestimmen:
if(kennzahl[1]/kennzahl[0]>SCHWELLE && kennzahl[2]/kennzahl[0]>SCHWELLE)
signal_nummer = 1;
else if(kennzahl[0]/kennzahl[1]>SCHWELLE && kennzahl[2]/kennzahl[1]>SCHWELLE)
signal_nummer = 2;
else if(kennzahl[0]/kennzahl[2]>SCHWELLE && kennzahl[1]/kennzahl[2]>SCHWELLE)
signal_nummer = 3;
else
signal_nummer = 0;
//EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
//EMPFANGS-BEREICH: Verarbeiten der signal_nummer abhängig von EMPFANGSZUSTAND
//Immer zurücksetzen, bei längerer 0-Phase:
if(signal_nummer==0)
{
NULL_PHASE++;
}
else
{
NULL_PHASE=0;
}
if(NULL_PHASE>=TONDAUER_PROZ_ZYKLEN*2)
{
NULL_PHASE=0;
WARTE_ZYKLUS=0;
EMPFANGSZUSTAND=0;
}
if(EMPFANGSZUSTAND>=16)
{
if(EMPFANG_OK==true)
{
empfangspuffer.push(zahl_empfangen);
}
WARTE_ZYKLUS=0;
EMPFANGSZUSTAND=0;
}
else if(EMPFANGSZUSTAND==0)
{
//es wird signal_nummer==1 erwartet
//hier stets reinitialisieren:
WARTE_ZYKLUS=0;
zahl_empfangen=0;
if(signal_nummer==1)
{
EMPFANGSZUSTAND++;
}
}
else if(EMPFANGSZUSTAND>0 && EMPFANGSZUSTAND%2==1) //1 3 5 7 9 11 13 15
{
if(WARTE_ZYKLUS>TIMEOUT_PROZ_ZYKLEN)
{
EMPFANG_OK=false;
WARTE_ZYKLUS=0;
zahl_empfangen*=2;
EMPFANGSZUSTAND++;
}
else if(signal_nummer==2)
{
zahl_empfangen*=2;
WARTE_ZYKLUS=0;
EMPFANGSZUSTAND++;
}
else if(signal_nummer==3)
{
zahl_empfangen*=2;
zahl_empfangen++;
WARTE_ZYKLUS=0;
EMPFANGSZUSTAND++;
}
else
{
WARTE_ZYKLUS++;
}
}
else //if(EMPFANGSZUSTAND>0 && EMPFANGSZUSTAND<16 && EMPFANGSZUSTAND%2==0) //2 4 6 8 10 12 14
{
if(WARTE_ZYKLUS>TIMEOUT_PROZ_ZYKLEN)
{
EMPFANG_OK=false;
WARTE_ZYKLUS=0;
EMPFANGSZUSTAND++;
}
else if(signal_nummer==1)
{
WARTE_ZYKLUS=0;
EMPFANGSZUSTAND++;
}
}
//EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
if(DURCHLAUF>=TONDAUER_PROZ_ZYKLEN)
{
tonwechsel();
DURCHLAUF=0;
}
DURCHLAUF++;
}
function init(e)
{
var context = new (window.AudioContext || window.webkitAudioContext)();
var volume = context.createGain(); //Ohne Volume-Knoten bleibt der Eingang stumm!
var audioInput = context.createMediaStreamSource(e);
audioInput.connect(volume);
var node = context.createScriptProcessor(AUDIO_PUFFER_GROESSE, 2, 2);
node.onaudioprocess = function(e) { prozess(e) };
volume.connect (node);
volume.gain.value=1.0;
node.connect(context.destination);
}
//*****************************************************
//*** Funktionen der Programmierschnittstelle (API) ***
//*****************************************************
this.sendeZahl = function(zahl)
{
if(zahl==null || typeof(zahl)!="number" || zahl<0 || zahl>255)
{
return false;
}
else
{
zahl = Math.floor(zahl); //sicherheitshalber nachkommastellen abschneiden.
//sendepuffer[sendepuffer.length] = zahl;
//besser:
//Zahl gleich in Tonfolgen zerlegen und diese in sendepuffer ablegen:
for(var i=7;i>=0;i--)
{
merker[i] = zahl%2;
zahl/=2;
zahl = Math.floor(zahl);
}
//sendepuffer[sendepuffer.length] = ..
//besser:
sendepuffer.push(TOENE[0]); //Länger KEIN TON
sendepuffer.push(TOENE[0]);
//for(var i=0;i<32;i++) //zur Sicherheit!!!! (sollte unbedingt verjkleinert werden!)
// sendepuffer.push(TOENE[0]);
//Dann Bits senden, also in Puffer Tonwechselfolge eintragen:
for(var i=0;i<merker.length;i++)
{
sendepuffer.push(TOENE[1]);
if(merker[i]==0)
sendepuffer.push(TOENE[2]);
else
sendepuffer.push(TOENE[3]);
}
sendepuffer.push(TOENE[0]); //Länger KEIN TON
sendepuffer.push(TOENE[0]);
return true;
}
}
this.sendeText = function(text)
{
if(text==null || typeof(text)!="string" || text.length==0)
{
return true;
}
else
{
for(var i=0;i<text.length;i++)
{
this.sendeZahl(text.charCodeAt(i));
}
}
}
this.holeZahl = function()
{
if(empfangspuffer== null || empfangspuffer.length==0)
{
return -1;
}
else
{
var zahl = empfangspuffer[0];
empfangspuffer.shift();
return zahl;
}
}
this.zahlLiegtVor = function()
{
if(empfangspuffer== null || empfangspuffer.length==0)
{
return false;
}
else
{
return true;
}
}
this.holeZeichen = function()
{
var zahl = this.holeZahl();
if(zahl==-1)
{
return "";
}
else
{
return String.fromCharCode(zahl);
}
}
this.holeText = function()
{
var text = "";
while(this.zahlLiegtVor())
text = text+this.holeZeichen();
return text;
}
this.initialisieren = function()
{
if (!navigator.getUserMedia)
{
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
}
if (navigator.getUserMedia)
{
//Mikrofon-Zugriff beim Benutzer anfordern
navigator.getUserMedia({audio:true}, init, function(e) {
alert('Error capturing audio.');
});
}
else
{
alert('getUserMedia not supported in this browser.');
}
}
}
Code 0-1: Klasse Audiotransfer in Datei Audiotransfer.js
<!DOCTYPE html>
<html>
<head lang="de">
<meta charset="iso-8859-1">
<script type="text/javascript" src="Audiotransfer.js"></script>
<script language:javascript>
var audiotransfer = null;
var malkontext = null;
function senden()
{
var text = document.getElementById("sendetext").value;
audiotransfer.sendeText(text);
}
function zeigeAudiopuffer()
{
var data_in = audiotransfer.holeAudiopuffer();
malkontext.fillStyle = "#000000";
malkontext.fillRect(0,0,1024,1000);
malkontext.strokeStyle="#ffffff";
malkontext.beginPath();
var x1 = 0;
var y1 = data_in[0]*200+200;
malkontext.moveTo(x1,y1);
for (var i = 0; i < data_in.length; i++)
{
var x2 = i;
var y2 = data_in[i]*200+200;
malkontext.lineTo(x2,y2);
}
malkontext.stroke();
document.getElementById("SIGNALNUMMER").innerHTML=audiotransfer.holeSignalnummer();
//Prüfen, ob etwas empfangen wurde, ggf. anfügen:
//var text = audiotransfer.holeText(); //erzeugt Seiteneffekt auf den Empfangszyklus!!!
var text = audiotransfer.holeZeichen();
if(text!="")
{
var text_bisher = document.getElementById("EMPFANGEN").value;
if(text_bisher!=null && text_bisher.length>0)
document.getElementById("EMPFANGEN").value = text_bisher+"\n"+text;
else
document.getElementById("EMPFANGEN").value = text;
}
//Zur Kontrolle den Empfangszustand darstellen:
document.getElementById("EMPFANGSZUSTAND").innerHTML=audiotransfer.holeEMPFANGSZUSTAND();
document.getElementById("empfangene_zahl").innerHTML=audiotransfer.holeZAHLEMPFANGEN();
}
function initialisieren()
{
malkontext = document.getElementById("grafik").getContext("2d");
audiotransfer = new Audiotransfer();
audiotransfer.initialisieren();
setInterval(zeigeAudiopuffer,50);
}
</script>
</head>
<body onload="javascript:initialisieren()">
<canvas id="grafik" width="1024" height="400"></canvas>
<h2>Erkannt wird Signalnummer: <span id="SIGNALNUMMER"></span></h2>
<h2>EMPFANGSZUSTAND: <span id="EMPFANGSZUSTAND"></span></h2>
<h2>empfangene_zahl: <span id="empfangene_zahl"></span></h2>
<br/>
<fieldset>
<input id="sendetext" type="text" style="width:200px;" value=""/>
<input id="senden" type="button" value="SENDEN" onclick="javascript:senden();"/>
<br/>
<p>Bisher empfangener Text:</p>
<br/>
<textarea id="EMPFANGEN" cols="40" rows="12"></textarea>
<br/>
</fieldset>
</body>
</html>
Code 0-2: Anwendungsteil in Datei Teste_Audiotransfer.html