# WAV-Samples bearbeiten oder: 2 Bytes -> short -> float



## Gelöschtes Mitglied 9001 (9. Aug 2007)

Hallo,

ich möchte WAV-Daten auslesen, bearbeiten und wieder schreiben. Das Laden einer WAV-Datei und das Wiedergeben mit SourceDataLine von AudioSystem.getLine klappt.
Die Daten liegen in einem byte-Array vor.
Meine Wav-Dateien sind in 16 Bit, also habe ich pro Sample und Kanal 2 Bytes, z.B.

puffer[i+0]  1. Byte des i-ten Samples des linken Kanals
puffer[i+1]  2. Byte des i-ten Samples des linken Kanals
puffer[i+2]  1. Byte des i-ten Samples des rechten Kanals
puffer[i+3]  2. Byte des i-ten Samples des linken Kanals

Nun möchte ich die Sample-Daten aber bearbeiten und benötige sie daher als float-Werte. Wie bekomme ich aus den beiden Bytes einen korrekten float-Wert und wie wandle ich diesen float-Wert nach Bearbeitung wieder in zwei richtige Bytes um?


```
float x1 = puffer[i+0] + puffer[i+1]*256
int x2 = puffer[i+0] | (puffer[i+1] << 8)
```
habe ich probiert, liefert aber nicht das richtige Ergebnis, denn nach dem Wiederzusammensetzen des unbearbeiteten Samples kam nicht mehr der Originalklang heraus.

Danke für alle Tipps!


----------



## Lübecker (9. Aug 2007)

Hallo, ich hatte vor kurzem das gleiche Problem und habe es mit ByteArray- und Data-Streams gelöst:

```
ByteArrayInputStream byteIn;
DataInputStream dataIn;
byte content[] = new byte[4];
float result = 0;

for (int i=0; i<4; i++)
{
	content[i] = (byte) readByte();
}
byteIn =  new ByteArrayInputStream(content);
dataIn = new DataInputStream(byteIn);
result = dataIn.readFloat();
```
Der in Bytes zerlegte Floatwert wird nach content gelesen (content[0] = msb, content[3] = lsb), aus dem byteArray wird dann ein ByteArrayInputStream erzeugt, aus welchem wiederum ein DataInputStream generiert werden kann. readFloat() interpretiert 4 Bytes des DataStreams als Float und liefert die korrekte Zahl zurück. 
Ich hoffe das hilft dir weiter!

Gruß


----------



## Rock Lobster (10. Aug 2007)

Bin auch grad dabei, Audio-Sachen zu programmieren, und habe mir dafür auch ein paar Funktionen geschrieben, vielleicht ist da was für Dich dabei:


```
public class AudioTools
{
	public static float[] getFloatArray(byte[] bytes, int bitRate, int numChannels)
	{
		int k = 0;
		int size = bytes.length*2;
		float[] floats = new float[0];
		
		switch(bitRate)
		{
		case 8:
			floats = new float[size/numChannels];
			
			if (numChannels == 2)
				for(int i=0; i<size/numChannels; i++)
					floats[i]	= ui8tof(bytes[i]);
			else
				for(int i=0; i<size/numChannels/2; i+=2)
				{
					floats[i]	= ui8tof(bytes[i]);
					floats[i+1]	= ui8tof(bytes[i]);
				}
			
			break;
			
		case 16:
			floats = new float[size/2/numChannels];
			
			if (numChannels == 2)
				for(int i=0; i<size/numChannels; i+=2)
				{
					floats[k]	= i16tof(bytes[i+1], bytes[i]);
					k++;
				}
			else
				for(int i=0; i<size/numChannels/2; i+=4)
				{
					floats[k]	= i16tof(bytes[i+1], bytes[i]);
					floats[k+1]	= i16tof(bytes[i+1], bytes[i]);
					k+=2;
				}
			
			break;
		}
		
		return floats;
	}
	
	
	public static byte[] getByteArray(float[] floats, int bitRate, int numChannels)
	{
		int k = 0;
		int size = floats.length/2;
		byte[] bytes = new byte[0];
		
		switch(bitRate)
		{
		case 8:
			bytes = new byte[size*2*numChannels];
			
			if (numChannels == 2)
				for(int i=0; i<size*numChannels; i++)
					bytes[i] = ftoui8(floats[i]);
			else
				for(int i=0; i<size*numChannels; i+=2)
				{
					bytes[i]	= ftoui8(floats[i]);
					bytes[i+1]	= ftoui8(floats[i]);
				}
			
			break;
			
		case 16:
			bytes = new byte[size*2*numChannels];
			
			if (numChannels == 2)
				for(int i=0; i<size*numChannels; i++)
				{
					ftoi16(floats[i], bytes, k);
					k+=2;
				}
			else
				for(int i=0; i<size*numChannels; i+=2)
				{
					ftoi16(floats[i], bytes, k);
					ftoi16(floats[i], bytes, k+2);
					k+=4;
				}
				
			
			break;
		}
		
		return bytes;
	}
	
	
	public static final float i16tof(byte hi, byte lo)
	{
		return (short) (hi << 8) | (short) (lo & 0xFF);
	}
	
	
	public static final void ftoi16(float f, byte[] bytes, int idx)
	{
		bytes[idx  ]	= (byte)((int)f);
		bytes[idx+1]	= (byte)((int)f >> 8);
	}
	
	
	public static final float ui8tof(byte b)
	{
		return (((short)b & 0xFF) - 128) * 256;
	}
	
	
	public static final byte ftoui8(float f)
	{
		return (byte)(((int)f/256) -128);
	}
}
```


----------



## Gelöschtes Mitglied 9001 (10. Aug 2007)

Danke!

Diese Klasse enthält genau das, was ich brauche. Kann es sein, daß Bitoperationen in Pascal irgendwie einfacher zu realisieren waren? Naja egal. Jetzt funktioniert's. Danke!


----------



## Rock Lobster (10. Aug 2007)

Java ist einfach keine Sprache für solche, die gerne im Speicher rumwurschteln 
Schlimm ist z.B., daß es keine unsigned-Variablen gibt. Das ist besonders tragisch wenn Du mit 8-Bit-Samples rumhantierst.

Daher muß man halt leider immer ein bißchen drumrumbauen. Aber immerhin ist es möglich, wenn auch mit Aufwand


----------



## Guest (10. Aug 2007)

Ah so, dann hab ich wohl was falsch verstanden. Dachte du wolltest für die Bitfolge des Bytearrays die entsprechende IEEE Fließkommazahl ermitteln und umgekehrt


----------

