temporal-csound 0.2.1 → 0.3.0
raw patch · 5 files changed
+545/−37 lines, 5 filesdep +csound-catalogdep +temporal-music-notation-westerndep ~csound-expression
Dependencies added: csound-catalog, temporal-music-notation-western
Dependency ranges changed: csound-expression
Files
- LICENSE +1/−1
- src/Csound.hs +155/−32
- src/Csound/Converter.hs +33/−0
- src/Csound/Patch.hs +301/−0
- temporal-csound.cabal +55/−4
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2013, Anton Kholomiov+Copyright (c) 2014, Anton Kholomiov All rights reserved.
src/Csound.hs view
@@ -1,5 +1,6 @@ {-# Language FlexibleInstances #-}--- | Defines instance of 'Csound.Base.CsdSco' for 'Temporal.Music.Score.Score'. +-- | Defines instance of 'Csound.Base.CsdSco' for 'Temporal.Music.Score.Score' and+-- reexports all functions from packages csound-expression and temporal-music-notation-western. -- -- We can trigger Csound orchestra with 'Temporal.Music.Score.Score'. --@@ -26,55 +27,177 @@ -- There are two handy infix operators for delay and stretch: @(+|)@ and @(*|)@. So we can write the previous score: -- -- > res = 0.5 *| mel [ temp a, 2 *| temp b, 1 +| har [temp a, temp b] ]+--+-- There are shortcuts for notes in western notation (a is 440 Hz).+--+-- > a, b, c, d, e, f, g+--+-- Notes reside in the same octave. To get the notes in higher or lower octaves+-- we can apply the functions:+--+-- * 'Temporal.Music.Score.high', 'Temporal.Music.Score.low' -- take note an octaver higher or lower+--+-- * 'Temporal.Music.Score.higher' n, 'Temporal.Music.Score.lower' n -- take note for @n@ octaves higher or lower+--+-- There are shortcuts for stretching the notes and rests:+--+-- > bn, wn, qn, en, sn -- brevis, whole, quarter, eight, sixteenth notes+--+-- and for rests+--+-- > bnr, wnr, qnr, enr, snr+--+-- These functions transform the melodies with given factors.+-- We can construct melodies:+--+-- > melody = mel [qn $ mel [c, e, g], bn $ har [c, e, g, high c], wnr]+--+-- Then we can apply a csound instrument to the melody to get the signal.+--+-- > res = notes someInstr melody+--+-- Now let's mix it to the signal and send the output to speakers:+--+-- > dac $ mix res +--+-- WARNING: The function 'dac' spawns a csound process in the background which+-- can run forever. If your haskell build tool doesn't kills the child processes with+-- haskell-runing process (As far as I know Sublime Editor doesn't, but vim does) +-- it's better to run the program from ghci and to stop it press @Ctrl+C@:+--+-- > % ghci MyMusic+-- > MyMusic> main +-- >+-- > ... The programm runs ... press Ctrl+C to stop it+-- >+-- +-- @runhaskell@ doesn't stop the child process. So it's better to use the+-- @dac@ function with terminal.+-- +-- If signal is to loud or to quiet we can scale it:+--+-- > dac $ mul factor $ mix res +-- +-- We can make it brighter with reverb ('Csound.Air.smallRoom', 'Csound.Air.smallHall', 'Csound.Air.largeHall', 'Csound.Air.reverTime')+--+-- > dac $ mul 0.2 $ smallHall $ mix res + module Csound (- {-+ -- * Converters- CsdNote, csdNote, CsdDrum, csdDrum, + CsdNote(..), csdNote, CsdDrum, csdDrum, N, Dr, -- * Scores- - -- | Tools to make compositions out of timbres.- sco, notes, drums,- -}+ --+ -- | Funxtions that apply instruments to scores. + --+ -- Notes on signatures:+ --+ -- * The class 'Csound.Base.Outs' includes the tuples of signals + -- that have side effects or have no side effects.+ --+ -- * @SigOuts@ -- means an underlying tuple of signals.+ -- For instance, it can be @Sig@ or @SE Sig@, the @SigOuts@+ -- converts it to the @Sig@. The @SigOuts@ removes the + -- prefix @SE@ if it is present.+ --+ -- * To get the final signal out of the type @Score (Mix (SigOuts b))@+ -- we should apply the function 'Csound.Base.mix' to it:+ --+ -- > mix :: (CsdSco f, Sigs a) => f (Mix a) -> a+ -- + -- Or we can continue to build the track of signals with + -- functions loke 'Temporal.Music.Score.mel', 'Temporal.Music.Score.har', 'Temporal.Music.Score.str'.+ notes, drums, ++ -- * Midis + --+ -- | Plays instruments with midi devices.+ --+ -- > import Csound + -- > import Csound.Patch(vibraphone2)+ -- >+ -- > -- | Plays with virtual midi device (if you have a midi device+ -- > -- you can substitute @vdac@ for @dac@).+ -- > main = vdac $ mul 0.1 $ largeHall $ onMidi vibraphone2+ -- + onMidi, onMidin, onPgmidi, + onMidiWith, onMidinWith, onPgmidiWith, - module Temporal.Music,+ module Temporal.Music.Western.P12, module Csound.Base ) where -import Temporal.Music hiding (delay, event, line, chord) import Temporal.Media(Track) import Csound.Base--import qualified Temporal.Music as T+import Temporal.Music.Western.P12 hiding (delay, event, line, chord, tone) instance CsdSco (Track Double) where toCsdEventList x = CsdEventList (dur x) (fmap toEvt $ render x) where toEvt a = (eventStart a, eventDur a, eventContent a) singleCsdEvent (start, dt, a) = del start $ str dt $ temp a -{---- | Plays some notes with Csound instrument. -sco :: Arg a => (a -> Out) -> Score a -> SigOut-sco instr s = score instr (fmap unpackEvent $ alignByZero $ render s)- where unpackEvent e = (eventStart e, eventDur e, eventContent e)+type N = CsdNote Unit+type Dr = CsdDrum Unit --- | Playes notes.-notes :: Arg a => (CsdNote a -> Out) -> Score (Note a) -> SigOut-notes instr as = sco instr (fmap csdNote as)+-- | Contains amplitude, frequency and auxiliary parameters.+--+-- > (amplitude, frequencyInHz, timbralParameters)+type CsdNote a = (D, D, a) --- | Plays drum-notes.-drums :: Arg a => (CsdDrum a -> Out) -> Score (Drum a) -> SigOut-drums instr as = sco instr (fmap csdDrum as)- --- | Csound note: (amplitude, cyclesPerSecond, otherParams) -type CsdNote a = (D, D, a) +-- | Contains amplitude and auxiliary parameters.+--+-- > (amplitude, timbralParameters)+type CsdDrum a = (D, a) -csdNote :: Note a -> CsdNote a-csdNote a = (double $ amp $ noteVolume a, double $ hz $ notePitch a, noteParam a)+-- | Converts the @Note@ to low level @CsdNote@.+csdNote :: Default a => Note a -> CsdNote a+csdNote a = + ( double $ volumeAsDouble $ noteVolume a+ , double $ absPitch $ notePitch a+ , maybe def id $ noteParam a) --- | Csound drum-note: (amplitude, otherParams)-type CsdDrum a = (D, a)+-- | Converts the @Note@ to low level @CsdNote@.+csdDrum :: Default a => Drum a -> CsdDrum a+csdDrum a = + ( double $ volumeAsDouble $ drumVolume a+ , maybe def id $ drumParam a) -csdDrum :: Drum a -> CsdDrum a-csdDrum a = (double $ amp $ drumVolume a, drumParam a)--}+-- | Plays the notes with csound instrument.+notes :: (Arg a, Default a, Outs b) => (CsdNote a -> b) -> Score (Note a) -> Score (Mix (SigOuts b))+notes g f = sco (toOuts . g) (fmap csdNote f)++-- | Plays the drum notes with csound instrument.+drums :: (Arg a, Default a, Outs b) => (CsdDrum a -> b) -> Score (Drum a) -> Score (Mix (SigOuts b))+drums g f = sco (toOuts . g) (fmap csdDrum f)++toMidiInstr :: (Default a, Outs b) => (CsdNote a -> b) -> (Msg -> SE (SigOuts b))+toMidiInstr f = \msg -> toOuts $ f (ampmidi msg 1, cpsmidi msg, def) ++toMidiInstrWith :: (Outs b) => a -> (CsdNote a -> b) -> (Msg -> SE (SigOuts b))+toMidiInstrWith defVal f = \msg -> toOuts $ f (ampmidi msg 1, cpsmidi msg, defVal) ++-- | Triggers an instrument on all midi-channels.+onMidi :: (Default a, Outs b) => (CsdNote a -> b) -> SigOuts b+onMidi f = midi $ toMidiInstr f++-- | Triggers an instrument on the given midi-channel.+onMidin :: (Default a, Outs b) => Channel -> (CsdNote a -> b) -> SigOuts b+onMidin chn f = midin chn $ toMidiInstr f++-- | Triggers an instrument on channel and programm bank.+onPgmidi :: (Default a, Outs b) => Maybe Int -> Channel -> (CsdNote a -> b) -> SigOuts b+onPgmidi pgm chn f = pgmidi pgm chn $ toMidiInstr f++-- | Just like @onMidi@ but takes a value for default auxiliary parameters.+onMidiWith :: (Outs b) => a -> (CsdNote a -> b) -> SigOuts b+onMidiWith defVal f = midi $ toMidiInstrWith defVal f++-- | Just like @onMidin@ but takes a value for default auxiliary parameters.+onMidinWith :: (Outs b) => a -> Channel -> (CsdNote a -> b) -> SigOuts b+onMidinWith defVal chn f = midin chn $ toMidiInstrWith defVal f++-- | Just like @onPgmidi@ but takes a value for default auxiliary parameters.+onPgmidiWith :: (Outs b) => a -> Maybe Int -> Channel -> (CsdNote a -> b) -> SigOuts b+onPgmidiWith defVal pgm chn f = pgmidi pgm chn $ toMidiInstrWith defVal f+
+ src/Csound/Converter.hs view
@@ -0,0 +1,33 @@+-- | Converters for the instruments.+module Csound.Converter(+ -- * Pitched instruments+ fromF, fromFs, fromAF, fromAsFs, fromAFs, fromAsF,++ -- * Drums+ fromDrum+) where++import Csound++fromF :: SigSpace a => (D -> a) -> CsdNote Unit -> a+fromF f (amp, cps, _) = mul (sig amp) $ f cps++fromFs :: SigSpace a => (Sig -> a) -> CsdNote Unit -> a+fromFs f (amp, cps, _) = mul (sig amp) $ f (sig cps)++fromAF :: (D -> D -> a) -> CsdNote Unit -> a+fromAF f (amp, cps, _) = f amp cps++fromAsFs :: (Sig -> Sig -> a) -> CsdNote Unit -> a+fromAsFs f (amp, cps, _) = f (sig amp) (sig cps)++fromAFs :: (D -> Sig -> a) -> CsdNote Unit -> a+fromAFs f (amp, cps, _) = f amp (sig cps)++fromAsF :: (Sig -> D -> a) -> CsdNote Unit -> a+fromAsF f (amp, cps, _) = f (sig amp) cps++-- Drums++fromDrum :: SigSpace a => a -> Dr -> a+fromDrum a (amp, _) = mul (sig amp) a
+ src/Csound/Patch.hs view
@@ -0,0 +1,301 @@+-- | Ready to use instruments.+--+-- An instrument takes in a note (@N@ which is shortcut for @CsdNote Unit@ +-- or @Dr@ which is shortcut for @CsdDrum Unit@) and procuces a signal.+-- We can use instruments with functions 'Csound.notes' and 'Csound.drums'.+--+-- > import Csound +-- > import Csound.Patch(stringPad)+-- >+-- > -- | Plays C-major chord.+-- > main = dac $ mul 0.2 $ smallHall $ mix $ notes stringPad $ +-- > str 0.5 $ mel [c, e, g, str 4 $ har [c, e, g, high c], rest 4]+--+-- Let's explain the functions:+-- +-- > -- dac -- sends signal to speakers+-- > -- +-- > -- mul -- scales the signal+-- > -- +-- > -- smallHall -- adds a reverb+-- > --+-- > -- mix -- mixes several tracks to a single signal+-- > --+-- > -- notes -- applies an instrument to the notes+-- > --+-- > -- stringPad -- predefined instrument+-- > -- +-- > -- str -- stretch the notes in time domain+-- > --+-- > -- mel, har -- sequential and parallel composition of the notes+-- > --+-- > -- c, e, g -- notes in western notation (a, b, c, d, ...), a is 440 Hz +-- > --+-- > -- high -- an octave higher+-- > --+-- > -- rest -- pause for a given amount of time+module Csound.Patch(+ -- * Pads+ stringPad, phasingSynth, pulseWidthPad,+ melodica, tibetan, ++ -- * Mystic+ sparkles, xanaduHarp,++ -- * Lead+ delaySaw, pulseWidth, toneWheel,++ -- * Tech+ okComp, OkCompParam(..), fmMod,++ -- * Plucked+ delayedStringLong, delayedStringShort, + plucked, xanadu1, xanadu2,+ guitar, harpsichord, harpsichordHarp, plainString, plainStringHarp,++ -- * Strike+ noisyMarimba, dahina, banyan, xylophone,+ spinelSphere, aluminumBar, + vibraphone1, vibraphone2, wineGlass, xing,++ -- ** Bells + amBell, fmTubularBell, tubularBell, albertClockBellBelfast,++ -- * Drums+ dumb, dumbBass, pluckSnare, knockSweep, metalBoink,+ snare, openHihat, closedHihat, bassDrum, crash, handClap,+ bambooDr, guiroDr, tambourineDr, cabasaDr, crunchDr,+ sleighbellsDr, sekereDr, sandpaperDr ++) where++import Csound(N, Dr, CsdNote, CsdDrum)+import Csound.Base++import qualified Csound.Catalog.Wave as C+import qualified Csound.Catalog.Effect as C+import qualified Csound.Catalog.Reson as C+import qualified Csound.Catalog.Drum as C++import Csound.Converter++fade :: SigSpace a => D -> D -> (b -> a) -> (b -> a)+fade ris dec f = mul (fades ris dec) . f++--------------------------------------------------------------------+-- Padds++stringPad :: N -> Sig+stringPad = fade 0.5 1.5 $ fromAsFs C.stringPad++phasingSynth :: N -> Sig+phasingSynth = fade 0.3 1.5 $ fromAsFs C.phasingSynth++melodica :: N -> SE Sig+melodica = fade 0.5 2.5 $ fromFs $ C.melody 5++-- | Parameter is time of fade out in seconds.+tibetan :: D -> N -> Sig+tibetan dec = fade 1 dec $ fromF $ C.tibetan 9 0.02++pulseWidthPad :: N -> Sig+pulseWidthPad = fade 1 1.5 $ fromAsFs C.pulseWidth++--------------------------------------------------------------------+-- Mystic++sparkles :: N -> SE Sig+sparkles = fade 0.01 2.5 $ fromFs $ C.blue 3 8 0.5 15++xanaduHarp :: N -> SE Sig+xanaduHarp = fade 0.01 5 $ fromF C.xanadu1++--------------------------------------------------------------------+-- Lead++pulseWidth :: N -> Sig+pulseWidth = fade 0.1 0.1 $ fromAsFs C.pulseWidth++delaySaw :: N -> Sig+delaySaw = fade 0.1 0.2 $ fromFs $ C.delaySaw++toneWheel :: N -> Sig+toneWheel = fade 0.01 0.1 $ fromF C.toneWheel++--------------------------------------------------------------------+-- Tech++okComp :: CsdDrum OkCompParam -> SE Sig+okComp = fade 0.01 0.1 $ \(amp, OkCompParam rate) -> mul (sig amp) $ C.okComputer (sig rate)++newtype OkCompParam = OkCompParam { unOkCompParam :: D }++instance Tuple OkCompParam where+ tupleMethods = makeTupleMethods OkCompParam unOkCompParam++instance Arg OkCompParam++instance Default OkCompParam where+ def = OkCompParam 10++fmMod :: N -> Sig+fmMod = fade 0.01 0.1 $ fromFs $ C.fmMod 5++--------------------------------------------------------------------+-- Plucked++pick :: SigSpace b => D -> (a -> b) -> (a -> b)+pick dec = fade 0.01 dec++delayedStringLong :: N -> Sig+delayedStringLong = pick 2.5 $ fromF C.delayedString++delayedStringShort :: N -> Sig+delayedStringShort = pick 0.1 $ fromF C.delayedString++plucked :: N -> Sig+plucked = pick 0.3 $ fromFs C.rhodes++xanadu1 :: N -> SE Sig+xanadu1 = pick 1.5 $ fromF C.xanadu1++xanadu2 :: N -> SE Sig+xanadu2 = pick 0.8 $ fromF C.xanadu2++guitar :: N -> Sig+guitar = fade 0.05 2 $ fromF C.guitar++harpsichord :: N -> Sig+harpsichord = pick 0.2 $ fromF C.harpsichord++harpsichordHarp :: N -> Sig+harpsichordHarp = pick 5 $ fromF C.harpsichord++plainString :: N -> Sig+plainString = pick 0.5 $ fromF C.plainString++plainStringHarp :: N -> Sig+plainStringHarp = pick 5 $ fromF C.plainString++--------------------------------------------------------------------+-- Striked++strk :: SigSpace b => (a -> b) -> (a -> b)+strk = pick 2.5++noisyMarimba :: N -> SE Sig+noisyMarimba = strk $ fromFs C.blackMarimba++dahina :: N -> Sig+dahina = strk $ fromFs C.dahina++banyan :: N -> Sig+banyan = strk $ fromFs C.banyan++xylophone :: N -> Sig+xylophone = strk $ fromFs C.xylophone++spinelSphere :: N -> Sig+spinelSphere = strk $ fromFs C.spinelSphere++aluminumBar :: N -> Sig+aluminumBar = strk $ fromFs C.uniformAluminumBar++vibraphone1 :: N -> Sig+vibraphone1 = strk $ fromFs C.vibraphone1++vibraphone2 :: N -> Sig+vibraphone2 = strk $ fromFs C.vibraphone2++wineGlass :: N -> Sig+wineGlass = strk $ fromFs C.wineGlass++xing :: N -> Sig +xing = strk $ fromFs $ C.xing 3++-- Bells++bl :: SigSpace b => (a -> b) -> (a -> b)+bl = pick 4++amBell :: N -> Sig+amBell = bl $ fromAFs $ C.amBell++fmTubularBell :: N -> Sig+fmTubularBell = bl $ fromFs $ C.fmTubularBell++tubularBell :: N -> Sig+tubularBell = bl $ fromFs C.tubularBell++albertClockBellBelfast :: N -> Sig+albertClockBellBelfast = bl $ fromFs C.albertClockBellBelfast++--------------------------------------------------------------------+-- drums++dumb :: Dr -> SE Sig+dumb = fromDrum C.dumb++dumbBass :: Dr -> SE Sig+dumbBass = fromDrum C.dumbBass++pluckSnare :: Dr -> Sig+pluckSnare = fromDrum C.pluckSnare++knockSweep :: Dr -> SE Sig+knockSweep = fromDrum C.sortaKnockSweep++metalBoink :: Dr -> Sig+metalBoink = fromDrum C.metalBoink++snare :: Dr -> SE Sig+snare = fromDrum C.snare++openHihat :: Dr -> SE Sig+openHihat = fromDrum C.openHihat++closedHihat :: Dr -> SE Sig+closedHihat = fromDrum C.closedHihat++bassDrum :: D -> Dr -> Sig+bassDrum cps = fromDrum $ C.bassDrum cps++-- | Recommended values for frequency parameter @cpspch(13.03) - cpspch(13.10)@ +crash :: D -> Dr -> SE Sig+crash cps = fromDrum $ C.crash cps++handClap :: D -> Dr -> SE Sig+handClap cps = fromDrum $ C.handClap cps++-- models++fromModel :: (Sig -> D -> Sig) -> Dr -> Sig+fromModel f (amp, _) = f (sig amp) 0.01++fromModelD :: (D -> D -> Sig) -> Dr -> Sig+fromModelD f (amp, _) = f amp 0.01++bambooDr :: Dr -> Sig+bambooDr = fromModel bamboo ++guiroDr :: Dr -> Sig+guiroDr = fromModel guiro ++tambourineDr :: Dr -> Sig+tambourineDr = fromModel tambourine++cabasaDr :: Dr -> Sig+cabasaDr = fromModelD cabasa++crunchDr :: Dr -> Sig+crunchDr = fromModelD crunch++sleighbellsDr :: Dr -> Sig+sleighbellsDr = fromModel sleighbells++sekereDr :: Dr -> Sig+sekereDr = fromModelD sekere++sandpaperDr :: Dr -> Sig+sandpaperDr = fromModelD sandpaper+
temporal-csound.cabal view
@@ -2,9 +2,8 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: temporal-csound-version: 0.2.1-synopsis: brings together temporal-music-notation and csound-expression packages--- description: +version: 0.3.0+synopsis: library to make electronic music, brings together temporal-music-notation and csound-expression packages license: BSD3 license-file: LICENSE author: Anton Kholomiov@@ -14,6 +13,53 @@ build-type: Simple cabal-version: >=1.6 +description: + This package joins the forces of the packages temporal-music-notation + and csound-expression.+ The former package gives you handy primitives to arrange the events+ in sequences (like parallel or sequential composition, the tempo change,+ standard names for notes and durations) and the later is used for+ creation of musical timbres or software synthesizers. + .+ You can find the short intro in the module "Csound".+ .+ * The tutorial for csound-epression packageb (timbres):+ <https://github.com/anton-k/csound-expression/blob/master/tutorial/QuickStart.markdown> + .+ * The tutorial for temporal-music-notation package (composition)+ and temporal-music-notation-western package (standard names for notes): see module "Csound" + .+ This library defines standard note representation that let's you + invoke csound instruments with notes defined in the package temporal-music-notation.+ .+ Also this library provides you with some cool instruments to try the things out (see "Csound.Patch").+ .+ WARNING: the library works best within ghci. The real-time sound rendering function dac spawns+ a child process in the background which may continue to execute after you stop the main process that runs the programm.+ It's not so in vim but it happens in the Sublime Editor and when you invoke runhaskell. So the best+ is to write you program in the separate file and then load it in the ghci and invoke the function main (which+ runs the sound rendering with the function dac). + .+ Library strives to be very simple. For example, to trigger the instrument with virtual midi-device is+ as simple as (in ghci with loaded modules "Csound" and "Csound.Patch")+ .+ > Csound Csound.Patch> vdac $ mul 0.2 $ largeHall $ onMidi stringPad+ .+ If you have a connected hardware midi-device you can just type:+ .+ > Csound Csound.Patch> dac $ mul 0.2 $ largeHall $ onMidi stringPad+ .+ And you are ready to go. To play a C-major chord just do:+ .+ > Csound Csound.Patch> dac $ mul 0.2 $ magicCave $ mix $ notes vibraphone2 $ mel [c, e, g, high c, rest 15]+ .+ Here we send the output to speakers (dac or vdac), scale the signal to make it quiter (mul), + place the signal in some room with reverberation (largeHall or magicCave), listen to midi+ events (onMidi or onMidin for a midi on the given channel) or get the signal from scores (mix),+ trigger the csound instrument (stringPad or vibraphone2) on events (notes) and construct+ the events in sequence (mel). Events include notes (c, e, g - C major) and rests (rest).++ Extra-Source-Files : Homepage: https://github.com/anton-k/temporal-csound@@ -28,5 +74,10 @@ Hs-Source-Dirs: src/ exposed-modules: Csound+ Csound.Patch+ Csound.Converter -- other-modules: - build-depends: base >= 4, base < 5, temporal-music-notation>=0.4, csound-expression>=3.1.0 , temporal-media >= 0.4+ build-depends: + base >= 4, base < 5, temporal-music-notation>=0.4, + csound-expression>=3.2.1, csound-catalog>=0.1.1,+ temporal-media >= 0.4, temporal-music-notation-western>=0.4.0