All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.sciss.mellite.Mellite.scala Maven / Gradle / Ivy

/*
 *  Mellite.scala
 *  (Mellite)
 *
 *  Copyright (c) 2012-2016 Hanns Holger Rutz. All rights reserved.
 *
 *  This software is published under the GNU General Public License v3+
 *
 *
 *  For further information, please contact Hanns Holger Rutz at
 *  [email protected]
 */

package de.sciss.mellite

import javax.swing.UIManager

import de.sciss.desktop.impl.{SwingApplicationImpl, WindowHandlerImpl}
import de.sciss.desktop.{OptionPane, WindowHandler}
import de.sciss.lucre.stm.TxnLike
import de.sciss.lucre.swing.requireEDT
import de.sciss.lucre.synth.{Server, Txn}
import de.sciss.mellite.gui.impl.document.DocumentHandlerImpl
import de.sciss.mellite.gui.{DocumentViewHandler, LogFrame, MainFrame, MenuBar}
import de.sciss.nuages.Wolkenpumpe
import de.sciss.{mellite, osc}
import de.sciss.synth.proc.{AuralSystem, Code, SensorSystem}

import scala.collection.immutable.{Seq => ISeq}
import scala.concurrent.stm.{TxnExecutor, atomic}
import scala.language.existentials
import scala.swing.Label
import scala.util.control.NonFatal

object Mellite extends SwingApplicationImpl("Mellite") with Application {

  import de.sciss.synth.proc
//  //  lucre.event    .showLog = true
//  //  lucre.confluent.showLog = true
//  proc.showLog            = true
//  proc.showAuralLog       = true
//  proc.showTransportLog   = true
//  showLog                 = true
//  showTimelineLog         = true
//  de.sciss.lucre.bitemp.impl.BiGroupImpl.showLog = true
//  // gui.impl.timeline.TimelineViewImpl.DEBUG = true
//  de.sciss.lucre.event.showLog = true

  def version : String = buildInfString("version")
  def license : String = buildInfString("license")
  def homepage: String = buildInfString("homepage")

  private def buildInfString(key: String): String = try {
    val clazz = Class.forName("de.sciss.mellite.BuildInfo")
    val m     = clazz.getMethod(key)
    m.invoke(null).toString
  } catch {
    case NonFatal(e) => "?"
  }

  lazy val isDarkSkin: Boolean = UIManager.getBoolean("dark-skin")

  override lazy val windowHandler: WindowHandler = new WindowHandlerImpl(this, menuFactory) {
    override lazy val usesInternalFrames = {
      false // XXX TODO: eventually a preferences entry
    }

    override lazy val usesNativeDecoration = Prefs.nativeWindowDecoration.getOrElse(true)
  }

  protected def menuFactory = MenuBar.instance

  private lazy val _aural     = AuralSystem ()
  private lazy val _sensor    = SensorSystem()
  private lazy val _compiler  = proc.Compiler()

  implicit def auralSystem : AuralSystem   = _aural
  implicit def sensorSystem: SensorSystem  = _sensor
  implicit def compiler    : Code.Compiler = _compiler

  def clearLog  (): Unit = LogFrame.instance.log.clear()
  def logToFront(): Unit = LogFrame.instance.front()  // XXX TODO - should avoid focus transfer

