kramann.info
© Guido Kramann

Login: Passwort:










3.11.5.2 Klangerzeugung mit Android unter Verwendung einer Audio-Datei.
3.11.5.2 Sound generation with Android using an audio file. (EN google-translate)
3.11.5.2 Generowanie dźwięku za pomocą Androida przy użyciu pliku audio. (PL google-translate)

Das vorhergehende Programm wird so ergänzt, dass eine wav-Audio-Datei zyklisch gespielt wird anstatt eines Sinustones.

The previous program will be completed in such a way that a wav audio file is played cyclically instead Ein Sinustones.

Poprzedni program zostanie ukończony w taki sposób, aby plik audio WAV jest odtwarzany cyklicznie Ein Sinustones.

Einige Hinweise zu dem nachfolgenden Programm

Some hints to the following program

Kilka wskazówek do następującego programu

Die Samplingrate der wav - Datei sr_wav könnte unterschiedlich zu der des Audiostreams sr sein. Dies wird in der Schleife berücksichtigt, wo zyklisch der Puffer aktualisiert wird.

The sampling rate of the wav file sr_wav could be different to be the audio stream sr. This is taken into account in the loop where the buffer is cyclically updated.

Częstotliwość próbkowania pliku wav sr_wav może być różna być strumieniem audio sr. Jest to brane pod uwagę w pętli, w której bufor jest cyklicznie aktualizowany.

Es wird die Technik eines kontinuierlichen Zeitstroms t beibehalten. Aus t wird zunächst der Zeitpunkt t_file berechnet. Das ist die zeitliche Stelle, die gerade von der zyklischen Datei gespielt werden muß.

It will maintain the technique of a continuous time t. The time t_file is first calculated from t. That is t temporal position that has to be played by the cyclic file.

Utrzyma technikę ciągłego czasu t. Czas t_file jest najpierw obliczany z t. To t pozycja czasowa, którą musi odtworzyć plik cykliczny.

Der Zeitpunkt t_file liegt im allgemeinen zwischen zwei Samples. Darum muß bestimmt werden welche beiden Samples das sind. Ihre Indices sind index_lo und index_hi.

The time t_file is generally between two samples. Therefore it must be determined which two samples are. Their indexes are index_lo and index_hi.

Czas t_file jest generalnie pomiędzy dwiema próbkami. Dlatego należy ustalić, które dwie próbki są. Ich indeksy to index_lo i index_hi.

Es wird dann noch bestimmt wo genau zwischen diesen Samples die aktuelle Zeit liegt und beide Samples werden gewichtet berücksichtigt.

It is then determined where exactly between these samples the current Time is up and both samples are weighted.

Następnie określa się, gdzie dokładnie pomiędzy tymi próbkami znajduje się prąd Czas się skończył i obie próbki są ważone.

Das alles ist sehr allgemein gehalten und kann in späteren Programmen etwas vereinfacht werden, wenn bestimmte Randbedingungen gegeben sind, wie beispielsweise, dass sr gleich sr_wav ist u.ä.

This is very general and can be used in later programs be simplified somewhat if certain boundary conditions are given, such as sr equals sr_wav, and so on.

Jest to bardzo ogólne i może być używane w późniejszych programach być nieco uproszczony, jeżeli podane są pewne warunki brzegowe, takie jak sr równa się sr_wav i tak dalej.

Bitte beachten Sie, dass die verwendete .wav-Datei zuvor in einen Unterordner "data" des Sketch Ordners gelegt werden muß.

Please note that the used .wav file was previously saved in a subfolder data of the sketch folder.

Należy pamiętać, że wykorzystany plik .wav został wcześniej zapisany w danych podfolderu folderu szkicu.

Die Methode zum Laden der wav-Datei kann einfach benutzt werden und wird hier nicht weiter erklärt.

The method for loading the wav file can be easily used and will not be explained here.

Metoda ładowania pliku wav może być łatwo używana i nie będzie tutaj wyjaśniony.

//Shortest program to just play two sinus waves with Android

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import android.media.AudioTrack;
import android.media.AudioFormat;
import android.media.AudioManager;

import android.media.AudioRecord;
import android.media.MediaRecorder;

Sound sound;
float[] mywavtone;
public void setup()
{
    mywavtone = ladeWavMix("ton69.wav");
    sound = new Sound();
    fullScreen();
    orientation(LANDSCAPE);
}

public void draw()
{
    background(0,0,255);
}

