I'm trying to to use Java Sound API in a Scala SBT-managed project.
Here is a toy app that plays a note.
import javax.sound.midi._
object MyMain extends App {
val infos = MidiSystem.getMidiDeviceInfo()
println( "[DEBUG] midi devices found: " + infos.length )
val myMsg = new ShortMessage;
// Start playing the note Middle C (60),
// moderately loud (velocity = 93).
myMsg.setMessage(ShortMessage.NOTE_ON, 0, 60, 93);
val timeStamp = -1;
val rcvr : Receiver = MidiSystem.getReceiver();
rcvr.send(myMsg, timeStamp);
readChar() // give time to play note
}
When I execute run
in SBT, I get the javax.sound.midi.MidiUnavailableException
because infos.length
returns 0. That said, when I run the app in IntelliJ, two devices are found and the note plays just fine.
What does SBT need to know to make it run? Is there something which needs to be added to the classpath? I noticed that IntelliJ attaches a whole bunch of jars to the execution command (however, removing those of the jars that come from jdk/jre/lib/ had no effect, while the others are scala related or IntelliJ related).
SBT runs your application in-process, with some classloader magic, which probably prevents MidiSystem
from finding (using SPI) the sound components.
You can try forking a new JVM to run your application: fork in run := true
. See Forking in the documentation.
Note that:
by default it does not redirect input to the application. You can add that with:
connectInput in run := true
kill
or any kind of task manager)