Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (120)
games submitted by our members
Games in WIP (577)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  MASTER_GAIN control on Clip but not SourceDataLine??  (Read 2877 times)
0 Members and 1 Guest are viewing this topic.
Offline philfrei
« Posted 2011-05-19 20:56:26 »

Is this typical? When I play a .wav as a Clip, I have access to a MASTER_GAIN control, and can use this to set the volume. When I play the same .wav as a SourceDataLine, there are no controls exposed whatsoever.

I'm using the getControls() function in both instances, on Clip "currentClip" in the first case and on SourceDataLine "currentLine" in the other. So, I'm pretty sure I'm invoking the controls correctly.

I guess, if I use a SourceDataLine, I'm going to have to scale the values for every data point in each input buffer as I am loading? Dragola. Tongue Is that common practice?

Consulting "Killer Game Programming in Java," all the examples with volume controls pertain to Clips. So I guess most games limit themselves to Clip usage?

Why not use Clips myself? Because for my design I want (insist upon) sounds that can recur with possible overlapping. I could preload three or four instances of each and manage them as a pool, but the multiplier effect on RAM needed is worrisome. So, I thought it better to load each one when it is needed, and loading as a SourceDataLine allows for quicker starts than continually reloading new Clips on an as-needed basis. But the SourceDataLine doesn't have a volume control!?!?

But I may have to head back to some sort of Clips pooling method if decoding OGG/Vorbis turns out to be slow to kick off with SourceDataLine playback.

"It's after the end of the world! Don't you know that yet?"
Offline philfrei
« Reply #1 - Posted 2011-05-20 08:58:18 »

More conversations with myself. This has been a common occurance in the Audio section for me. I assume that is because most folks here at Java-Gaming are putting their emphasis elsewhere, and that I am trying to do things in a slightly non-normal way by working things out with JavaSound rather than going with an existing system.

OK, so the results are in. I wrote my own volume changer that works directly on the data in the buffer used to read data in from the .wav before it is sent back out to SourceDataLine. And it works like a charm!

Basically, by doing so, one can increment or decrement the volume towards a desired volume every frame! Thus the increment/decrement value can be quite small and a respectable volume changing speed can be obtained without clicks occuring. In my first test, I have the increment set to +/- 0.00001f, where the entire dynamic range is 0.0f to 1.0f. With 44100 fps, the entire dynamic range can be traversed in less than half a second with not a single click. (Haven't tested for upper limits of speed yet.)

And (bonus): the slight occasional hesitations of the sound cues have disappeared, as far as I can tell. SourceDataLine's really do start quicker and more reliably than starting a brand new Clip. Makes sense, as Clips are designed to optimize for reuse, not first use.

"It's after the end of the world! Don't you know that yet?"
Offline 20thCenturyBoy

Senior Duke


Medals: 3


So much to learn, so little time.


« Reply #2 - Posted 2011-05-20 13:36:55 »

I must admit it can be quiet in here!

FWIW I am working on Java Sound at the moment. Sampled, not midi. I have written a few simple wrapper classes for Clips and Streams.
I am quite enjoying it! I found the Java Tutorial section on sound pretty good for everything. You can definitely use Volume control on SourceDataLine. Are you following the section "Getting the Controls from the Line" at http://download.oracle.com/javase/tutorial/sound/controls.html? I haven't yet implemented the controls in my sound "engine" (what a grand term for a few small classes hehe).

If you like I can share my code with you, it is still in a state of active development.

Martin
http://crazygamedev.blogspot.com/


"I have never done unit testing and I don’t find it a very useful concept" - Jonathan Blow
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline philfrei
« Reply #3 - Posted 2011-05-20 21:06:33 »

Nice to meet you!
Quote
You can definitely use Volume control on SourceDataLine. Are you following the section "Getting the Controls from the Line" at http://download.oracle.com/javase/tutorial/sound/controls.html?
Yes, I've gone over that section a number of times. My Windows XP system don't offer MASTER_VOLUME or VOLUME for a newly generated SourceDataLine. What OS are you using? When you change volume, do you get clicks? I do, on the MASTER_VOLUME made available for Clips, unless I keep the volume change increment very small, which limits how fast one can go from one volume to another.

I'm using the method described in "Getting a Line Directly from the AudioSystem," from "Accessing Audio System Resources" to get my SourceDataLine. An exhaustive search for all Controls for all Mixers in my system only uncovered one control, for a Reverb of all things! So I assume it won't help to try and get a SourceDataLine from a specified Mixer.

Even so, a control will only allow the "granularity" corresponding to the size of the byte buffer you use, yes? By putting a volume updater where you can iterate through the byte buffer itself, you get granularity per frame! 44100 increments per second! Undoubtably there are efficiencies to add to the following. This is first pass, just-get-it-working code and I'm happy to get suggestions for improvements.The byte[] dual is one stereo frame in size for my 16-bit wav files.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public class VolumeProcessor {

   public byte[] handleStaticVolume(byte[] buffer,
         int numBytes, float volume)
   {
      float audioVal = 0.0f;
      for (int i = 0; i < numBytes; i += 2)
      {
         audioVal = (float) ( ( buffer[i+1] << 8 )
               | ( buffer[i] & 0xff )) * volume;
         buffer[i] = (byte)audioVal;
         buffer[i + 1] =   (byte)((int)audioVal >> 8 );
      }
      return buffer;
   }
   
}
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
int numBytesRead = 0;
               while (numBytesRead !=-1)
               {
                  numBytesRead = aiStream.read(
                        myData, 0, numBytesToRead);
                  if (numBytesRead == -1) break;
//                  myData = vp.handleStaticVolume(
//                        myData, numBytesRead, volume);
                  for (int i = 0; i < numBytesRead; i += 4)
                  {
                     if (volume <= volumeGoal)
                     {
                        volume += 0.00001f;
                     }
                     else
                     {
                        volume -= 0.00001f;
                     }
                     dual[0] = myData[i];
                     dual[1] = myData[i+1];
                     dual[2] = myData[i+2];
                     dual[3] = myData[i+3];
                     dual = vp.handleStaticVolume(
                           dual, 4, volume);
                     myData[i] = dual[0];
                     myData[i+1] = dual[1];
                     myData[i+2] = dual[2];
                     myData[i+3] = dual[3];
                  }
                 
                 
                  line.write(myData, 0, numBytesRead);
               }