  /** Tries to start the aural system by booting SuperCollider.
    * This reads the relevant preferences entries such as
    * path, audio device, number of output channels, etc.
    * Transport is hard-coded to TCP at the moment, and port
    * is randomly picked.
    *
    * If the program path does not denote an existing file,
    * an error dialog is shown, and the method simply returns `false`.
    *
    * ''Note:'' This method must run on the EDT.
    *
    * @return `true` if the attempt to boot was made, `false` if the program was not found
    */
  def startAuralSystem(): Boolean = {
    requireEDT()
    val config        = Server.Config()
    applyAudioPrefs(config, useDevice = true, pickPort = true)
    import de.sciss.file._

    val f = file(config.program)
    if (!f.isFile && (f.parentOption.nonEmpty || {
      sys.env.getOrElse("PATH", "").split(File.pathSep).forall(p => !(file(p) / config.program).isFile)
    })) {
      val msg = new Label(
        s"""The SuperCollider server program 'scsynth'
|is not found at this location:

 
${config.program}

 
|Please adjust the path in the preferences.""".stripMargin ) val opt = OptionPane.message(msg, OptionPane.Message.Error) opt.show(title = "Starting Aural System") return false } TxnExecutor.defaultAtomic { implicit itx => implicit val tx = Txn.wrap(itx) auralSystem.start(config) } true } def applyAudioPrefs(config: Server.ConfigBuilder, useDevice: Boolean, pickPort: Boolean): Unit = { requireEDT() import de.sciss.file._ val programPath = Prefs.superCollider.getOrElse(Prefs.defaultSuperCollider) if (programPath != Prefs.defaultSuperCollider) config.program = programPath.path if (useDevice) { val audioDevice = Prefs.audioDevice .getOrElse(Prefs.defaultAudioDevice) if (audioDevice != Prefs.defaultAudioDevice) config.deviceName = Some(audioDevice) } val numOutputs = Prefs.audioNumOutputs .getOrElse(Prefs.defaultAudioNumOutputs) config.outputBusChannels = numOutputs val numInputs = Prefs.audioNumInputs .getOrElse(Prefs.defaultAudioNumInputs) config.inputBusChannels = numInputs val numPrivate = Prefs.audioNumPrivate .getOrElse(Prefs.defaultAudioNumPrivate) config.audioBusChannels = numInputs + numOutputs + numPrivate config.wireBuffers = Prefs.audioNumWireBufs.getOrElse(Prefs.defaultAudioNumWireBufs) config.sampleRate = Prefs.audioSampleRate .getOrElse(Prefs.defaultAudioSampleRate) config.blockSize = Prefs.audioBlockSize .getOrElse(Prefs.defaultAudioBlockSize) config.memorySize = Prefs.audioMemorySize .getOrElse(Prefs.defaultAudioMemorySize) * 1024 if (pickPort) { config.transport = osc.TCP config.pickPort() } } def startSensorSystem(): Unit = { val config = SensorSystem.Config() config.osc = Prefs.defaultSensorProtocol match { case osc.UDP => osc.UDP.Config() case osc.TCP => osc.TCP.Config() } config.osc.localPort = Prefs.sensorPort .getOrElse(Prefs.defaultSensorPort ) config.command = Prefs.sensorCommand.getOrElse(Prefs.defaultSensorCommand) atomic { implicit itx => implicit val tx = TxnLike.wrap(itx) sensorSystem.start(config.build) } } override protected def init(): Unit = { Application.init(this) // ---- type extensions ---- mellite.initTypes() Wolkenpumpe.init() // ---- look and feel try { val lafInfo = Prefs.lookAndFeel.getOrElse { val res = Prefs.LookAndFeel.default Prefs.lookAndFeel.put(res) res } lafInfo.install() } catch { case NonFatal(e) => e.printStackTrace() } UIManager.getDefaults.remove("SplitPane.ancestorInputMap") // I don't remember -- what was this about? // if (isDarkSkin) { // UIManager.put("Table.background", new ColorUIResource( 29, 32, 36)) // UIManager.put("Table.foreground", new ColorUIResource(220, 220, 220)) // } if (Prefs.useLogFrame) LogFrame.instance // init DocumentViewHandler.instance // init new MainFrame } /** We are bridging between the transactional and non-EDT `mellite.DocumentHandler` and * the GUI-based `de.sciss.desktop.DocumentHandler`. This is a bit ugly. In theory it * should be fine to call into either, as this bridge is backed up by the peer * `mellite.DocumentHandler.instance`. */ override lazy val documentHandler: DocumentHandler = new DocumentHandlerImpl // ---- Application trait ---- lazy val topLevelObjects: ISeq[String] = List("Folder", "AudioGrapheme", "Proc", "Timeline") /** All objects included */ lazy val objectFilter: String => Boolean = _ => true }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy