-- | Basic types and functions.
--
-- WARNING (for Csound users): the maximum amplitude is 1.0. There is no way to alter it.
-- don't define your amplitudes with 9000 or 11000. But the good news are: all signals
-- are clipped by 1 so that you can not damage your ears and your speakers by a little typo.
module Csound.Base(
-- * Introduction to Csound for Haskell users
-- | We are going to make electronic music. But what is Csound? And why should we use it?
--
-- Csound is a domain specific programming language. It helps you to define synthesizers and make some music with them (<http://www.csounds.com>).
-- Csound was born in 1985 (a bit older than Haskell) at MIT by Barry Vercoe. It's widely used in the academia.
-- It has a long history. So with Csound we get a lot of music dsp-algorithms ready to be used. It's written in C.
-- So it's very efficient. It's driven by text, so we can generate it. Csound's community is very friendly (what a coincidence!).
-- Csound is very well documented.
--
-- ** Making music with Csound
-- | You don't need to know Csound to use this library.
-- but it's helpful to know the main features of the Csound: how can you create music with Csound in general,
-- what design choices were made, basic features and quirks. Csound belongs to the MUSIC N family
-- of programming languages. What does it mean? It means that music is divided in two parts:
--
-- 1. Orchestra. User defines instruments
--
-- 2. Scores. User triggers instruments with a list of notes
--
-- Ab instrument is something that listens to notes and converts them to signals.
-- Note is a tuple: (instrument name, start time, duration, parameters). Parameters cell is
-- a tuple of primitive types: numbers ('Csound.Base.D'), strings ('Csound.Base.Str') and tables or arrays of numbers ("Csound.Tab").
--
-- Scores are very simple yet powerful. Csound handles polyphony for you. If you trigger
-- several notes at the same time on the same instrument you get three instances of the same
-- instrument running in parallel. It's very cool feature (not so easy thing to do with Pd).
--
-- But main strength lies in the Orchestra section. Here you can define the timbres for
-- your musical journey. Csound is mostly for making strange sounds. How you can do it?
-- You do it with instruments. An instrument is a sequence of statements that define a flow-graph
-- for your sound waves. In instrument you can use predefined sound generators and transformers ("Csound.Opcode" and "Csound.Air").
--
-- Score/Orchestra division stays in this library too. You define your instruments of the type
--
-- > (Arg a, Out b) => a -> b
--
-- An instrument is something that converts arguments-like things (tuple of primitive values) to output-like things (list of signals).
--
-- Later when you are done with orchestra section you can trigger the instruments with the function 'Csound.Base.score'
--
-- > score :: (Arg a, Out b) => (a -> b) -> [(Double, Double, a)] -> SigOut
--
-- It takes an instrument and the list of notes for this instrument. I've said that in Csound note contains
-- four elements. But here it has only three because we define all notes at the time for one instrument.
-- No need to label instrument with names explicitly. arguments-like thing is something that can be converted
-- to the tuple of primitive values. There are a lot of predefined instances.
--
-- This library doesn't help you with score section that much. Scores are the same as you would write them with Csound.
-- It's a list of events. Haskell can help you with powerful functions for lists but it's not so convenient as it
-- can be. It's so on purpose. Csound-expression stays clear from score-generation libraries. But you can use
-- your favourite library to create complex scores. You can use temporal-music-notation or Haskore or Euterpea.
-- Any library that can generate the list of events will do.
--
-- ** Flags and options
-- | Music is defined in two parts. They are Orchestra and Scores. But there is a third one. It's used
-- to set the global settings like sample rate or control rate values (block size). In this library you
-- can set the initial values with 'Csound.Base.CsdOptions'.
-- ** Features and quirks
-- *** Audio and control rates
-- | Csound has made a revolution in electronic music technology. It introduced two types of signals.
-- They are audio rate and control rate signals. The audio rate signals is what we hear and control rate
-- signals is what changes the parameters of sound. Control rate is smaller then audio rate. It speeds
-- up performance dramatically. Let's look at one of the sound units (they are called opcodes)
--
-- > ares buthp asig, kfreq [, iskip]
--
-- It's a butterworth high pass filter as it defined in the Csound. a-sig - means sig at audio rate.
-- k-freq means freq at control rate (for historical reasons it is k not c). iskip means skip at i-rate.
-- i-rate means init time rate. It is when an instruments instance is initialized to play a note. i-rate
-- values stays the same for the whole note. So we can see that signal is filtered at audio rate but
-- the center frequency of the filter changes at the control rate. In this library I've merged the
-- two types together ('Csound.Base.Sig'). If you plug a signal into kfreq we can infer that you want this
-- signal to be control rate. In Csound some opcodes exist go in pairs. One that produces audio signals
-- and one that produces control rate signals. By default if there is no constraint for the signal it is rendered
-- at the audio rate except for those units that produce sound envelopes (like 'Csound.Opcode.Basic.linseg').
--
-- You can change this behaviour with functions 'Csound.Base.ar' and 'Csound.Base.kr'. They set the signal-like things to
-- audio or control rate. For instance if you want your envelope to run
-- at control rate, write:
--
-- > env = ar $ linseg [0, idur/2, 1, idur/2, 0]
--
-- Constants are converted to signals with them also.
-- *** Table size
-- | For speed table size should be the power of two or power of two plus one (all tables for oscillators).
-- In this library you can specify the relative size (see 'Csound.Base.Adoptions').
-- I've tried to hide the size definition to make sings easier.
-- ** How to read the Csound docs
-- | I'm to lazy to rewrite the Csound docs for all opcodes so you'd better get acquainted with Csound docs.
-- Docs are very good. How to read them? For instance you want to use an oscillator with cubic interpolation
-- so you dig into the "Csound.Opcode.Basic" and find the function:
--
-- > oscil3 :: Sig -> Sig -> Tab -> Sig
--
-- From Hackage we can guess that it takes two signals and table and returns a signal. It's a clue but a vogue one.
-- Let's read along, in the docs you can see a short description (taken from Csound docs):
--
-- > oscil3 reads table ifn sequentially and repeatedly at a frequency xcps.
-- > The amplitude is scaled by xamp. Cubic interpolation is applied for table look up from internal phase values.
--
-- and here is the Csound types (the most useful part of it)
--
-- > ares oscil3 xamp, xcps, ifn [, iphs]
-- > kres oscil3 kamp, kcps, ifn [, iphs]
--
-- We see a two versions of the opcode. For audio and control rate signals. By default first is rendered
-- if we don't plug it in something that expects control rates. It's all about rates, but what can we find out
-- about the arguments?
--
-- First letter signifies the type of the argument and the rest is the name. We can see that first signal is amp with x rate.
-- and the second one is cps with x rate. We can guess that amp is the amplitude and cps is cycles per second. This unit
-- reads the table with given amplitude (it is a signal) and frequency (it is a signal too). Or we can just read about it
-- in the docs if we follow the link that comes at the very last line in the comments:
--
-- * doc: <http://www.csounds.com/manual/html/oscil3.html>
--
-- I've said about a-, k- and i-rates. But what is the x-rate? Is it about X-files or something? X means a-rate or k-rate.
-- You can use both of them for this argument. Let's go through all types that you can find:
--
-- * asig -- audio rate ('Csound.Base.Sig')
--
-- * ksig -- control rate ('Csound.Base.Sig')
--
-- * xsig -- audio or control rate ('Csound.Base.Sig')
--
-- * inum -- constant number ('Csound.Base.D')
--
-- * ifn -- table ('Csound.Tab.Tab'). They are called functional tables in Csound.
--
-- * Sfile -- string, probably a file name ('Csound.Base.Str')
--
-- * fsrc -- spectrum ('Csound.Base.Spec'). Yes, you can mess with sound in the space domain.
--
-- Often you will see the auxiliary arguments, user can skip them in Csound. So we can do it in Haskell too.
-- But what if we want to supply them? We can use the function 'Csound.Base.withInits' for this purpose.
-- ** Example (a concert A)
-- |
-- > module Main where
-- >
-- > -- imports everything
-- > import Csound.Base
-- >
-- > -- Let's define a simple sound unit that
-- > -- reads in cycles the table that contains a single sine partial.
-- > -- oscil1 is the standard oscillator with linear interpolation.
-- > -- 1 - means the amplitude, cps - is cycles per second and the last argument
-- > -- is the table that we want to read.
-- > myOsc :: Sig -> Sig
-- > myOsc cps = oscili 1 cps (sines [1])
-- >
-- > -- Let's define a simple instrument that plays a sound on the specified frequency.
-- > -- We use kr to convert a constant value to signal and then plug it in the osc unit.
-- > -- We make it a bit quieter by multiplying with 0.5.
-- > pureTone :: D -> Sig
-- > pureTone cps = 0.5 * (myOsc $ kr cps)
-- >
-- > -- Let's trigger the instrument from the score section.
-- > -- It plays a single note that starts at 0 and lasts for 1 second and
-- > -- triggers the instrument 'instr' with frequency of 440 (Hz).
-- > res = score pureTone [(0, 1, 440)]
-- >
-- > -- Renders generated csd-file to the "tmp.csd".
-- > main :: IO ()
-- > main = writeFile "tmp.csd" $ renderCsd [res]
--
-- Now you can invoke Csound on tmp.csd and listen to the result with your favourite player.
--
-- > csound tmp.csd -o a.wav
--
-- That's it @csound@ is a separate program that we have to run to compile our csd-files to sounds.
-- We can listen to the sound as it runs. It can be configured with flags.
-- ** References
-- | Got interested in Csound? Csound is very well documented. There are good tutorials, read about it at:
--
-- * Reference manual: <http://www.csounds.com/manual/html/index.html >
--
-- * Floss tutorials: <http://en.flossmanuals.net/csound/>
--
-- * Amsterdam Csound catalog: <http://www.music.buffalo.edu/hiller/accci/>
--
-- * Lots of wonderful real-time examples by Iain McCurdy: <http://iainmccurdy.org/csound.html>
--
-- * Outdated but short manual on Csound <http://cara.gsu.edu/courses/csound_users_seminar/csound/3.46/CsIntro.html>
-- * Types
Val,
-- ** Constants
-- | A constant value doesn't change while instrument is playing a note.
-- Only constants can be passed as arguments to the instruments.
D, Str,
withInits,
-- ** Tables
-- | In Csound tables can be treated as primitive values. They can be passed to instruments in the score events.
-- There are limited set of functions which you can use to make new tables. Look at the following module for details:
module Csound.Tab,
-- ** Signals
-- | Signals can be audio or control rate. Rate is derived from the code.
-- If there are rate-collisions, values will be converted to the right rates.
-- For example, if you are trying to apply an opcode that expects control
-- rate signal to some audio rate signal, the signal will be downsampled behind the scenes.
Sig, Spec,
-- ** Booleans
-- | Use functions from the module "Data.Boolean" to make boolean expressions.
BoolSig, BoolD,
module Data.Boolean,
-- ** Side effects
SE,
-- ** Tuples
CsdTuple,
-- ** Converters
ToSig(..), ir, double, str,
-- * Making a sound
-- | Let's make some noise. Sound is build from list of tracks ('SigOut').
Out, SigOut, effect,
-- ** Handy short-cuts
Outs, Sig2, Sig3, Sig4,
-- ** Scores
-- | We can define an instrument and tell it to play some notes.
score, Arg(..), ArgMethods, makeArgMethods,
-- ** Midi
-- | We can define a midi-instrument. Then we can trigger the instrument with a midi-keyboard.
Msg, massign, pgmassign,
-- ** Rendering
-- | Now we are ready to create a csound-file. The function 'renderCsd' creates a 'String' that
-- contains the description of our music. We can save it to a file and compile it with our @csound@
-- wizard.
renderCsd,
-- ** Opcodes
-- | Some colors to paint our soundscapes.
module Csound.Opcode,
-- ** Patterns
-- | Frequently used combinations of opcodes.
module Csound.Air,
-- ** Options
-- | We can set some csound options.
renderCsdBy,
Channel, CtrlId, CsdOptions(..), module Data.Default, mixing, mixingBy
) where
import Data.Default
import Data.Boolean
import Csound.Air
import Csound.Exp
import Csound.Exp.Cons
import Csound.Exp.Wrapper
import Csound.Tab
import Csound.Opcode
import Csound.Exp.Numeric
import Csound.Exp.Logic
import Csound.Render.Sco
import Csound.Render.Options
import Csound.Render