# Lautstärke von Audiosignal live berechnen



## Marmorkuchen (19. Nov 2008)

Hallo zusammen!
Habe ein Programm geschrieben, welches die Lautstärke eines Audiosignal meiner Recordingkarte anzeigt. Es funktioniert auch, ich kann sogar alle Eingänge gleichzeitig anzeigen, doch stört mich, dass ich niemals den aktuellen Pegel bekomme, sondern immer nur mit einer minimalen Verzögerung (<0.5sec). Ich nehme an, dass es mit dem Buffer zu tun hat, der erstmal voll sein muss, bevor ich das Audio-Datenpäckchen verarbeiten kann. Habe die Buffergröße auf das kleinste geschraubt, es wird etwas besser, aber es ist trotzdem nicht zufriedenstellend!

Wie kriege ich den aktuellen Lautstärkepegel? Muss ich dafür "direktere" Wege, z.B. über irgendwelche Hardwaretreiber oder Klassen an die Recordingkarte (M-Audio Delta 1010LT) rangehen? Geht das überhaupt mit Java, oder muss ich mit dieser Verzögerung leben (dann wirds Zeit zu C/C++ zu wechseln..) ? Ich verwende bisher die Standard-Java-Klassen für Audiosignale.

Schön wäre es, direkt einen Ausschlag der Messinstrumente zu sehen, wenn ein Signal am Eingang erscheint, so wie in jeder gängigen Recordingsoftware.

Danke für eure Hilfe schonmal!

Gruß,
Mammo


----------



## stev.glasow (19. Nov 2008)

zeig mal den code, bitte.


----------



## Marmorkuchen (19. Nov 2008)

Der Code ist schon ein paar tausend Zeilen lang deswegen nur Ausschnitte:


```
package soundinterface;

import javax.sound.sampled.*;

public class CaptureInterface {

	protected boolean running;
	private final TargetDataLine line;
	private AudioFormat format;
	private int buffersize;

	public CaptureInterface(int size, TargetDataLine l, AudioFormat f){
		line = l;
		format = f;
		buffersize = size;
	}

	public void stop(){
		
		if (running){
			running = false;
			line.stop();
		}
		
	}
	
	public void start() throws LineUnavailableException {

		line.open(format);
		line.start();
		
		Runnable runner = new Runnable() {

			byte buffer[] = new byte[buffersize];

			public void run() {

				running = true;

				while (running) {
					
					int count = line.read(buffer, 0, buffersize);

					if (count > 0) {

						// mache was
					}
					
				}
				
			}

		};

		Thread captureThread = new Thread(runner);
		captureThread.start();
		
	}

}
```

Das AudioFormat sieht so aus:


```
float sampleRate = 44100F;
int sampleSizeInBits = 16;
int channels = 2;
boolean signed = true;
boolean bigEndian = true;
		
format = new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
```

Und der Buffer..


```
private static final int BUFFER_SIZE = 2048;
```

Hier wird das alles initalisiert:


```
private void initInterface(int no){
		
		try {
			Mixer mixer = AudioSystem.getMixer(AudioSystem.getMixerInfo()[no]);
			interfaces.add(new CaptureInterface(BUFFER_SIZE, (TargetDataLine) mixer.getLine(new DataLine.Info(TargetDataLine.class, format)), format));

		} catch (LineUnavailableException e) {
			this.addProtocol("ERROR line unavailable exception: " + e.getMessage());
		}
		
	}
```

Ich hoffe, ihr könnt damit was anfangen.

Gruß


----------



## stev.glasow (20. Nov 2008)

denke die initialisierungen, das thread-gedönste und ein "int count = line.read(buffer, 0, buffersize);" haben weniger mit dem problem zu tun. 

zeig mal bisschen code wo du den pegel berechnest - versuche das problem zu kapseln und halbwegs aufs wesentliche zu beschränken - du kannst ruhig ordentlich code hier posten, nur halt nicht unmengen an irrelevantem zeug oder ganze programme. es wäre auch interessant wie du überhaupt merkst dass der pegel sich leicht verzögert.

vielleicht ist ja "nur" nen performance problem, nur wie soll man da ohne code was zu sagen - bin jetzt auch nicht der akustikoberguru mit glaskugel.


----------



## kopfsalat (20. Nov 2008)

Moinsen!
Ich bin da auch nicht so der Crack, aber was mir dazu einfällt:
[Halbwissen ON]
Es gibt ja verschiedene Treiber, um mit der Soundkarte zu kommunizieren. Üblicherweise nutzt man ja unter Windows die DirectX-Anbindung für Audio. Auch MMC (oder so ähnlich) lässt sich verwenden. Gag ist nun aber, dass es auch ASIO-Treiber für viele (semi-)professionelle Soundkarten gibt, und erst mit denen lassen sich die geringstmöglichen Latenzen einer Recording-Soundkarte erzeugen, oft im Bereich von nur einstelligen Millisekunden, das merkt man dann wenn überhaupt nur noch beim Live-Spielen von Softwaresamplern.
Eine Vermutung von mir ist nun, dass Java (wie andere Programmiersprachen mit eigener Audio-Library auch) die DirectX-Anbindung nutzt. Um den ASIO-Treiber zu nutzen, ohne Dich selbst zu tief in die Materie einarbeiten zu müssen, könntest du eine der gängigen Audio-Libraries verwenden, z.B. fmod (www.fmod.org - mit der habe ich mal gute Erfahrungen gemacht und für die gibt es auch ene Java-Anbindung) oder bass (www.un4seen.com), beide kostenlos für Freeware, aber können im kommerziellen Einsatz teuer werden. Vllt tuns da aber auch andere (audiere, portaudio?)
[Halbwissen OFF]

