Search code examples
javascalaintellij-ideajavasound

Java Sound: devices found when run in IntelliJ, but not in SBT


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).


Solution

  • 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
      
    • the forked JVM can be killed by any external tool without problem (using kill or any kind of task manager)