moduleHaskore.Interface.SuperCollider.Render(fileFromMelody,fileFromMelodyMonad,byteStringFromSchedule,runSCSynth,HeaderFormat(..),SampleFormat(..),)whereimportqualifiedHaskore.Interface.SuperCollider.ScheduleasScheduleimportqualifiedHaskore.Interface.SuperCollider.PlayasPlayimportHaskore.Interface.SuperCollider.Schedule(Time)importHaskore.Interface.SuperCollider.SoundMap(Instrument)importqualifiedSound.SC3.Server.NRTasSCNRTimportqualifiedSound.SC3.Server.PlayEasyasSCPlay-- import Sound.OpenSoundControl.Transport (Transport)-- import qualified Sound.OpenSoundControl.Transport.Monad as TransimportSound.OpenSoundControl.OSC(OSC(Bundle))importqualifiedSound.OpenSoundControl.TimeasOSCTimeimportqualifiedData.ByteString.LazyasBimportqualifiedHaskore.MelodyasMelodyimportqualifiedHaskore.RealTime.Timer.ImmediateasTimerImmediateimportqualifiedHaskore.RealTime.EventList.TimeBodyasTimeListimportqualifiedData.EventList.Absolute.TimeBodyasAbsoluteEventListimportqualifiedNumeric.NonNegative.WrapperasNonNegimportSystem.Cmd(rawSystem)importSystem.Exit(ExitCode)importData.Array(Array,Ix,(!),listArray){- * Generate audio files for various representations of music. -}fileFromMelody::FilePath->Instrument->Melody.T()->IO()fileFromMelodyfileNamesound=B.writeFilefileName.byteStringFromSchedule.Schedule.fromMelodysoundfileFromMelodyMonad::FilePath->Instrument->Melody.T()->IO()fileFromMelodyMonadfileNamesound=SCPlay.withSC3FilefileName.Play.scheduleWithPlayer(Play.messagesGroupedTimerImmediate.timer0).Schedule.fromMelodysound{- * invocation of SuperCollider program -}dataHeaderFormat=AIFF|Wave|NeXTderiving(Read,Show,Eq,Ord,Ix,Bounded)headerExtension::ArrayHeaderFormatStringheaderExtension=listArray(minBound,maxBound)["aiff","wav","au"]headerName::ArrayHeaderFormatStringheaderName=listArray(minBound,maxBound)["AIFF","WAVE","NeXT"]dataSampleFormat=Int16|Int24|Int32|Float|Doublederiving(Read,Show,Eq,Ord,Ix,Bounded)sampleName::ArraySampleFormatStringsampleName=listArray(minBound,maxBound)["int16","int24","int32","float","double"]{-
because there are so much parameters,
an option list would be the better choice
-}runSCSynth::[String]->Int{- ^ number of (stereo) channels -}->HeaderFormat->SampleFormat->Int{- ^ sample rate -}->FilePath->IOExitCoderunSCSynthoptionsnumChannelsheaderFormatsampleFormatsampleRatefileName=rawSystem"scsynth"(options++["-D","0","-o",shownumChannels,"-N",fileName++".osc","_",fileName++'.':headerExtension!headerFormat,showsampleRate,headerName!headerFormat,sampleName!sampleFormat]){- * helper functions -}byteStringFromSchedule::Schedule.T->B.ByteStringbyteStringFromSchedule=SCNRT.encodeNRT.scheduleToStreamscheduleToStream::Schedule.T->[OSC]scheduleToStreamsc=timeStamp0(Schedule.initialsc):messagesToStream(Schedule.bodysc)messagesToStream::TimeList.TTimeOSC->[OSC]messagesToStream=map(uncurrytimeStamp).AbsoluteEventList.toPairList.{- first absolutize, then collectCoincident in order to catch
coincidences caused by rounding -}AbsoluteEventList.collectCoincident.TimeList.toAbsoluteEventList0timeStamp::Time->[OSC]->OSCtimeStamp=Bundle.OSCTime.NTPr.NonNeg.toNumber