-- | Data
module Csound.Opcode.Data (
-----------------------------------------------------
-- * Buffer and Function tables
{-
-- ** Writing To Tables
tableiw, tablew, tabw_i, tabw,
-}
-- ** Reading From Tables
table, tablei, table3, tab_i, tab,
-----------------------------------------------------
-- * Signal Input and Output, Sample and Loop Playback, Soundfonts
-- ** Signal Input And Output
inch, outch,
-- ** Sample Playback With Optional Looping
flooper2, sndloop,
-----------------------------------------------------
-- * File Input and Output
-- ** Sound File Input
soundin, diskin2, mp3in,
-- ** Sound File Queries
filelen, filesr, filenchnls, filepeak, filebit,
-- ** Sound File Output
fout,
-- ** Non-Soundfile Input And Output
-----------------------------------------------------
-- * Converters of Data Types
Nums,
-- ** Rate conversions
downsamp, upsamp, interp,
-- ** Amplitude conversions
ampdb, ampdbfs, dbamp, dbfsamp,
-- ** Pitch conversions
cent, cpsmidinn, cpsoct, cpspch, octave, octcps, octmidinn, octpch, pchmidinn, pchoct, semitone,
-- ** Integer and fractional parts
fracD, floorD, ceilD, intD, roundD,
fracSig, floorSig, ceilSig, intSig, roundSig,
-----------------------------------------------------
-- * Printing and Strings
-- ** Simple Printing
printi, printk,
-- ** Formatted Printing
-- ** String Variables
sprintf, sprintfk,
-- ** String Manipulation And Conversion
strcat, strcatk
) where
import Csound.Exp
import Csound.Exp.Wrapper
import Csound.LowLevel
import Csound.Exp.Numeric
-----------------------------------------------------
-- * Buffer and Function tables
{-
-- ** Writing To Tables
-- | This opcode operates on existing function tables, changing their contents. tablew is for writing
-- at k- or at a-rates, with the table number being specified at init time. Using tablew with i-rate signal
-- and index values is allowed, but the specified data will always be written to the function table at k-rate,
-- not during the initialization pass. The valid combinations of variable types are shown by the first letter of the variable names.
--
-- > tablew asig, andx, ifn [, ixmode] [, ixoff] [, iwgmode]
-- > tablew isig, indx, ifn [, ixmode] [, ixoff] [, iwgmode]
-- > tablew ksig, kndx, ifn [, ixmode] [, ixoff] [, iwgmode]
--
-- doc: <http://www.csounds.com/manual/html/tablew.html>
tablew :: Sig -> Sig -> Tab -> SE ()
tablew a1 a2 a3 = se_ $ opc3 "tablew" (map sign [a, k, i]) a1 a2 a3
where sign t = (x, t:t:is 4)
-- | This opcode operates on existing function tables, changing their contents. tableiw is
-- used when all inputs are init time variables or constants and you only want to run it at
-- the initialization of the instrument. The valid combinations of variable types are shown by the first letter of the variable names.
--
-- > tableiw isig, indx, ifn [, ixmode] [, ixoff] [, iwgmode]
--
-- doc: <http://www.csounds.com/manual/html/tableiw.html>
tableiw :: D -> D -> Tab -> SE ()
tableiw a1 a2 a3 = se_ $ opc3 "tableiw" [(i, is 6)] a1 a2 a3
-- | Fast table opcodes. Faster than table and tablew because don't allow wrap-around
-- and limit and don't check index validity. Have been implemented in order to provide
-- fast access to arrays. Support non-power of two tables (can be generated by any GEN function by giving a negative length value).
--
-- > tabw ksig, kndx, ifn [,ixmode]
-- > tabw asig, andx, ifn [,ixmode]
--
-- doc: <http://www.csounds.com/manual/html/tab.html>
tabw :: Sig -> Sig -> Tab -> SE ()
tabw a1 a2 a3 = se_ $ opc3 "tabw" (map sign [a, k]) a1 a2 a3
where sign t = (x, t:t:is 2)
-- | Fast table opcodes. Faster than table and tablew because don't allow wrap-around
-- and limit and don't check index validity. Have been implemented in order to provide
-- fast access to arrays. Support non-power of two tables (can be generated by any GEN function by giving a negative length value).
--
-- > tabw_i isig, indx, ifn [,ixmode]
--
-- doc: <http://www.csounds.com/manual/html/tab.html>
tabw_i :: D -> D -> Tab -> SE ()
tabw_i a1 a2 a3 = se_ $ opc3 "tabw_i" [(x, is 4)] a1 a2 a3
-}
-- ** Reading From Tables
-- | Accesses table values by direct indexing.
--
-- > ares table andx, ifn [, ixmode] [, ixoff] [, iwrap]
-- > ires table indx, ifn [, ixmode] [, ixoff] [, iwrap]
-- > kres table kndx, ifn [, ixmode] [, ixoff] [, iwrap]
--
-- doc: <http://www.csounds.com/manual/html/table.html>
table :: Sig -> Tab -> Sig
-- | Accesses table values by direct indexing with linear interpolation.
--
-- > ares tablei andx, ifn [, ixmode] [, ixoff] [, iwrap]
-- > ires tablei indx, ifn [, ixmode] [, ixoff] [, iwrap]
-- > kres tablei kndx, ifn [, ixmode] [, ixoff] [, iwrap]
--
-- doc: <http://www.csounds.com/manual/html/tablei.html>
tablei :: Sig -> Tab -> Sig
-- | Accesses table values by direct indexing with cubic interpolation.
--
-- > ares table3 andx, ifn [, ixmode] [, ixoff] [, iwrap]
-- > ires table3 indx, ifn [, ixmode] [, ixoff] [, iwrap]
-- > kres table3 kndx, ifn [, ixmode] [, ixoff] [, iwrap]
--
-- doc: <http://www.csounds.com/manual/html/table3.html>
table3 :: Sig -> Tab -> Sig
table = mkTable "table"
tablei = mkTable "tablei"
table3 = mkTable "table3"
mkTable :: Name -> Sig -> Tab -> Sig
mkTable name = opc2 name [
(a, a:rest),
(k, k:rest),
(i, i:rest)]
where rest = [i, i, i]
-- | Fast table opcodes. Faster than table and tablew because don't allow wrap-around
-- and limit and don't check index validity. Have been implemented in order to provide
-- fast access to arrays. Support non-power of two tables (can be generated by any GEN function by giving a negative length value).
--
-- > kr tab kndx, ifn[, ixmode]
-- > ar tab xndx, ifn[, ixmode]
--
-- doc: <http://www.csounds.com/manual/html/tab.html>
tab :: Sig -> Tab -> Sig
tab = opc2 "tab" [
(a, [x,i,i]),
(k, [k,i,i])]
-- | Fast table opcodes. Faster than table and tablew because don't allow wrap-around
-- and limit and don't check index validity. Have been implemented in order to provide
-- fast access to arrays. Support non-power of two tables (can be generated by any GEN function by giving a negative length value).
--
-- > ir tab_i indx, ifn[, ixmode]
--
-- doc: <http://www.csounds.com/manual/html/tab.html>
tab_i :: D -> Tab -> D
tab_i = opc2 "tab_i" [(i, [i,i,i])]
-- ** Saving Tables To Files
{-
-- ftsave "filename", iflag, ifn1 [, ifn2] [...]
ftsave :: S -> I -> [Tab] -> SE ()
ftsave a1 a2 a3 = opcs "ftsave" [(x, repeat i)] (phi a1 : phi a2 : map phi a3)
where phi :: Val a => a -> E
phi = Fix . unwrap
-- ftsavek "filename", ktrig, iflag, ifn1 [, ifn2] [...]
ftsavek :: S -> Sig -> I -> [Tab] -> SE ()
ftsavek a1 a2 a3 a4 = opcs "ftsavek" [(x, repeat i)] (phi a1 : phi a2 : phi a3 : map phi a4)
where phi :: Val a => a -> E
phi = Fix . unwrap
-}
-- ** Reading Tables From Files
-----------------------------------------------------
-- * Signal Input and Output, Sample and Loop Playback, Soundfonts
-- ** Signal Input And Output
-- | Reads from numbered channels in an external audio signal or stream.
--
-- > ain1[, ...] inch kchan1[,...]
--
-- doc: <http://www.csounds.com/manual/html/inch.html>
inch :: CsdTuple a => [Sig] -> a
inch = mopcs "inch" (repeat a, repeat k)
-- | Writes multi-channel audio data, with user-controllable channels, to an external device or stream.
--
-- > outch kchan1, asig1 [, kchan2] [, asig2] [...]
--
-- doc: <http://www.csounds.com/manual/html/outch.html>
outch :: [(Sig, Sig)] -> SE ()
outch ts = se_ $ opcs "outch" [(x, cycle [a,k])] $ (\(a, b) -> [a, b]) =<< ts
-- ** Sample Playback With Optional Looping
-- | This opcode implements a crossfading looper with variable loop parameters and three
-- looping modes, optionally using a table for its crossfade shape. It accepts non-power-of-two tables
-- for its source sounds, such as deferred-allocation GEN01 tables.
--
-- > asig flooper2 kamp, kpitch, kloopstart, kloopend, kcrossfade, ifn \
-- > [, istart, imode, ifenv, iskip]
--
-- doc: <http://www.csounds.com/manual/html/flooper2.html>
flooper2 :: Sig -> Sig -> Sig -> Sig -> Sig -> Tab -> Sig
flooper2 = opc6 "flooper2" [(a, ks 5 ++ is 5)]
-- | This opcode records input audio and plays it back in a loop with user-defined duration and
-- crossfade time. It also allows the pitch of the loop to be controlled, including reversed playback.
--
-- > asig, krec sndloop ain, kpitch, ktrig, idur, ifad
--
-- doc: <http://www.csounds.com/manual/html/sndloop.html>
sndloop :: Sig -> Sig -> Sig -> D -> D -> (Sig, Sig)
sndloop = mopc5 "sndloop" ([a, k], [a,k,k,i,i])
-- ** Soundfonts And Fluid Opcodes
-----------------------------------------------------
-- * File Input and Output
-- ** Sound File Input
-- | Reads audio data from an external device or stream. Up to 24 channels may be read before v5.14, extended to 40 in later versions.
--
-- > ar1[, ar2[, ar3[, ... a24]]] soundin ifilcod [, iskptim] [, iformat] \
-- > [, iskipinit] [, ibufsize]
--
-- doc: <http://www.csounds.com/manual/html/soundin.html>
soundin :: CsdTuple a => Str -> a
soundin = mopc1 "soundin" (repeat a, s:is 4)
-- | Reads audio data from a file, and can alter its pitch using one of several available interpolation
-- types, as well as convert the sample rate to match the orchestra sr setting. diskin2 can also read
-- multichannel files with any number of channels in the range 1 to 24 in versions before 5.14, and
-- 40 after. . diskin2 allows more control and higher sound quality than diskin, but there is also the disadvantage of higher CPU usage.
--
-- > a1[, a2[, ... aN]] diskin2 ifilcod, kpitch[, iskiptim \
-- > [, iwrap[, iformat [, iwsize[, ibufsize[, iskipinit]]]]]]
--
-- doc: <http://www.csounds.com/manual/html/diskin2.html>
diskin2 :: CsdTuple a => Str -> Sig -> a
diskin2 = mopc2 "diskin2" (repeat a, s:k:is 6)
-- | Reads stereo audio data from an external MP3 file.
--
-- > ar1, ar2 mp3in ifilcod[, iskptim, iformat, iskipinit, ibufsize]
--
-- doc: <http://www.csounds.com/manual/html/mp3in.html>
mp3in :: Str -> (Sig, Sig)
mp3in = mopc1 "mp3in" ([a,a], s:is 4)
-- ** Sound File Queries
-- | Returns the length of a sound file.
--
-- > ir filelen ifilcod, [iallowraw]
--
-- doc: <http://www.csounds.com/manual/html/filelen.html>
filelen :: Str -> D
filelen = opc1 "filelen" [(i, [i,i])]
-- | Returns the sample rate of a sound file.
--
-- > ir filesr ifilcod [, iallowraw]
--
-- doc: <http://www.csounds.com/manual/html/filesr.html>
filesr :: Str -> D
filesr = opc1 "filesr" [(i, [i,i])]
-- | Returns the number of channels in a sound file.
--
-- > ir filenchnls ifilcod [, iallowraw]
--
-- doc: <http://www.csounds.com/manual/html/filechnls.html>
filenchnls :: Str -> D
filenchnls = opc1 "filenchnls" [(i, [i,i])]
-- | Returns the peak absolute value of a sound file.
--
-- > ir filepeak ifilcod [, ichnl]
--
-- doc: <http://www.csounds.com/manual/html/filepeak.html>
filepeak :: Str -> D
filepeak = opc1 "filepeak" [(i, [i,i])]
-- | Returns the number of bits in each sample in a sound file.
--
-- > ir filebit ifilcod [, iallowraw]
--
-- doc: <http://www.csounds.com/manual/html/filebit.html>
filebit :: Str -> D
filebit = opc1 "filebit" [(i, [i,i])]
-- ** Sound File Output
-- | fout outputs N a-rate signals to a specified file of N channels.
--
-- > fout ifilename, iformat, aout1 [, aout2, aout3,...,aoutN]
--
-- doc: <http://www.csounds.com/manual/html/fout.html>
fout :: [Sig] -> SE ()
fout as = se_ $ opcs "fout" [(x, repeat a)] as
-- ** Non-Soundfile Input And Output
-----------------------------------------------------
-- * Converters of Data Types
-- | Modify a signal by down-sampling.
--
-- > kres downsamp asig [, iwlen]
--
-- doc: <http://www.csounds.com/manual/html/downsamp.html>
downsamp :: Sig -> Sig
downsamp = opc1 "downsamp" [(k, [a,i])]
-- | Modify a signal by up-sampling.
--
-- > ares upsamp ksig
--
-- doc: <http://www.csounds.com/manual/html/upsamp.html>
upsamp :: Sig -> Sig
upsamp = opc1 "upsamp" [(a, [k])]
-- | Converts a control signal to an audio signal using linear interpolation.
--
-- > ares interp ksig [, iskip] [, imode]
--
-- doc: <http://www.csounds.com/manual/html/interp.html>
interp :: Sig -> Sig
interp = opc1 "interp" [(a, [k,i,i])]
------------------------------------------------------------------------------------------
-- amplitude conversions
-- | Floating number types: 'Sig' or 'D'.
class Val a => Nums a where
isSig :: a -> Bool
instance Nums Sig where isSig = const True
instance Nums D where isSig = const False
conv :: Nums a => NumOp -> a -> a
conv op a = noRate $ ExpNum $ PreInline op [toPrimOr $ toE a]
convKr :: Nums a => NumOp -> a -> a
convKr op a = conv op $ phi a
where phi
| isSig a = setRate Kr
| otherwise = id
-- | Returns the amplitude equivalent of the decibel value x. Thus:
--
-- * 60 dB = 1000
--
-- * 66 dB = 1995.262
--
-- * 72 dB = 3891.07
--
-- * 78 dB = 7943.279
--
-- * 84 dB = 15848.926
--
-- * 90 dB = 31622.764
--
-- > ampdb(x) (no rate restriction)
--
-- doc: <http://www.csounds.com/manual/html/ampdb.html>
ampdb :: Nums a => a -> a
ampdb = conv Ampdb
-- | Returns the amplitude equivalent of the full scale decibel (dB FS) value x.
-- The logarithmic full scale decibel values will be converted to linear 16-bit signed integer values from −32,768 to +32,767.
--
-- > ampdbfs(x) (no rate restriction)
--
-- doc: <http://www.csounds.com/manual/html/ampdbfs.html>
ampdbfs :: Nums a => a -> a
ampdbfs = conv Ampdbfs
-- | Returns the decibel equivalent of the raw amplitude x.
--
-- > dbamp(x) (init-rate or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/dbamp.html>
dbamp :: Nums a => a -> a
dbamp = convKr Dbamp
-- | Returns the decibel equivalent of the raw amplitude x, relative to full scale amplitude. Full scale is assumed to be 16 bit. New is Csound version 4.10.
--
-- > dbfsamp(x) (init-rate or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/dbfsamp.html>
dbfsamp :: Nums a => a -> a
dbfsamp = convKr Dbfsamp
------------------------------------------------------------------------------------------
-- pitch conversions
-- | Calculates a factor to raise/lower a frequency by a given amount of cents.
--
-- > cent(x) (no rate restriction)
--
-- doc: <http://www.csounds.com/manual/html/cent.html>
cent :: Nums a => a -> a
cent = conv Cent
-- | Converts a Midi note number value to cycles-per-second.
--
-- > cpsmidinn (MidiNoteNumber) (init- or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/cpsmidinn.html>
cpsmidinn :: Nums a => a -> a
cpsmidinn = convKr Cpsmidinn
-- | Converts an octave-point-decimal value to cycles-per-second.
--
-- > cpsoct(oct) (no rate restriction)
--
-- doc: <http://www.csounds.com/manual/html/cpsoct.html>
cpsoct :: Nums a => a -> a
cpsoct = conv Cpsoct
-- | Converts a pitch-class value to cycles-per-second.
--
-- > cpspch (pch) (init- or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/cpspch.html>
cpspch :: Nums a => a -> a
cpspch = convKr Cpspch
-- | Calculates a factor to raise/lower a frequency by a given amount of octaves.
--
-- > octave(x) (no rate restriction)
--
-- doc: <http://www.csounds.com/manual/html/octave.html>
octave :: Nums a => a -> a
octave = conv Octave
-- | Converts a cycles-per-second value to octave-point-decimal.
--
-- > octcps (cps) (init- or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/octcps.html>
octcps :: Nums a => a -> a
octcps = convKr Octcps
-- | Converts a Midi note number value to octave-point-decimal.
--
-- > octmidinn (MidiNoteNumber) (init- or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/octmidinn.html>
octmidinn :: Nums a => a -> a
octmidinn = convKr Octmidinn
-- | Converts a pitch-class value to octave-point-decimal.
--
-- > octpch (pch) (init- or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/octpch.html>
octpch :: Nums a => a -> a
octpch = convKr Octpch
-- | Converts a Midi note number value to octave point pitch-class units.
--
-- > pchmidinn (MidiNoteNumber) (init- or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/pchmidinn.html>
pchmidinn :: Nums a => a -> a
pchmidinn = convKr Pchmidinn
-- | Converts an octave-point-decimal value to pitch-class.
--
-- > pchoct (oct) (init- or control-rate args only)
--
-- doc: <http://www.csounds.com/manual/html/pchoct.html>
pchoct :: Nums a => a -> a
pchoct = convKr Pchoct
-- | Calculates a factor to raise/lower a frequency by a given amount of semitones.
--
-- > semitone(x) (no rate restriction)
--
-- doc: <http://www.csounds.com/manual/html/semitone.html>
semitone :: Nums a => a -> a
semitone = conv Semitone
-----------------------------------------------------
-- * Printing and Strings
-- ** Simple Printing
-- | These units will print orchestra init-values.
--
-- > print iarg [, iarg1] [, iarg2] [...]
--
-- doc: <http://www.csounds.com/manual/html/print.html>
printi :: [D] -> SE ()
printi a1 = se_ $ opcs "print" [(x, repeat i)] a1
-- | Prints one k-rate value at specified intervals.
--
-- > printk itime, kval [, ispace]
--
-- doc: <http://www.csounds.com/manual/html/printk.html>
printk :: D -> Sig -> SE ()
printk a1 a2 = se_ $ opc2 "printk" [(x, [i,k,i])] a1 a2
-- ** Formatted Printing
-- ** String Variables
-- | sprintf write printf-style formatted output to a string variable, similarly to the C function sprintf(). sprintf runs at i-time only.
--
-- > Sdst sprintf Sfmt, xarg1[, xarg2[, ... ]]
--
-- doc: <http://www.csounds.com/manual/html/sprintf.html>
sprintf :: Str -> [D] -> Str
sprintf a1 a2 = opcs "sprintf" [(s, s:repeat i)] (toE a1 : map toE a2)
-- | sprintfk writes printf-style formatted output to a string variable, similarly to the C function sprintf(). sprintfk runs both at initialization and performance time.
--
-- > Sdst sprintfk Sfmt, xarg1[, xarg2[, ... ]]
--
-- doc: <http://www.csounds.com/manual/html/sprintfk.html>
sprintfk :: Str -> [Sig] -> Str
sprintfk a1 a2 = opcs "sprintfk" [(s, s:repeat k)] (toE a1 : map toE a2)
-- ** String Manipulation And Conversion
-- | Concatenate two strings and store the result in a variable. strcat runs at i-time only. It is allowed for any of the input arguments to be the same as the output variable.
--
-- > Sdst strcat Ssrc1, Ssrc2
--
-- doc: <http://www.csounds.com/manual/html/strcat.html>
strcat :: Str -> Str -> Str
strcat = opc2 "strcat" [(s, [s,s])]
-- | Concatenate two strings and store the result in a variable. strcatk does the
-- concatenation both at initialization and performance time. It is allowed for any of the input arguments to be the same as the output variable.
--
-- > Sdst strcatk Ssrc1, Ssrc2
--
-- doc: <http://www.csounds.com/manual/html/strcatk.html>
strcatk :: Str -> Str -> Str
strcatk = opc2 "strcatk" [(s, [s,s])]