public class Sound implements Runnable
{
    private AudioTrack audioTrack; //Connection to sound card
    private int sr=44100; //Sample rate
    private int sr_wav=44100; //Sample rate of the loaded tone. So this is handled seperately.
    //Thus, you do not care about if changing sampling rate sr. It may differ to one of sound files!
    private int buffsize=512; //buffer size
    private int buffsize2=buffsize*2;
    private ScheduledExecutorService schedExecService; //realtime process    
    private short[] shortbuffer = new short[buffsize*2]; //stereo buffer l0 r0 l1 r1 l2 r2 ... frequently sent to sound card

    private double t=0.0; //realtime
    private double dt = 1.0/(double)sr; //time step according to sampling rate.
    private double dt_wav = 1.0/(double)sr_wav; //time step according to sampling rate of loaded file.
    private float MAX_SHORT = 32767.0;
    public Sound()
    {
        try
        {                                                
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sr, 
                                    AudioFormat.CHANNEL_OUT_STEREO, 
                                    AudioFormat.ENCODING_PCM_16BIT, 
                                    buffsize*10, 
                                    AudioTrack.MODE_STREAM);
            audioTrack.setStereoVolume(1.0f, 1.0f);
            
            audioTrack.play();            
        }
        catch(Exception eee)
        {
            System.out.println("FEHLER: "+eee);
        }     
        
        schedExecService = Executors.newSingleThreadScheduledExecutor();
        long period = (buffsize*1000)/sr; //Seconds per Beat==60/BPM, die Hälfte weil 8tel, mal 1000 weil Millisekunden.
        schedExecService.scheduleAtFixedRate(this, 0, period, TimeUnit.MILLISECONDS);                
        
        
    }
    public void run()
    {
        for(int i=0;i<buffsize2;i+=2)
        {
             //ACCURACY OF TIME SHOULD BE HIGHER THAN ONE OF AMPLITUDE.
             //SO TIME IS CALCULATED USING double AND AMPLITUDE USING float.
          
             //This may be the part of the programm where you might want to modify something like
             //introducing other sound sources / directional sound and so on:
             
             //Calculate the actual sample from the provided wav-file:
             //Actual time may be in between two samples:
             double T_entire = dt_wav*(double)mywavtone.length; //duration of file
             double t_file = t - T_entire*Math.floor(t/T_entire); //actual time in looped wav file
             
             int index_lo = (int)(t_file/(double)dt_wav); //first sample index
             int index_hi = (index_lo+1)%mywavtone.length; //following sample index
             
             //calculating weight for each sample:
             double t_part = t_file - dt_wav*Math.floor(t_file/dt_wav);
             double part   = t_part/dt_wav; //range [0,1]
             float weight_lo = 1.0 - (float)part;
             float weight_hi = (float)part;
             
             float amplitude = weight_lo*mywavtone[index_lo] + weight_hi*mywavtone[index_hi];
             
             float left  = MAX_SHORT*amplitude;
             float right = MAX_SHORT*amplitude;
             shortbuffer[i]=(short)left;
             shortbuffer[i+1]=(short)right;
             t+=dt; //increment of realtime for each sample
        }
      
        audioTrack.write(shortbuffer, 0,buffsize2);      
    }
}

    /**
     * Loads a Stereo-Wav-Datei. It is mixed to one channel and provided as float-Array.
     */
    public float[] ladeWavMix(String name) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren)
    {
            int zl,zh,lo,gesamt;
            float gross = 0.5f*(255.0f*256.0f + 255.0f);          
            byte[] dat = loadBytes(name);
            int anz = dat.length;          
            float[] y = new float[(anz-44)/4];                        

            int inx=44;
            
            for(int i=0;i<y.length;i++)
            {
                 zl = dat[inx++];
                 zh = dat[inx++];
                 if(zl>127)
                     zl-=256;
            
                 if(zh>127)
                     zh-=256;

                 lo     =  zl;
                 if(lo<0)
                     lo+=256;
                 gesamt = (zh+128)*256;                
                 gesamt+=lo;
                
                 y[i] = 0.5f*((float)gesamt - gross)/gross;        

                 zl = dat[inx++];
                 zh = dat[inx++];
                 if(zl>127)
                     zl-=256;            
                 if(zh>127)
                     zh-=256;

                 lo     =  zl;
                 if(lo<0)
                     lo+=256;
                 gesamt = (zh+128)*256;
                
                 gesamt+=lo;
                
                 y[i] += 0.5f*((float)gesamt - gross)/gross;                         
            }                
            return y;    
    }

Code 3.11.5.2-1: Androidsound002

Androidsound002.zip -- Sketch folder.