kramann.info
© Guido Kramann

Login: Passwort:










6.3.3 Hinzufügen der Empfangs-Funktionalität

6.3.3 Add the receive functionality (EN google-translate)

6.3.3 Dodaj funkcję odbierania (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 6.3.3-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 6.3.3-2: Anwendungsteil in Datei Teste_Audiotransfer.html