module Music.Score.Export.SuperCollider (
SuperCollider,
HasSuperCollider,
toSuperCollider,
writeSuperCollider,
openSuperCollider,
) where
import Music.Dynamics.Literal
import Music.Pitch.Literal
import qualified Codec.Midi as Midi
import Control.Comonad (Comonad (..), extract)
import Control.Applicative
import Data.Colour.Names as Color
import Data.Foldable (Foldable)
import qualified Data.Foldable
import Data.Functor.Couple
import Data.Maybe
import Data.Ratio
import Data.Traversable (Traversable, sequenceA)
import Music.Score.Internal.Export hiding (MVoice)
import System.Process
import Music.Score.Internal.Quantize
import qualified Text.Pretty as Pretty
import qualified Data.List
import Music.Score.Internal.Util (composed, unRatio, swap, retainUpdates)
import Music.Score.Export.DynamicNotation
import Data.Semigroup.Instances
import Music.Score.Export.Backend
import Data.Functor.Identity
import Data.Semigroup
import Control.Monad
import Data.VectorSpace hiding (Sum(..))
import Data.AffineSpace
import Control.Lens hiding (rewrite)
import Music.Time
import Music.Score.Meta
import Music.Score.Meta.Title
import Music.Score.Meta.Attribution
import Music.Score.Dynamics
import Music.Score.Articulation
import Music.Score.Part
import Music.Score.Tremolo
import Music.Score.Text
import Music.Score.Harmonics
import Music.Score.Slide
import Music.Score.Color
import Music.Score.Ties
import Music.Score.Export.Backend
import Music.Score.Meta.Time
import Music.Score.Phrases
data SuperCollider
type ScContext = Identity
type ScEvent = (Double, Double)
data ScScore a = ScScore [[(Duration, Maybe a)]]
deriving (Functor)
instance Monoid (ScScore a) where
mempty = ScScore mempty
ScScore a `mappend` ScScore b = ScScore (a `mappend` b)
instance HasBackend SuperCollider where
type BackendContext SuperCollider = ScContext
type BackendScore SuperCollider = ScScore
type BackendNote SuperCollider = ScEvent
type BackendMusic SuperCollider = String
finalizeExport _ (ScScore trs) = composeTracksInParallel $ map exportTrack trs
where
composeTracksInParallel :: [String] -> String
composeTracksInParallel = (\x -> "Ppar([" ++ x ++ "])") . Data.List.intercalate ", "
exportTrack :: [(Duration, Maybe ScEvent)] -> String
exportTrack triples = "Pbind("
++ "\\dur, Pseq(" ++ show durs ++ ")"
++ ", "
++ "\\midinote, Pseq(" ++ showRestList pitches ++ ")"
++ ")"
where
showRestList = (\x -> "[" ++ x ++ "]")
. Data.List.intercalate ", "
. map (maybe "\\rest" show)
durs :: [Double]
pitches :: [Maybe Double]
ampls :: [Maybe Double]
durs = map (realToFrac . fst) triples
pitches = map (fmap fst . snd) triples
ampls = map (fmap snd . snd) triples
instance () => HasBackendScore SuperCollider (Voice (Maybe a)) where
type BackendScoreEvent SuperCollider (Voice (Maybe a)) = a
exportScore _ xs = Identity <$> ScScore [view pairs xs]
instance (HasPart' a, Ord (Part a)) => HasBackendScore SuperCollider (Score a) where
type BackendScoreEvent SuperCollider (Score a) = a
exportScore b = mconcat
. map (exportScore b . view singleMVoice)
. extractParts
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider [a] where
exportNote b ps = head $ map (exportNote b) $ sequenceA ps
instance HasBackendNote SuperCollider Double where
exportNote _ (Identity x) = (x + 60, 1)
instance HasBackendNote SuperCollider Int where
exportNote _ (Identity x) = (fromIntegral x + 60, 1)
instance HasBackendNote SuperCollider Integer where
exportNote _ (Identity x) = (fromIntegral x + 60, 1)
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (Behavior a) where
exportNote b = exportNote b . fmap (! 0)
exportChord b = exportChord b . fmap (fmap (! 0))
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (DynamicT b a) where
exportNote b = exportNote b . fmap extract
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (ArticulationT b a) where
exportNote b = exportNote b . fmap extract
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (PartT n a) where
exportNote b = exportNote b . fmap extract
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (TremoloT a) where
exportNote b = exportNote b . fmap extract
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (TextT a) where
exportNote b = exportNote b . fmap extract
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (HarmonicT a) where
exportNote b = exportNote b . fmap extract
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (SlideT a) where
exportNote b = exportNote b . fmap extract
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (TieT a) where
exportNote b = exportNote b . fmap extract
instance HasBackendNote SuperCollider a => HasBackendNote SuperCollider (ColorT a) where
exportNote b = exportNote b . fmap extract
type HasSuperCollider a = (HasBackendNote SuperCollider (BackendScoreEvent SuperCollider a), HasBackendScore SuperCollider a)
toSuperCollider :: HasSuperCollider a => a -> String
toSuperCollider = export (undefined::SuperCollider)
writeSuperCollider :: HasSuperCollider a => FilePath -> a -> IO ()
writeSuperCollider path score =
writeFile path ("(" ++ toSuperCollider score ++ ").play")
openSuperCollider :: HasSuperCollider a => a -> IO ()
openSuperCollider = writeSuperCollider "test.sc"