"It's after the end of the world! Don't you know that yet?"
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #4 - Posted 2011-05-20 21:20:35 »

It is possible to get the FloatControl.MASTER_GAIN on SourceDataLine:
1  
2  
FloatControl volume = (FloatControl)line.getControl(FloatControl.MASTER_GAIN);
volume.setValue(<int>);


Look at the Java API next time Wink

Offline philfrei
« Reply #5 - Posted 2011-05-20 22:37:46 »

That is exactly the code I used! And I assume that works for most people's setups. But it doesn't work for mine, as stated previously.

Remind me what system you are running? I'm assuming you have implemented this and it works for you. I can get it to work for Clips but not SourceDataLines.

I'm wondering if it is an XP issue, or perhaps related to my odd audio setup. I run my sound through my Tascam mixer, via a MiaMIDI sound card. I don't have a direct line out from the computer itself for sound except via this card, e.g., nothing can be heard from my computer's headphone out. So maybe that is part of it. I knew I was going to use my studio monitors exclusively, so having internal sound seemed like something I could skip when I put the system together. Might have been overzealously frugal on that matter.

Not every OS/AudioSystem exposes every possible feature. A limited PC setup may not have some features. I suppose I could show a data dump of my AudioSystem if you don't believe me.

But even if it did work, I don't think I would use the MASTER_VOLUME control anymore, given the superior performance of working directly on the audio data!  Cool

"It's after the end of the world! Don't you know that yet?"
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #6 - Posted 2011-05-20 23:15:48 »

Uhhh are you forgetting that you are using Java? Write once, run anywhere?

You are probably using a really old version of Java. What version are you using?


Misunderstood your problem, for a while I thought you said it wouldn't compile or wouldn't run.

So calling these methods don't work? It must be either driver issues or hardware issues.

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Longarmx (52 views)
2014-10-17 03:59:02

Norakomi (43 views)
2014-10-16 15:22:06

Norakomi (33 views)
2014-10-16 15:20:20

lcass (38 views)
2014-10-15 16:18:58

TehJavaDev (68 views)
2014-10-14 00:39:48

TehJavaDev (68 views)
2014-10-14 00:35:47

TehJavaDev (60 views)
2014-10-14 00:32:37

BurntPizza (73 views)
2014-10-11 23:24:42

BurntPizza (45 views)
2014-10-11 23:10:45

BurntPizza (86 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!