So oder ähnlich was das jedenfalls mal vor ca. 8 Jahren, als ich mich damit mal auseinandergesetzt habe.
Tschö,
kopfsalat


----------



## Marmorkuchen (20. Nov 2008)

Hallo!



			
				stevg hat gesagt.:
			
		

> zeig mal bisschen code wo du den pegel berechnest - versuche das problem zu kapseln und halbwegs aufs wesentliche zu beschränken - du kannst ruhig ordentlich code hier posten, nur halt nicht unmengen an irrelevantem zeug oder ganze programme. es wäre auch interessant wie du überhaupt merkst dass der pegel sich leicht verzögert.
> 
> vielleicht ist ja "nur" nen performance problem, nur wie soll man da ohne code was zu sagen - bin jetzt auch nicht der akustikoberguru mit glaskugel.



Verstehe was du meinst, aber das wird glaube ich nicht das Problem sein, es reicht schon an der Stelle des Kommentares ein "System.out.println(count);" zu machen und du siehst alleine an der Konsolenaufgabe, dass es etwas lahmt. Ich kanns ja mal trotzdem posten:


```
double channelLeft = 0.0, channelRight = 0.0;
						
						for (int i = 0; i < count - 4; i = i + 4){
							channelLeft = channelLeft + Math.abs(((buffer[i+0] & 0xFF)|(buffer[i+1] << 8))/32768.0);
							channelRight = channelRight + Math.abs(((buffer[i+2] & 0xFF)|(buffer[i+3] << 8))/32768.0);
						}
						
						channelLeft = channelLeft/(count/4);
						channelRight = channelRight/(count/4);
```

Die beiden Werte channelLeft und channelRight werden dann ausgegeben. (Ganz richtig ist die Berechnung glaube ich noch nicht, da ich nie denselben Ausschlag wie bei der Soundkarte kriege, aber bei der Verzögerung ist es eh unmöglich gezielt zu arbeiten.)

Danke für deine Hilfe!



			
				kopfsalat hat gesagt.:
			
		

> Es gibt ja verschiedene Treiber, um mit der Soundkarte zu kommunizieren. Üblicherweise nutzt man ja unter Windows die DirectX-Anbindung für Audio. Auch MMC (oder so ähnlich) lässt sich verwenden. Gag ist nun aber, dass es auch ASIO-Treiber für viele (semi-)professionelle Soundkarten gibt, und erst mit denen lassen sich die geringstmöglichen Latenzen einer Recording-Soundkarte erzeugen, oft im Bereich von nur einstelligen Millisekunden, das merkt man dann wenn überhaupt nur noch beim Live-Spielen von Softwaresamplern.
> Eine Vermutung von mir ist nun, dass Java (wie andere Programmiersprachen mit eigener Audio-Library auch) die DirectX-Anbindung nutzt. Um den ASIO-Treiber zu nutzen, ohne Dich selbst zu tief in die Materie einarbeiten zu müssen, könntest du eine der gängigen Audio-Libraries verwenden, z.B. fmod (www.fmod.org - mit der habe ich mal gute Erfahrungen gemacht und für die gibt es auch ene Java-Anbindung) oder bass (www.un4seen.com), beide kostenlos für Freeware, aber können im kommerziellen Einsatz teuer werden. Vllt tuns da aber auch andere (audiere, portaudio?)



Das klingt interessant, ich werde es mir mal genauer ansehen. ASIO-Treiber habe ich, aber ich wusste nicht, dass man die auch direkt ansteuern kann. Werde mich mal einlesen und dann berichten, Danke!

Gruß,
mammo


----------



## Marmorkuchen (24. Nov 2008)

Habe noch nicht mit der Programmierung angefangen, wollte mal nativeFmodFX ausprobieren, doch scheint mir das ganze ziemlich schwach verbreitet und schlecht ausdokumentiert zu sein. Es scheitert noch etwas an der Installation des Ganzen, aber ich hab auch noch nicht genug Zeit investiert. Habe aber noch was anderes, interessantes (was besser ausdokumentiert scheint) gefunden:

http://www.groovemanager.com/manudiplom/

Gruß,
Andreas


----------



## kopfsalat (25. Nov 2008)

Fmod's Java-Anbindung nativeFmodFX ist nur ein Privat-Projekt und sicherlich nicht sonderlich stark verbreitet. Fmod selbst hingegen kann wohl als _die_ Audioengine bezeichnet werden, insbesondere in der Spieleprogrammierung. Die einfache Audiodateiwiedergabe ist dabei nur ein Bruchteil der Funktionalität. Zielgruppe sind aber die gängigen maschinencodegenerierenden Programmiersprachen.

Die Infos zu Java Sound hinter dem Link sind interessant. Im Text wird aber erwähnt, dass es mit Java Sound in der untersuchten Version nicht möglich ist, den Treiber für die Soundkartenanbindung zu wählen. Und: Das ist doch dieselbe Soundkartenanbindung, die Du bereits nutzt?

Noch eine andere Idee: Lässt sich unter Windows nicht irgendwo ein Standardtreiber für die Audiowiedergabe einstellen? Vielleicht hilft es Dir bereits, dort einen anderen Treiber zu wählen (falls möglich, den ASIO-Treiber).


----------

