简体   繁体   中英

Real-time java sound volume adjustment

I play back sound with Java's SourceDataLine but whenever I try to adjust the volume (gain), there is a 0.2-0.5 second delay between the action and the response in the speaker. The audio data is written in 4k-16k chunks (16bit mono, 22kHz ~ 44k/s).

How can I make this volume adjustment more real-time?

Does the write(byte[], int, int) lock out the gain adjustment of the FloatControl?

Do I need to revert back to a DSP way of concurrent adjustment of the sound buffer data volume or submit smaller chunks?

JDK7, Decent Windows PC

Sound system takes the data from SourceDataLine in chunks of a few (hundred...) kilobytes and buffers them. If you change params for it, it won't take effect until system playback buffer is empty and new data is read from SDL.

What you need to do is to hack somewhere around changing system playback volume (which has immediate effect) rather than modyfing data you provide to it.

Have you tried using a custom (lower) buffer size when calling SourceDataLine.open()?

SourceDataLine.open( AudioFormat format, int bufferSize )

That should decrease latency. The master playback volume solution is still probably going to be faster though.

If you can somehow affect/create the Line.Info class your Mixer contains for your Line , you can change its minimum and maximum buffers. Then, you can set the buffers to the size of chunks you're feeding it, and then your delay will reduce to none (supposedly)

The Oracle tutorial on Java Sound provides an alternative answer to the use of Float.Control in its closing section: "Manipulating the Audio Data Directly". By manipulating the data directly, the possibility of real-time capabilities, with the potential for single-frame granularity, arises. Unfortunately, they don't give a concrete example.

The basic method is to first get access to the individual PCM frames. A Clip does not give any hooks into the data that it stores in memory. One solution is to process the bytes into PCM when loading the file via an AudioInputStream . PCM values can be multiplied by a volume factor to achieve the desired volume. Then, after the PCM is converted back to bytes, it can be played by a SourceDataLine .

The key here, for real-time response, is the handling of the volume factor. In AudioCue , I use a plan of having the playback code expose a public, loosely coupled "target" volume. On a per-frame basis, the current volume is compared to the desired, and incrementally moved towards the desired. (The volume change occurs linearly over 1024 frames, approximately 1/40th of a second for 44100 fps.) A code example can be observed in the public setVolume method on line 883, with the specifics of initializing the smoothing at line 892. The code where the volume factor is applied in the processing loop is with the area 1301-1322 (in the second-level for-loop within the method fillBuffer after the comment line //adjust volume if needed ).

I'm adding this answer many years after the question was first asked. I think this is merited for inclusion because it provides a useful alternative that was not given when the question was first asked.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM