Skip to content

Commit

Permalink
Merge pull request #182 from tidalcycles/0.9-dev
Browse files Browse the repository at this point in the history
0.9 dev
  • Loading branch information
yaxu authored Mar 9, 2017
2 parents a6dcda0 + 6c94c91 commit 409b4ed
Show file tree
Hide file tree
Showing 21 changed files with 1,528 additions and 281 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

Tidal [![Build Status](https://travis-ci.org/tidalcycles/Tidal.svg?branch=master)](https://travis-ci.org/tidalcycles/Tidal)
=====

Expand Down
34 changes: 34 additions & 0 deletions Sound/Tidal/Bjorklund.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module Sound.Tidal.Bjorklund (bjorklund) where

-- The below is (c) Rohan Drape, taken from the hmt library and
-- distributed here under the terms of the GNU Public Licence. Tidal
-- used to just include the library but removed for now due to
-- dependency problems.. We could however likely benefit from other
-- parts of the library..

type STEP a = ((Int,Int),([[a]],[[a]]))

left :: STEP a -> STEP a
left ((i,j),(xs,ys)) =
let (xs',xs'') = splitAt j xs
in ((j,i-j),(zipWith (++) xs' ys,xs''))

right :: STEP a -> STEP a
right ((i,j),(xs,ys)) =
let (ys',ys'') = splitAt i ys
in ((i,j-i),(zipWith (++) xs ys',ys''))

bjorklund' :: STEP a -> STEP a
bjorklund' (n,x) =
let (i,j) = n
in if min i j <= 1
then (n,x)
else bjorklund' (if i > j then left (n,x) else right (n,x))

bjorklund :: (Int,Int) -> [Bool]
bjorklund (i,j') =
let j = j' - i
x = replicate i [True]
y = replicate j [False]
(_,(x',y')) = bjorklund' ((i,j),(x,y))
in concat x' ++ concat y'
114 changes: 114 additions & 0 deletions Sound/Tidal/Chords.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
module Sound.Tidal.Chords where

import Sound.Tidal.Pattern
import Data.Maybe
import Control.Applicative

major :: [Int]
major = [0,4,7]
minor :: [Int]
minor = [0,3,7]
major7 :: [Int]
major7 = [0,4,7,11]
dom7 :: [Int]
dom7 = [0,4,7,10]
minor7 :: [Int]
minor7 = [0,3,7,10]
aug :: [Int]
aug = [0,4,8]
dim :: [Int]
dim = [0,3,6]
dim7 :: [Int]
dim7 = [0,3,6,9]
one :: [Int]
one = [0]
five :: [Int]
five = [0,7]
plus :: [Int]
plus = [0,4,8]
sharp5 :: [Int]
sharp5 = [0,4,8]
msharp5 :: [Int]
msharp5 = [0,3,8]
sus2 :: [Int]
sus2 = [0,2,7]
sus4 :: [Int]
sus4 = [0,5,7]
six :: [Int]
six = [0,4,7,9]
m6 :: [Int]
m6 = [0,3,7,9]
sevenSus2 :: [Int]
sevenSus2 = [0,2,7,10]
sevenSus4 :: [Int]
sevenSus4 = [0,5,7,10]
sevenFlat5 :: [Int]
sevenFlat5 = [0,4,6,10]
m7flat5 :: [Int]
m7flat5 = [0,3,6,10]
sevenSharp5 :: [Int]
sevenSharp5 = [0,4,8,10]
m7sharp5 :: [Int]
m7sharp5 = [0,3,8,10]
nine :: [Int]
nine = [0,4,7,10,14]
m9 :: [Int]
m9 = [0,3,7,10,14]
m7sharp9 :: [Int]
m7sharp9 = [0,3,7,10,14]
maj9 :: [Int]
maj9 = [0,4,7,11,14]
nineSus4 :: [Int]
nineSus4 = [0,5,7,10,14]
sixby9 :: [Int]
sixby9 = [0,4,7,9,14]
m6by9 :: [Int]
m6by9 = [0,3,9,7,14]
sevenFlat9 :: [Int]
sevenFlat9 = [0,4,7,10,13]
m7flat9 :: [Int]
m7flat9 = [0,3,7,10,13]
sevenFlat10 :: [Int]
sevenFlat10 = [0,4,7,10,15]
nineSharp5 :: [Int]
nineSharp5 = [0,1,13]
m9sharp5 :: [Int]
m9sharp5 = [0,1,14]
sevenSharp5flat9 :: [Int]
sevenSharp5flat9 = [0,4,8,10,13]
m7sharp5flat9 :: [Int]
m7sharp5flat9 = [0,3,8,10,13]
eleven :: [Int]
eleven = [0,4,7,10,14,17]
m11 :: [Int]
m11 = [0,3,7,10,14,17]
maj11 :: [Int]
maj11 = [0,4,7,11,14,17]
evelenSharp :: [Int]
evelenSharp = [0,4,7,10,14,18]
m11sharp :: [Int]
m11sharp = [0,3,7,10,14,18]
thirteen :: [Int]
thirteen = [0,4,7,10,14,17,21]
m13 :: [Int]
m13 = [0,3,7,10,14,17,21]

-- | @chordate cs m n@ selects the @n@th "chord" (a chord is a list of Ints)
-- from a list of chords @cs@ and transposes it by @m@
chordate :: Num b => [[b]] -> b -> Int -> [b]
chordate cs m n = map (+m) $ cs!!n

-- | @flatpat@ takes a Pattern of lists and pulls the list elements as
-- separate Events
flatpat :: Pattern [a] -> Pattern a
flatpat p = stack [unMaybe $ fmap (`maybeInd` i) p | i <- [0..9]]
where maybeInd xs i | i < length xs = Just $ xs!!i
| otherwise = Nothing
unMaybe = (fromJust <$>) . filterValues isJust

-- | @enchord chords pn pc@ turns every note in the note pattern @pn@ into
-- a chord, selecting from the chord lists @chords@ using the index pattern
-- @pc@. For example, @Chords.enchord [Chords.major Chords.minor] "c g" "0 1"@
-- will create a pattern of a C-major chord followed by a G-minor chord.
enchord :: Num a => [[a]] -> Pattern a -> Pattern Int -> Pattern a
enchord chords pn pc = flatpat $ (chordate chords) <$> pn <*> pc
2 changes: 2 additions & 0 deletions Sound/Tidal/Context.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ import Sound.Tidal.Time as C
import Sound.Tidal.SuperCollider as C
import Sound.Tidal.Params as C
import Sound.Tidal.Transition as C
import qualified Sound.Tidal.Scales as Scales
import qualified Sound.Tidal.Chords as Chords
56 changes: 44 additions & 12 deletions Sound/Tidal/Dirt.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import Data.Bits
import Data.Maybe
import Data.Fixed
import Data.Ratio
import System.Process

import Sound.Tidal.Stream
import Sound.Tidal.OscStream
Expand Down Expand Up @@ -58,7 +57,7 @@ dirt = Shape { params = [ s_p,
release_p
],
cpsStamp = True,
latency = 0.04
latency = 0.3
}

dirtSlang = OscSlang {
Expand Down Expand Up @@ -102,7 +101,7 @@ superDirtSetters getNow = do ds <- superDirtState 57120


superDirts :: [Int] -> IO [(ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())]
superDirts ports = do (_, getNow) <- bpsUtils
superDirts ports = do (_, getNow) <- cpsUtils
states <- mapM (superDirtState) ports
return $ map (\state -> (setter state, transition getNow state)) states

Expand All @@ -118,7 +117,7 @@ dirtstream _ = dirtStream

dirtToColour :: ParamPattern -> Pattern ColourD
dirtToColour p = s
where s = fmap (\x -> maybe black (maybe black datumToColour) (Map.lookup (param dirt "sound") x)) p
where s = fmap (\x -> maybe black (datumToColour) (Map.lookup (param dirt "s") x)) p

showToColour :: Show a => a -> ColourD
showToColour = stringToColour . show
Expand Down Expand Up @@ -198,10 +197,9 @@ striate' n f p = cat $ map (\x -> off (fromIntegral x) p) [0 .. n-1]
where off i p = p # begin (atom (slot * i) :: Pattern Double) # end (atom ((slot * i) + f) :: Pattern Double)
slot = (1 - f) / (fromIntegral n)

{- | _not sure what this does_, variant of `striate` -}
striateO :: ParamPattern -> Int -> Double -> ParamPattern
striateO p n o = cat $ map (\x -> off (fromIntegral x) p) [0 .. n-1]
where off i p = p # begin ((atom $ (fromIntegral i / fromIntegral n) + o) :: Pattern Double) # end ((atom $ (fromIntegral (i+1) / fromIntegral n) + o) :: Pattern Double)
{- | like `striate`, but with an offset to the begin and end values -}
striateO :: Int -> Double -> ParamPattern -> ParamPattern
striateO n o p = striate n p |+| begin (atom o :: Pattern Double) |+| end (atom o :: Pattern Double)

{- | Just like `striate`, but also loops each sample chunk a number of times specified in the second argument.
The primed version is just like `striate'`, where the loop count is the third argument. For example:
Expand All @@ -218,11 +216,36 @@ striateL' n f l p = striate' n f p # loop (atom $ fromIntegral l)

metronome = slow 2 $ sound (p "[odx, [hh]*8]")

{-|
Also degrades the current pattern and undegrades the next.
To change the number of cycles the transition takes, you can use @clutchIn@ like so:
@
d1 $ sound "bd(5,8)"
t1 (clutchIn 8) $ sound "[hh*4, odx(3,8)]"
@
will take 8 cycles for the transition.
-}
clutchIn :: Time -> Time -> [Pattern a] -> Pattern a
clutchIn _ _ [] = silence
clutchIn _ _ (p:[]) = p
clutchIn t now (p:p':_) = overlay (fadeOut' now t p') (fadeIn' now t p)

{-|
Degrades the current pattern while undegrading the next.
This is like @xfade@ but not by gain of samples but by randomly removing events from the current pattern and slowly adding back in missing events from the next one.
@
d1 $ sound "bd(3,8)"
t1 clutch $ sound "[hh*4, odx(3,8)]"
@
@clutch@ takes two cycles for the transition, essentially this is @clutchIn 2@.
-}
clutch :: Time -> [Pattern a] -> Pattern a
clutch = clutchIn 2

Expand All @@ -241,7 +264,7 @@ xfadeIn _ _ [] = silence
xfadeIn _ _ (p:[]) = p
xfadeIn t now (p:p':_) = overlay (p |*| gain (now ~> (slow t envEqR))) (p' |*| gain (now ~> (slow t (envEq))))

{- |
{- |
Crossfade between old and new pattern over the next two cycles.
@
Expand All @@ -255,15 +278,15 @@ t1 xfade $ sound "can*3"
xfade :: Time -> [ParamPattern] -> ParamPattern
xfade = xfadeIn 2

{- | Stut applies a type of delay to a pattern. It has three parameters,
{- | Stut applies a type of delay to a pattern. It has three parameters,
which could be called depth, feedback and time. Depth is an integer
and the others floating point. This adds a bit of echo:
@
d1 $ stut 4 0.5 0.2 $ sound "bd sn"
@
The above results in 4 echos, each one 50% quieter than the last,
The above results in 4 echos, each one 50% quieter than the last,
with 1/5th of a cycle between them. It is possible to reverse the echo:
@
Expand All @@ -275,7 +298,13 @@ stut steps feedback time p = stack (p:(map (\x -> (((x%steps)*time) ~> (p |*| ga
where scale x
= ((+feedback) . (*(1-feedback)) . (/(fromIntegral steps)) . ((fromIntegral steps)-)) x

{- | _not sure what this does_, variant of `stut`
{- | Instead of just decreasing volume to produce echoes, @stut'@ allows to apply a function for each step and overlays the result delayed by the given time.
@
d1 $ stut' 2 (1%3) (# vowel "{a e i o u}%2") $ sound "bd sn"
@
In this case there are two _overlays_ delayed by 1/3 of a cycle, where each has the @vowel@ filter applied.
-}
stut' :: Integer -> Time -> (ParamPattern -> ParamPattern) -> ParamPattern -> ParamPattern
stut' steps steptime f p | steps <= 0 = p
Expand All @@ -297,3 +326,6 @@ Build up some tension, culminating in a _drop_ to the new pattern after 8 cycles
-}
anticipate :: Time -> [ParamPattern] -> ParamPattern
anticipate = anticipateIn 8

{- | Copies the @n@ parameter to the @orbit@ parameter, so different sound variants or notes go to different orbits in SuperDirt. -}
nToOrbit = copyParam n_p orbit_p
54 changes: 37 additions & 17 deletions Sound/Tidal/OscStream.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,32 @@ data OscSlang = OscSlang {path :: String,
preamble :: [Datum]
}

type OscMap = Map.Map Param (Maybe Datum)
type OscMap = Map.Map Param Datum

toOscDatum :: Value -> Maybe Datum
toOscDatum (VF x) = Just $ float x
toOscDatum (VI x) = Just $ int32 x
toOscDatum (VS x) = Just $ string x
toOscDatum :: Value -> Datum
toOscDatum (VF x) = float x
toOscDatum (VI x) = int32 x
toOscDatum (VS x) = string x

toOscMap :: ParamMap -> OscMap
toOscMap m = Map.map (toOscDatum) (Map.mapMaybe (id) m)
toOscMap m = Map.map (toOscDatum) m

-- constructs and sends an Osc Message according to the given slang
-- and other params - this is essentially the same as the former
-- toMessage in Stream.hs
send s slang shape change tick (o, m) = osc

send
:: (Integral a) =>
UDP
-> OscSlang
-> Shape
-> Tempo
-> a
-> (Double,
Double,
OscMap)
-> IO ()
send s slang shape change tick (on, off, m) = osc
where
osc | timestamp slang == BundleStamp =
sendOSC s $ Bundle (ut_to_ntpr logicalOnset) [Message (path slang) oscdata]
Expand All @@ -41,18 +53,26 @@ send s slang shape change tick (o, m) = osc
| otherwise =
doAt logicalOnset $ sendOSC s $ Message (path slang) oscdata
oscPreamble = cpsPrefix ++ preamble slang
oscdata | namedParams slang = oscPreamble ++ (concatMap (\(k, Just v) -> [string (name k), v] )
$ filter (isJust . snd) $ Map.assocs m)
| otherwise = oscPreamble ++ (catMaybes $ mapMaybe (\x -> Map.lookup x m) (params shape))
cpsPrefix | cpsStamp shape && namedParams slang = [string "cps", float (cps change)]
oscdata | namedParams slang = oscPreamble ++ (concatMap (\(k, v) -> [string (name k), v] )
$ Map.assocs m)
| otherwise = oscPreamble ++ (catMaybes $ map (\x -> Map.lookup x m) (params shape))
cpsPrefix | cpsStamp shape && namedParams slang = [string "cps",
float (cps change),
string "delta",
float (logicalOffset
- logicalOnset),
string "cycle", float cycle
]
| cpsStamp shape = [float (cps change)]
| otherwise = []
parameterise ds = mergelists (map (string . name) (params shape)) ds
cycle = (on + fromIntegral tick) / (fromIntegral ticksPerCycle)
_parameterise ds = mergelists (map (string . name) (params shape)) ds
usec = floor $ 1000000 * (logicalOnset - (fromIntegral sec))
sec = floor logicalOnset
logicalOnset = logicalOnset' change tick o ((latency shape) + nudge)
nudge = maybe 0 (toF) (Map.lookup nudge_p m)
toF (Just (Float f)) = float2Double f
logicalOnset = logicalOnset' change tick on ((latency shape) + nudge)
logicalOffset = logicalOnset' change tick off ((latency shape) + nudge)
nudge = maybe 0 (toF) (Map.lookup nudge_p (m :: OscMap))
toF (Float f) = float2Double f
toF _ = 0

-- type OscMap = Map.Map Param (Maybe Datum)
Expand All @@ -62,10 +82,10 @@ send s slang shape change tick (o, m) = osc
makeConnection :: String -> Int -> OscSlang -> IO (ToMessageFunc)
makeConnection address port slang = do
s <- openUDP address port
return (\ shape change tick (o,m) -> do
return (\ shape change tick (on,off,m) -> do
let m' = if (namedParams slang) then (Just m) else (applyShape' shape m)
-- this might result in Nothing, make sure we do this first
m'' <- fmap (toOscMap) m'
-- to allow us to simplify `send` (no `do`)
return $ send s slang shape change tick (o,m'')
return $ send s slang shape change tick (on,off,m'')
)
Loading

0 comments on commit 409b4ed

Please sign in to comment.