1

I'm working on an interactive sound installation that runs using Processing and Minim, among other things. This project requires more than just a simple left/right output (5 speakers, to be specific), which from what I've read means the Java Sound api is my primary option with my setup. I'm fairly new to Processing and totally new to lower level Java.

I'm running this all on a 2011 Macbook Pro with this external USB sound card: http://amzn.com/B004Y0ERRO, which seems to detect as a single USB audio interface just fine on the Mac. When using the Java Sound api, theoretically I should be able to get a list of Lines from a Mixer which would correspond to the 3 stereo output jacks I need access to, but I can't seem to figure out how and where to find them after spending much time in the Java Audio api docs and related tutorial sites.

EDIT: Turns out most surround sound soundcards are only stereo compatible on Macs, which explains much of my trouble. I will be retrying this with 3 stereo soundcards instead.

Here is a bare-bones version of a demo I'm working with in Processing:

import javax.sound.sampled.*;

Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
Mixer mixer = AudioSystem.getMixer(mixerInfo[8]);

void setup()
{
  size(200, 200);

  printArray(mixerInfo);

  for(Line.Info lineInfo : mixer.getTargetLineInfo()){
    Line thisLine = mixer.getLine(lineInfo);
    thisLine.open();
    println(thisLine);
  }

}

The printArray returns this:

[0] Default Audio Device, version Unknown Version
[1] Built-in Microphone, version Unknown Version
[2] Built-in Input, version Unknown Version
[3] Built-in Output, version Unknown Version
[4] USB Sound Device        , version Unknown Version
[5] Port Built-in Microphone, version Unknown Version
[6] Port Built-in Input, version Unknown Version
[7] Port Built-in Output, version Unknown Version
[8] Port USB Sound Device        , version Unknown Version

Presumably I would want the last device (8) or maybe 4. I can't quite tell because I can't see what lines/ports belong to each device. When I try using:

mixer.getTargetLineInfo()

I get only one result:

SPEAKER target port

The for loop at the end should loop through all the lines in the mixer and open them (up until this point you have to comment out this section to not throw an error) but instead I get this error:

Unhandled exception type LineUnavailableException

I feel like I must be digging into the wrong place, how could a surround sound USB card have only a single, closed SPEAKER target port when there are 10 jacks on the device? No matter how closely I read the documentation I can't figure out where I'm going wrong. Thanks for reading and I greatly appreciate any insight you can provide!

EDIT:

Version of above sketch with basic minim playback included:

import ddf.minim.Minim;
import ddf.minim.ugens.Oscil;
import ddf.minim.AudioOutput;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.Line;

Minim       minim;
AudioOutput out;
Oscil       wave;

Mixer.Info[] mixerInfo;
javax.sound.sampled.Line.Info lineInfo;
javax.sound.sampled.Line Line;


void setup()
{
  size(200, 200);

  minim = new Minim(this);

  mixerInfo = AudioSystem.getMixerInfo();   
  Mixer mixer = AudioSystem.getMixer(mixerInfo[8]);

  try {
    for (Line.Info lineInfo : mixer.getTargetLineInfo()) {
      Line thisLine = mixer.getLine(lineInfo);
      thisLine.open();
      println(lineInfo);
    }
  }
  catch(LineUnavailableException e) {
    e.printStackTrace();
  }

  minim.setOutputMixer(mixer);

  out = minim.getLineOut(Minim.STEREO);

  wave = new Oscil( 440, 0.5f, Waves.SINE );
  wave.patch( out );
}
Russ
  • 21
  • 4

1 Answers1

1

You're getting the Unhandled exception type LineUnavailableException error because these two lines can both throw a LineUnavailableException:

Line thisLine = mixer.getLine(lineInfo);
thisLine.open();

That means you have to wrap these lines in a try-catch block:

  try {
    for (Line.Info lineInfo : mixer.getTargetLineInfo()) {
      Line thisLine = mixer.getLine(lineInfo);
      thisLine.open();
      println(thisLine);
    }
  }
  catch(LineUnavailableException e) {
    e.printStackTrace();
  }

I can try to work through the rest of your problems, but step one is fixing this, since it's a compilation error probably preventing you from actually running any code.

Also, look at this line:

println(thisLine);

Here you're printing a Line instance. Processing doesn't know how to print a Line instance (the Line class does not override the toString() method), so you'll just get its hashcode instead of any useful information. Try printing out the `Line.Info instance instead:

println(lineInfo);

Edit: As for your error about Line being ambiguous, that's because you're using wildcard imports- you're importing everything in the ddf.minim, ddf.minim.ugens, and javax.sound.sampled packages. The problem is that ddf.minim and javax.sound.sampled both have a Line class, so Processing has no way of knowing which class you mean!

The "real" solution is probably to import classes specifically instead of using an import wildcard:

import ddf.minim.Minim;
import javax.sound.sampled.Line;
//1 import statement for each class...

But the lazy solution is to use the fully qualified name so Processing knows exactly what Line class you mean:

for (javax.sound.sampled.Line.Info [] lineInfo : mixer.getTargetLineInfo()){

Note that you'll have to do this for every line that might be ambiguous, so the better solution is to directly import the classes.

Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
  • Thank you! That's a step in the right direction, the code now reads: `import javax.sound.sampled.*; Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo(); Mixer mixer = AudioSystem.getMixer(mixerInfo[8]); void setup() { size(200, 200); //printArray(mixerInfo); try { for (Line.Info lineInfo : mixer.getTargetLineInfo()) { Line thisLine = mixer.getLine(lineInfo); thisLine.open(); println(lineInfo); } } catch(LineUnavailableException e) { e.printStackTrace(); } }` and the print statement returns: `SPEAKER target port` Same as before. – Russ Nov 30 '15 at 19:54
  • @Russ Well, now you have to figure out which line goes to which device. Have you tried just playing a sound on a line and seeing where it comes out? – Kevin Workman Nov 30 '15 at 19:58
  • I've added a version of the code with minim generating a sine wave to the bottom of my original question. I get an error on the **for** of the **try** statement saying `The type Line is ambiguous`. I got this error once before which was what prompted me to pull minim out of the equation to troubleshoot. – Russ Nov 30 '15 at 20:15
  • Thank you again. I think I've included them individually up in my post. Now I oddly am getting the error that "Cannot find a class or type named 'LineUnavailableException'" in the catch statement. Weird! It had no problem throwing that error before. – Russ Nov 30 '15 at 20:45
  • @Russ If you took out your wildcard imports, then you'll have to directly import the `LineUnavailableException` class as well. – Kevin Workman Nov 30 '15 at 20:58
  • I changed to mixer 4 (as I had considered before) and now I get the sine wave out of the right and left speaker pair. So that's something! – Russ Nov 30 '15 at 21:46