module Haskore.Interface.SuperCollider.Play.Live where
import qualified Sound.SC3 as SC
import qualified Sound.SC3.UGen.IO as SCIO
import qualified Sound.SC3.UGen.UGen as SCUGen
import qualified Sound.SC3.UGen.Oscillator as SCOsci
import qualified Sound.SC3.UGen.Filter as SCFilt
import qualified Sound.SC3.UGen.Envelope as SCUGEnv
import qualified Sound.SC3.UGen.Noise.ID as SCNoise
import qualified Sound.SC3.UGen.UId as SCUId
import Sound.SC3.UGen.Enum (DoneAction(DoNothing, PauseSynth))
import Sound.SC3.UGen.Rate (Rate(AR,KR))
import qualified Sound.SC3.Server.PlayEasy as SCPlay
import qualified Sound.SC3.Server.Command as SCCmd
import Sound.SC3.UGen.UGen (UGen)
import Sound.OpenSoundControl.Transport (Transport)
import qualified Sound.OpenSoundControl.Transport.Monad as Trans
import qualified Haskore.Interface.SuperCollider.Example as Example
import qualified Haskore.Interface.SuperCollider.Play.Install as IPlay
import qualified Haskore.Interface.SuperCollider.Play as Play
import qualified Haskore.Interface.SuperCollider.Schedule as Schedule
import qualified Haskore.Interface.SuperCollider.Schedule.Channel as CSched
import qualified Haskore.Interface.SuperCollider.Schedule.Install as ISched
import qualified Haskore.Interface.SuperCollider.Performance as SCPf
import qualified Haskore.Interface.SuperCollider.SoundMap as SoundMap
import Haskore.Interface.SuperCollider.SoundMap
(InstrumentParameters, DrumParameters, AttributeList)
import qualified Haskore.Interface.SuperCollider.Channel.Env as ChannelEnv
import qualified Haskore.Interface.SuperCollider.Channel as Channel
import Haskore.Interface.SuperCollider.Channel (Channel, NumberChannels)
import Haskore.Interface.SuperCollider.Schedule.Channel
(Sound(..), ugenFromSound,
Instrument,
Drum,
rhythmicMusicFromDynamicMelody, rhythmicMusicFromMelody,
rhythmicMusicFromRhythm, rhythmicMusicFromDrum)
import Haskore.Interface.SuperCollider.Schedule.Install
(InstrumentAttributes(..), DrumAttributes(..))
import qualified Haskore.Basic.Pitch as Pitch
import qualified Haskore.Basic.Duration as Dur
import Haskore.Basic.Duration ((%+))
import qualified Haskore.Interface.SuperCollider.Timer as SCTimer
import qualified Haskore.General.IdGenerator as IdGen
import qualified Haskore.Composition.Drum as Drum
import Haskore.Composition.Chord as Chord
import Haskore.Melody as Melody
import qualified Haskore.Music as Music
import Haskore.Music (mapNote)
import qualified Haskore.Music.Rhythmic as RhyMusic
import Haskore.Music.Rhythmic (
(+:+), (=:=),
wn, hn, qn, en, sn, tn, sfn,
dwn, dhn, dqn, den, dsn, dtn,
wnr, hnr, qnr, enr, snr, tnr, sfnr,
dwnr, dhnr, dqnr, denr, dsnr, dtnr,)
import System.Posix.Process (forkProcess)
import Control.Monad (liftM2)
import Data.List (elemIndex)
type InstrumentUGen = UGen -> UGen -> UGen
installInstr ::
(parameterTuple -> AttributeList, graph -> InstrumentUGen) ->
String ->
graph ->
IO (ISched.Instrument parameterTuple)
installInstr (makeAttributeList, makeSoundUGen) name sound =
SCPlay.withSC3 $
IPlay.installSound
(makeAttributeList, SoundMap.instrumentFromUGen . makeSoundUGen) name sound
installInstr0 ::
String ->
InstrumentUGen ->
IO (ISched.Instrument ())
installInstr0 =
installInstr SoundMap.with0Attributes
installInstr1 ::
String ->
(UGen -> InstrumentUGen) ->
IO (ISched.Instrument Double)
installInstr1 =
installInstr SoundMap.with1Attribute
installInstr2 ::
String ->
(UGen -> UGen -> InstrumentUGen) ->
IO (ISched.Instrument (Double,Double))
installInstr2 =
installInstr SoundMap.with2Attributes
type DrumUGen = UGen -> UGen
installDrum ::
(parameterTuple -> AttributeList, graph -> DrumUGen) ->
String ->
graph ->
IO (ISched.Drum parameterTuple)
installDrum (makeAttributeList, makeSoundUGen) name sound =
SCPlay.withSC3 $
IPlay.installSound
(makeAttributeList, SoundMap.drumFromUGen . makeSoundUGen) name sound
installSoundChan ::
SoundMap.SoundParameters params =>
String ->
SoundMap.Sound params ->
IO (Channel, NumberChannels)
installSoundChan name sound =
do let ugen = SoundMap.ugenFromSound sound
let numChan = SCPlay.mceDegree ugen
chan <- Channel.next ChannelEnv.manager numChan
SCPlay.withSC3 $
SCPlay.simpleSync $ SCPlay.d_recv_synthdef name $
SCIO.out (SCUGen.Constant (fromIntegral chan)) ugen
return (chan, numChan)
installInstrChan ::
(parameterTuple -> AttributeList, graph -> InstrumentUGen) ->
String ->
graph ->
IO (Instrument parameterTuple)
installInstrChan (makeAttributeList, makeInstrumentUGen) name sound =
do chanChunk <-
installSoundChan name $
SoundMap.instrumentFromUGen $
makeInstrumentUGen sound
return (Sound name chanChunk makeAttributeList)
installDrumChan ::
(parameterTuple -> AttributeList, graph -> DrumUGen) ->
String ->
graph ->
IO (Drum parameterTuple)
installDrumChan (makeAttributeList, makeDrumUGen) name sound =
do chanChunk <-
installSoundChan name $
SoundMap.drumFromUGen $
makeDrumUGen sound
return (Sound name chanChunk makeAttributeList)
reset :: IO ()
reset =
do Channel.reset ChannelEnv.manager
SCPlay.withSC3 $ SCPlay.reset
playSound :: UGen -> IO ()
playSound = fmap (const ()) . SCPlay.withSC3 . SCPlay.play
playMusic ::
RhyMusic.T DrumAttributes InstrumentAttributes -> IO ()
playMusic =
Play.performance Play.defaultLatency [] .
SCPf.fixNodeIds .
SCPf.fromRhythmicMusicWithAttributes
(\(ISched.SoundAttributes params name) -> (params,name))
(\(ISched.SoundAttributes params name) -> (params,name))
playMusicEffect ::
UGen ->
RhyMusic.T CSched.DrumAttributes CSched.InstrumentAttributes ->
IO ()
playMusicEffect effect song =
let (sid,pf) =
SCPf.fixNodeIds $
liftM2 (,)
IdGen.alloc
(SCPf.fromRhythmicMusicWithAttributes
(\(CSched.SoundAttributes params name) -> (params,name))
(\(CSched.SoundAttributes params name) -> (params,name))
song)
effectsName = "global effects"
in SCPlay.withSC3 $
Play.scheduleWithPlayer
(Play.messagesGrouped SCTimer.timer Play.defaultLatency)
(Schedule.fromPerformance
[Schedule.installUGenMsg effectsName
Schedule.defaultChannel effect]
[SCCmd.s_new effectsName sid SCCmd.AddToTail SCPlay.homeId []]
pf) >>
return ()
germanLatin1Keyboard :: [Char]
germanLatin1Keyboard =
let oUmlaut = '\246'
uUmlaut = '\252'
szLig = '\223'
in "ysxdcvgbhnjm,l."++oUmlaut:"-q2w3e4rt6z7ui9o0p"++szLig:uUmlaut:"+"
playKey :: ISched.Instrument () -> Char -> IO ()
playKey (ISched.Sound name _) key =
maybe
(return ())
(\pitch ->
do SCPlay.withSC3 $
Play.playAtom SCPlay.noId name $
("pitch", Pitch.intToFreq pitch) :
("velocity", 1) : []
print (Pitch.fromInt pitch))
(elemIndex key germanLatin1Keyboard)
playKeyboard :: ISched.Instrument () -> IO ()
playKeyboard instr =
let recourse =
do char <- getChar
if char == '\004'
then putStrLn ""
else do putChar '\008'
playKey instr char
recourse
in recourse
example :: IO ()
example =
do reset
sawPerc <- installInstr0 "saw percussion" Example.sawPercUGen
dynPerc <- installInstr1 "detuned bass" Example.dynPercUGen
let mel = ISched.rhythmicMusicFromMelody sawPerc $ Music.transpose 12 $ Music.line
[c 0 qn (), e 0 qn (),
Music.chord [c 0 qn (), e 0 qn (), g 0 qn ()]]
bass = ISched.rhythmicMusicFromMelody dynPerc $ Music.line
[c 0 qn 0.001, c 0 qn 0.003, c 0 qn 0.01]
playMusic $
Music.changeTempo 2 $
Music.chord [mel,bass]
exampleEffect :: IO ()
exampleEffect =
do reset
sawPerc <- installInstrChan SoundMap.with0Attributes "saw percussion" Example.sawPercUGen
dynPerc <- installInstrChan SoundMap.with1Attribute "detuned bass" Example.dynPercUGen
let lfoSine = exp (SCOsci.sinOsc KR 0.2 (pi/2) * 0.5) * 1000
lfoSquare = exp (SCOsci.pulse KR 5.1 0.5 * 1) * 1000
mix =
SCFilt.rlpf (0.5 * ugenFromSound sawPerc) lfoSine 0.1 +
SCFilt.rlpf (0.5 * ugenFromSound dynPerc) lfoSquare 0.1
let mel = CSched.rhythmicMusicFromMelody sawPerc $ Music.transpose 12 $ Music.line $
cycle [c 0 qn (), b 0 qn (), c 1 qn ()]
bass = CSched.rhythmicMusicFromMelody dynPerc $ Music.line $
cycle [c 0 qn 0.001, c 0 qn 0.003, c 0 qn 0.01]
playMusicEffect mix $
Music.changeTempo 2 $
Music.chord [Music.changeTempo 3 mel, bass]