Puzzel Puzzels
Gebruikersavatar
Flisk
Artikelen: 0
Berichten: 1.264
Lid geworden op: vr 02 mar 2012, 14:21

WAV bestanden Java

Ik ben bezig met het maken van geluid in Java. Het WAV formaat werkt het makkelijkste en met 8bit mono (44.1kHz) geluid gaat alles goed en krijg ik heel zuiver klinkende golven. Nu probeer ik mijn code om te schrijven naar 16bit stereo(44.1kHz) maar ik krijg geen zuiver geluid. Bij een square golf krijg ik gewoon een stil bestand en bij een sinus golf klinkt het heel irritant (de frequentie klopt wel ongeveer). Hier een stukje van mijn code waarin het probleem waarschijnlijk zit:

Code: Selecteer alles

public static void main(String[] args) {

        WaveForm.loadAllWaveforms();
        String name="sine";
        WAV.createFile(sineWave(100), "C:\\wave\\"+name+".wav");

    }

    public static byte[] sineWave(int f){

        byte [] data=new byte[(int)(176400)];
        double pos=0;
        double freq=f;

        //left channel
        for(int i=0;i<data.length;i+=4){
            byte[] ba=intToByteArray(WaveForm.sine[(int)pos%131072]);
            data[i]=ba[0];
            data[i+1]=ba[1];
            pos+=freq*(double)131072/(double)44100;
        }

        //right channel
        for(int i=2;i<data.length;i+=4){
            byte[] ba=intToByteArray(WaveForm.sine[(int)pos%131072]);
            data[i]=ba[0];
            data[i+1]=ba[1];
            pos+=freq*(double)131072/(double)44100;
        }
        return data;

    }

Uitleg bij de code:

In de WaveForm klasse zitten tabellen van vaak gebruikte golven, in elke tabel zitten er 131072 gehele getallen tussen 0 en 2^16-1. Deze heb ik allemaal eens geprint en dat zag er goed uit (vergeleken met de 8bit tabellen). De methode createFile van de WAV klasse neemt een stuk data, plakt de juiste header ervoor en slaat het bestand daarna op. De methode intToByteArray returned de binaire voorstelling van de input in een koppel bytes, little-endian gerangschikt. Die methode wordt ook gebruikt tijdens het maken van de header en klopt dus sowieso.

Het probleem moet dus in de twee for loops zitten denk ik. Iemand een idee waar het foutloopt?
Je leest maar niet verder want je, je voelt het begin van wanhoop.

ads

Steun Sciencetalk bol cadeaukaart - verpakking luxe

bol cadeaukaart - verpakking luxe

Bekijk product

Steun Sciencetalk Screenprotector - 2 stuks - Geschikt voor iPhone 17 Pro Tempered Glass - Extra Sterk – beschermglas screen protector

Screenprotector - 2 stuks - Geschikt voor iPhone 17 Pro Tempered Glass - Extra Sterk – beschermglas screen protector

Bekijk product

Steun Sciencetalk Lumina Mini Pro Beamer - Home Cinema - Projector - Android 11.0 - WiFi 6 & Bluetooth 5.2 - 4k Beeldkwaliteit - Projector Scherm - Wit

Lumina Mini Pro Beamer - Home Cinema - Projector - Android 11.0 - WiFi 6 & Bluetooth 5.2 - 4k Beeldkwaliteit - Projector Scherm - Wit

Bekijk product

Gebruikersavatar
Xenion
Artikelen: 0
Berichten: 2.609
Lid geworden op: za 21 jun 2008, 10:41

Re: WAV bestanden Java

Kijk eens met een extern programma (MATLAB, Audacity, ...) naar de gegenereerde wav file. Bekijk de twee kanalen individueel en kijk of die eruit zien zoals jij bedoeld had.
 
Verder hebben we niet echt genoeg informatie om hier het specifieke probleem te vinden.

Code: Selecteer alles

WaveForm.loadAllWaveforms();
String name="sine";
WAV.createFile(sineWave(100), "C:\\wave\\"+name+".wav");
Hier vraag je om een byte-array naar een wav-file te schrijven, maar ik zie nergens de specificatie voor stereo 16bit. Het zou goed kunnen, dat je library die byte-array heeft geïnterpreteerd als een mono 8bit en dat zou wel eens funky kunnen klinken.
 
Verder zou ik ook het interleaven van de twee kanalen iets properder aanpakken. Zorg dat je de twee kanalen als aparte lijsten hebt en schrijf dan een functie om ze te interleaven en de-interleaven.
Scispace Scispace

Scispace is dé ai voor wetenschappers en onderzoekers. Ga naar SciSpace en profiteer van één van de beste ai's.

Scispace

Gebruikersavatar
Flisk
Artikelen: 0
Berichten: 1.264
Lid geworden op: vr 02 mar 2012, 14:21

Re: WAV bestanden Java

Xenion schreef:Hier vraag je om een byte-array naar een wav-file te schrijven, maar ik zie nergens de specificatie voor stereo 16bit. Het zou goed kunnen, dat je library die byte-array heeft geïnterpreteerd als een mono 8bit en dat zou wel eens funky kunnen klinken.
Hieronder de code waarmee ik het WAV bestand maak (verborgen inhoud). Ik heb de header aangepast naar 16bit dus daar lijkt het probleem niet te zitten
Spoiler: [+]

Code: Selecteer alles

public static void createFile(byte[] data, String filepath){

        byte[] total = new byte[data.length+44];
        byte[] header =wavHeader(data.length);

        for(int i=0;i<44;i++){
            total[i]=header[i];
        }
        for(int i=0;i<data.length;i++){

            total[i+44]=data[i];
        }

        try{
            FileOutputStream file = new FileOutputStream(filepath);
            file.write(total);
            file.close();
        }catch(IOException e){
            System.out.println("Failed to create audio file");
            System.out.println("Check if the fail isn't opened elsewhere.");
        }
    }

    public static byte[] wavHeader(long datasize){          //Alle getallen zijn little-endian, woorden big-endian.
        byte[] chunkSize=longToByteArray(datasize+36);      //De methodes long-int ToByteArray returnen dus little-endian arrays.
        byte[] subchunk1Size=longToByteArray(16);           //De bits in de bytes zelf zijn big-endian.
        byte[] sampleRate=longToByteArray(44100);           //
        byte[] byteRate=longToByteArray(176400);            //
        byte[] subchunk2Size=longToByteArray(datasize);     //
        byte[] formatType=intToByteArray(1);                //1=pcm,6=mulaw,7=alaw
        byte[] numChannels=intToByteArray(2);               //
        byte[] blockAlign=intToByteArray(4);                //(bitsPerSample*numChannels)/8
        byte[] bitsPerSample=intToByteArray(16);
        byte[] header= new byte[44];

        header[0]='R';
        header[1]='I';
        header[2]='F';
        header[3]='F';
        header[4]=chunkSize[0];
        header[5]=chunkSize[1];
        header[6]=chunkSize[2];
        header[7]=chunkSize[3];
        header[8]='W';
        header[9]='A';
        header[10]='V';
        header[11]='E';
        header[12]='f';
        header[13]='m';
        header[14]='t';
        header[15]=' ';
        header[16]=subchunk1Size[0];
        header[17]=subchunk1Size[1];
        header[18]=subchunk1Size[2];
        header[19]=subchunk1Size[3];
        header[20]=formatType[0];
        header[21]=formatType[1];
        header[22]=numChannels[0];
        header[23]=numChannels[1];
        header[24]=sampleRate[0];
        header[25]=sampleRate[1];
        header[26]=sampleRate[2];
        header[27]=sampleRate[3];
        header[28]=byteRate[0];
        header[29]=byteRate[1];
        header[30]=byteRate[2];
        header[31]=byteRate[3];
        header[32]=blockAlign[0];
        header[33]=blockAlign[1];
        header[34]=bitsPerSample[0];
        header[35]=bitsPerSample[1];
        header[36]='d';
        header[37]='a';
        header[38]='t';
        header[39]='a';
        header[40]=subchunk2Size[0];
        header[41]=subchunk2Size[1];
        header[42]=subchunk2Size[2];
        header[43]=subchunk2Size[3];
        return header;
    }
 
Xenion schreef:Kijk eens met een extern programma (MATLAB, Audacity, ...) naar de gegenereerde wav file.
Goeie tip! Met behulp van Audacity krijg ik volgende golf:
sinus16bit
sinus16bit 1048 keer bekeken
Twee kanalen, frequentie is goed maar de golf duidelijk verkeerd, is de data van 16 bit wav signed? Want nu heb ik het unsigned geprogrammeerd, daar zit de fout misschien.

Wel raar dat de 8bit golf dan, op dezelfde wijze gemaakt, wél mooi klopt:
sine8bit
sine8bit 1044 keer bekeken
Of ligt het ergens anders aan?

EDIT:

Verder zou ik ook het interleaven van de twee kanalen iets properder aanpakken. Zorg dat je de twee kanalen als aparte lijsten hebt en schrijf dan een functie om ze te interleaven en de-interleaven.
Zou er inderdaad beter uitzien maar gaat de code dan niet twee keer zo traag gaan (twee keer zoveel assignaties)? Ik wil het ook relatief snel laten lopen op mijn kleine laptop en die is wat traag.
Je leest maar niet verder want je, je voelt het begin van wanhoop.
Gebruikersavatar
Flisk
Artikelen: 0
Berichten: 1.264
Lid geworden op: vr 02 mar 2012, 14:21

Re: WAV bestanden Java

Kleine update:
wikipedia schreef:...There are some inconsistencies in the WAV format: for example, 8-bit data is unsigned while 16-bit data is signed,...
Het lag dus daaraan, wavetabels even omgeschreven naar signed en nu krijg ik weer zuiver geluid.
Je leest maar niet verder want je, je voelt het begin van wanhoop.
Gebruikersavatar
Xenion
Artikelen: 0
Berichten: 2.609
Lid geworden op: za 21 jun 2008, 10:41

Re: WAV bestanden Java

Haha dat had ik ook over het hoofd gezien. In het algemeen is dit de beste werkwijze wanneer je een gestandaardiseerde bitstream genereert: kijk of een bekend programma waarvan je weet dat het werkt het kan openen en check hoe de content erin weergegeven wordt.

Betreft dat interleaven hangt het ervan af wat je precies wil bereiken. Op dit moment is je code ook niet geweldig efficiënt omdat je twee for loops hebt terwijl het evengoed met eentje zou kunnen. Je kan in 1 loop beide kanalen genereren en ineens wegschrijven naar de juiste plaats in de array. Ik lijkt me dan iets cleaner om het maken en interleaven in aparte functies te zetten omdat je die dan makkelijker kan hergebruiken.
willyb
Artikelen: 0
Berichten: 29
Lid geworden op: vr 12 aug 2005, 00:02

Re: WAV bestanden Java

Een klein beetje offtopic, maar wist je dat je hier een behoorlijk beveiligingslek creëert in je applicatie?
Zoek maar eens op Path Traversal bij OWASP.

Code: Selecteer alles



        WAV.createFile(sineWave(100), "C:\\wave\\"+name+".wav");

ads

Steun Sciencetalk Canon SELPHY QX20 - Mobiele Fotoprinter - Draadloos - Grijs

Canon SELPHY QX20 - Mobiele Fotoprinter - Draadloos - Grijs

Bekijk product

Steun Sciencetalk Twinmarkers 80 stuks voor volwassenen - Alcohol Markers - Stiften - Markeerstiften - Vivid Green

Twinmarkers 80 stuks voor volwassenen - Alcohol Markers - Stiften - Markeerstiften - Vivid Green

Bekijk product

Steun Sciencetalk Screenprotector Geschikt voor Samsung A56 Screen protector Tempered Gehard galaxy glas - 2 stuks beschermglas

Screenprotector Geschikt voor Samsung A56 Screen protector Tempered Gehard galaxy glas - 2 stuks beschermglas

Bekijk product

Gebruikersavatar
Flisk
Artikelen: 0
Berichten: 1.264
Lid geworden op: vr 02 mar 2012, 14:21

Re: WAV bestanden Java

Kan geen kwaad denk ik, ik heb het geschreven voor persoonlijk gebruik, het is niet voor een web applicatie oid.

De voorbije maanden is er heel wat code bijgekomen en momenteel heb ik het geheel in een GUI gegoten (runnable jar), de gebruiker kan trouwens zelf nergens die name variabele kiezen, die wordt in de source code bepaald. Of zie ik iets over het hoofd?
Naamloos
Naamloos 1044 keer bekeken
Je leest maar niet verder want je, je voelt het begin van wanhoop.

Plaats een reactie

Je mail wordt niet openbaar getoond. Het wordt enkel gebruik voor contact of notificatie vanuit het beheer.

🗨️ Wat vind jij? Stel direct je vraag of geef je mening – zonder registratie. Je reactie zet het topic weer bovenaan bij 'Laatste posts' en trekt snel nieuwe reacties aan🔥. Mocht je als vaste bezoeker willen reageren, dan kun je je ook registreren.

Bevestig dat je geen robot bent door de volgende vragen te beantwoorden.

Noor heeft 10 knikkers. Ze verliest er 4 in het gras. Hoeveel heeft ze er nog?

Antwoord: (vul een getal in)

Er zitten 5 vogels op een hek. Twee vliegen weg. Hoeveel blijven er zitten?

Antwoord: (vul een getal in)

Terug naar “Informatica en programmeren”

Sciencetalk: Leer, deel of groei. Volg of geef een cursus op Sciencetalk!