summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--csound-expression-typed.cabal26
-rw-r--r--data/opcodes/AmbiRow.udo68
-rw-r--r--data/opcodes/AmbiRowMp3.udo68
-rw-r--r--data/opcodes/LiveRow.udo215
-rw-r--r--data/opcodes/LiveRows.udo226
-rw-r--r--src/Csound/Typed/GlobalState/Elements.hs18
-rw-r--r--src/Csound/Typed/Plugins.hs8
-rw-r--r--src/Csound/Typed/Plugins/AmbiRow.hs25
-rw-r--r--src/Csound/Typed/Plugins/LiveRow.hs25
-rw-r--r--src/Csound/Typed/Plugins/ZeroDelayConvolution.hs4
10 files changed, 677 insertions, 6 deletions
diff --git a/csound-expression-typed.cabal b/csound-expression-typed.cabal
index a5a64bc..e521c30 100644
--- a/csound-expression-typed.cabal
+++ b/csound-expression-typed.cabal
@@ -1,5 +1,5 @@
Name: csound-expression-typed
-Version: 0.2.2.0
+Version: 0.2.3.1
Cabal-Version: >= 1.22
License: BSD3
License-file: LICENSE
@@ -35,6 +35,10 @@ Data-Files :
data/opcodes/korg35.udo
data/opcodes/zero-delay-convolution.udo
data/opcodes/PitchShifterDelay.udo
+ data/opcodes/AmbiRow.udo
+ data/opcodes/AmbiRowMp3.udo
+ data/opcodes/LiveRow.udo
+ data/opcodes/LiveRows.udo
data/opcodes/MultiFX/AnalogDelay.udo
data/opcodes/MultiFX/Distortion.udo
data/opcodes/MultiFX/EnvelopeFollower.udo
@@ -63,8 +67,22 @@ Source-repository head
Library
Ghc-Options: -Wall
Build-Depends:
- base >= 4, base < 5, ghc-prim, containers, transformers >= 0.3, Boolean >= 0.1.0, colour >= 2.0, data-default, deepseq, NumInstances, filepath, directory,
- wl-pprint >= 1.2.1, csound-expression-dynamic >= 0.3.3, temporal-media >= 0.6.3, hashable
+ base >= 4.6,
+ base < 5,
+ ghc-prim,
+ containers,
+ transformers >= 0.3,
+ Boolean >= 0.1.0,
+ colour >= 2.0,
+ data-default,
+ deepseq,
+ NumInstances,
+ filepath,
+ directory,
+ wl-pprint >= 1.2.1,
+ csound-expression-dynamic >= 0.3.5,
+ temporal-media >= 0.6.3,
+ hashable
Hs-Source-Dirs: src/
Exposed-Modules:
Csound.Typed
@@ -137,6 +155,8 @@ Library
Csound.Typed.Plugins.SolinaChorus
Csound.Typed.Plugins.ZeroDelayConvolution
Csound.Typed.Plugins.Iain
+ Csound.Typed.Plugins.AmbiRow
+ Csound.Typed.Plugins.LiveRow
Csound.Typed.Plugins.Utilities
Paths_csound_expression_typed
diff --git a/data/opcodes/AmbiRow.udo b/data/opcodes/AmbiRow.udo
new file mode 100644
index 0000000..920193e
--- /dev/null
+++ b/data/opcodes/AmbiRow.udo
@@ -0,0 +1,68 @@
+; plays wav-files in row
+;
+; > al, ar AmbiRow Sfiles, kSpeed, kUserIndex, iFadeTime
+opcode AmbiRow, aa, S[]kki
+
+Sfiles[], kSpeed, kUserIndex, iFadeTime xin
+kNext init 0
+iSize lenarray Sfiles
+
+kEnvPoints init 0
+
+kenv linseg 0, iFadeTime, 1, 1, 1
+kUserIndex = floor(kUserIndex)
+aLeft init 0
+aRight init 0
+
+kTrig changed kUserIndex
+kTrigChange delayk kTrig, iFadeTime
+kLoad init 1
+kTrigChange = kTrigChange + kLoad
+
+kSkipFirst linseg 1, 0.1, 1, 0.1, 0, iFadeTime + 0.1, 0, 0.1, 1
+kTrigChange = kTrigChange * kSkipFirst
+
+if (kTrig == 1) && (kNext != kUserIndex) then
+ ;printks "Fade out: %d\n", 0.001, kUserIndex
+ kNext = kUserIndex
+ kEnvPoints = 0
+ ; timout 0, iFadeTime, fade_out
+ ;reinit fade_out
+endif
+
+if kTrigChange == 1 then
+ ;printks "Change: %d\n", 0.001, kUserIndex
+ kEnvPoints = 1
+ reinit load_file
+ kLoad = 0
+endif
+
+kEnv2 portk kEnvPoints, iFadeTime * 0.5
+
+xout kEnv2 * aLeft, kEnv2 * aRight
+
+fade_out:
+ ;prints "Do fade\n", 0.001
+ kenv linseg 1, iFadeTime, 0, 1, 0
+ ; rireturn
+
+load_file:
+ kenv linseg 0, iFadeTime, 1, 1, 1
+ ;prints "Do load: %d\n", 0.001, kNext
+ iIndex = i(kNext)
+ if (iIndex >= 0) && (iIndex < iSize) then
+ Sfile = Sfiles[iIndex]
+ iStop = 0
+ else
+ iStop = 1
+ endif
+
+ if iStop == 0 then
+ aLeft, aRight diskin2 Sfile, kSpeed
+ else
+ aLeft = 0
+ aRight = 0
+ endif
+ rireturn
+
+endop \ No newline at end of file
diff --git a/data/opcodes/AmbiRowMp3.udo b/data/opcodes/AmbiRowMp3.udo
new file mode 100644
index 0000000..1b602a9
--- /dev/null
+++ b/data/opcodes/AmbiRowMp3.udo
@@ -0,0 +1,68 @@
+; plays mp3-files in row
+;
+; > al, ar AmbiRowMp3 Sfiles, kUserIndex, iFadeTime
+opcode AmbiRowMp3, aa, S[]ki
+
+Sfiles[], kUserIndex, iFadeTime xin
+kNext init 0
+iSize lenarray Sfiles
+
+kEnvPoints init 0
+
+kenv linseg 0, iFadeTime, 1, 1, 1
+kUserIndex = floor(kUserIndex)
+aLeft init 0
+aRight init 0
+
+kTrig changed kUserIndex
+kTrigChange delayk kTrig, iFadeTime
+kLoad init 1
+kTrigChange = kTrigChange + kLoad
+
+kSkipFirst linseg 1, 0.1, 1, 0.1, 0, iFadeTime + 0.1, 0, 0.1, 1
+kTrigChange = kTrigChange * kSkipFirst
+
+if (kTrig == 1) && (kNext != kUserIndex) then
+ ;printks "Fade out: %d\n", 0.001, kUserIndex
+ kNext = kUserIndex
+ kEnvPoints = 0
+ ; timout 0, iFadeTime, fade_out
+ ;reinit fade_out
+endif
+
+if kTrigChange == 1 then
+ ;printks "Change: %d\n", 0.001, kUserIndex
+ kEnvPoints = 1
+ reinit load_file
+ kLoad = 0
+endif
+
+kEnv2 portk kEnvPoints, iFadeTime * 0.5
+
+xout kEnv2 * aLeft, kEnv2 * aRight
+
+fade_out:
+ ;prints "Do fade\n", 0.001
+ kenv linseg 1, iFadeTime, 0, 1, 0
+ ; rireturn
+
+load_file:
+ kenv linseg 0, iFadeTime, 1, 1, 1
+ ;prints "Do load: %d\n", 0.001, kNext
+ iIndex = i(kNext)
+ if (iIndex >= 0) && (iIndex < iSize) then
+ Sfile = Sfiles[iIndex]
+ iStop = 0
+ else
+ iStop = 1
+ endif
+
+ if iStop == 0 then
+ aLeft, aRight mp3in Sfile
+ else
+ aLeft = 0
+ aRight = 0
+ endif
+ rireturn
+
+endop
diff --git a/data/opcodes/LiveRow.udo b/data/opcodes/LiveRow.udo
new file mode 100644
index 0000000..d5fe81b
--- /dev/null
+++ b/data/opcodes/LiveRow.udo
@@ -0,0 +1,215 @@
+; Anton Kholomiov, 2019
+
+;
+; UDO to play row of toggle clip like in Ableton Live
+;
+; Mono version. Toggle of audio clips syncronised with BPM.
+;
+; > aOut liveRow iTabSize, iTabs, iBpm, iBeatDur, kUserIndex, iAuxParams
+;
+; * iTabSize - how many audio clips in the row
+; * iTabs - table that contains indices to tables with monophonic audio clips (loaded with GEN01)
+; * iBpm - BPM of the track
+; * iBeatDur - duration of the bar relative to quaters. So 4 - means 4/4, 3 means 3/4, 3.5 means 7/8 etc.
+; * kUserIndex - index of the played clip, if it's out of bounds silence is played back.
+;
+; The clip switch happens only in even iBeatDur times. So that it's always in sync.
+; It's supposed that audio clips are monophonic and aligned with specified tempo.
+; So no automatic rescaling is done.
+;
+; Basic functionality is to switch the clips. But there are also aux-params that
+; can control the length and spacing of playback.
+;
+; The aux-params are packed into single table. It's last parameter and we can omit it.
+; The params follow by packets of 6 digits per audio-clip in the row.
+;
+; We can create the aux-param table with GEN02 like this
+;
+; > ; Aux params Size Del Tail AutoSwitch NeedRetrig Volume
+; > f201 0 10 -2 1 0 1 -1 1 1
+; 1 0 0 -1 0 1
+;
+; in the example above we can see two 5-packets sets for two audio clips.
+;
+; There are params:
+; * Size (Int) - the size of the audio in bars
+; * Delay (Int) - how many bars to skip on clip start
+; * Tail delay (Int) - how many empty bara to play at the end of the clip
+; * AutoSwitch (Int) - what audio-clip to switch when the current is over
+; if it equals to -1 than we continue to play the current clip.
+; * NeedRetrig - if we switch the clips we can continue to play from where we left out (default behaviour)
+; or we can start from beginning on switch (if NeedRetrig equals 1).
+; * Volume scale per audio-clip
+;
+opcode liveRow, a, iiiikjj
+iTabSize, iTabs, iBpm, iBeatDur, kUserIndex, iAuxParams, isDebugPrint xin
+kUserIndex = floor(kUserIndex)
+
+iDur = iBeatDur / (iBpm / 60)
+
+ii = 0
+; iTabSize = ftlen(iTabs)
+itTotalSteps[] init iTabSize
+itTotalDurs[] init iTabSize
+itTrans[] init iTabSize
+itDels[] init iTabSize
+itTailDels[] init iTabSize
+itRetrig[] init iTabSize
+itClipVolume[] init iTabSize
+while ii < iTabSize do
+ iTab tab_i ii, iTabs
+ itCurrentFileSteps = floor((ftlen(iTab) / ftsr(iTab)) / iDur)
+
+ if (iAuxParams < 0) then
+ itTotalSteps[ii] = itCurrentFileSteps
+ else
+ itUserTotalSteps tab_i (ii * 6), iAuxParams
+ if (itUserTotalSteps > 0) then
+ itTotalSteps[ii] = itUserTotalSteps
+ else
+ itTotalSteps[ii] = itCurrentFileSteps
+ endif
+ endif
+
+ itTotalDurs[ii] = itTotalSteps[ii] * iDur * itCurrentFileSteps / itTotalSteps[ii]
+
+ if (iAuxParams < 0) then
+ itDels[ii] = 0
+ else
+ itDels[ii] tab_i (ii * 6 + 1), iAuxParams
+ if (itDels[ii] <= 0) then
+ itDels[ii] = 0
+ endif
+ endif
+
+ if (iAuxParams < 0) then
+ itTailDels[ii] = 0
+ else
+ itTailDels[ii] tab_i (ii * 6 + 2), iAuxParams
+ if (itTailDels[ii] <= 0) then
+ itTailDels[ii] = 0
+ endif
+ endif
+
+ if (iAuxParams < 0) then
+ itTrans[ii] = ii
+ else
+ itTrans[ii] tab_i (ii * 6 + 3), iAuxParams
+ if (itTrans[ii] < 0) then
+ itTrans[ii] = ii
+ endif
+ endif
+
+ if (iAuxParams < 0) then
+ itRetrig[ii] = ii
+ else
+ itRetrig[ii] tab_i (ii * 6 + 4), iAuxParams
+ if (itRetrig[ii] < 0) then
+ itRetrig[ii] = 0
+ endif
+ endif
+
+ if (iAuxParams < 0) then
+ itClipVolume[ii] = 1
+ else
+ itClipVolume[ii] tab_i (ii * 6 + 5), iAuxParams
+ if (itClipVolume[ii] < 0) then
+ itClipVolume[ii] = 1
+ endif
+ endif
+
+
+ ii = ii + 1
+od
+
+
+ki init 0
+iInitTab tab_i 0, iTabs
+iInitDur = itTotalDurs[0]
+kTab init iInitTab
+kTotalDur init iInitDur
+kStart init 0
+kDel init 0
+kLim init 0
+kClipVolume init 1
+kStarts[] init iTabSize
+kTrans[] init iTabSize
+kStop init 0
+ktTotalSteps[] init iTabSize
+ktTotalDurs[] init iTabSize
+ktDels[] init iTabSize
+ktTailDels[] init iTabSize
+ktRetrig[] init iTabSize
+ktClipVolume[] init iTabSize
+while ki < iTabSize do
+ kStarts[ki] = 0
+ kTrans[ki] = itTrans[ki]
+ ktRetrig[ki] = itRetrig[ki]
+ ktDels[ki] = itDels[ki]
+ ktTailDels[ki] = itTailDels[ki]
+ ktTotalSteps[ki] = itTotalSteps[ki] + ktDels[ki] + ktTailDels[ki]
+ ktTotalDurs[ki] = itTotalDurs[ki]
+ ktClipVolume[ki] = itClipVolume[ki]
+ ki = ki + 1
+od
+
+aNdx phasor (1 / iDur)
+aNdx = iDur * aNdx
+
+kIndex init 0
+kTrigIndex changed kUserIndex
+if (kTrigIndex == 1) then
+ if (kUserIndex != kIndex) then
+ kIndex = kUserIndex
+
+ ; should we retriger audio clip from the start or continue (default: continue)
+ if ktRetrig[kIndex] == 1 then
+ kStarts[kIndex] = 0
+ endif
+ endif
+endif
+
+
+kTrig metro (1 / iDur)
+if (kTrig == 1) then
+ if kIndex >= 0 && kIndex <= (iTabSize - 1) then
+ kStop = 0
+ kTabNext tab kIndex, iTabs
+ kStart = kStarts[kIndex]
+ kDel = ktDels[kIndex]
+ kLim = ktTotalSteps[kIndex] - ktTailDels[kIndex]
+ kTotalDur = ktTotalDurs[kIndex]
+ kClipVolume = ktClipVolume[kIndex]
+
+ if (isDebugPrint > 0) then
+ printks "kTab %d\n", 0, kTab
+ printks "kTabNext %d\n", 0, kTabNext
+ printks "kStart %d\n", 0, kStart
+ printks "kLim %d\n", 0, (ktTotalSteps[kIndex] - 1)
+ printks "kTotalDur %f\n", 0, kTotalDur
+ printks "kDel %f\n", 0, kDel
+ endif
+
+ if (kStart == ktTotalSteps[kIndex] - 1) then
+ kStarts[kIndex] = 0
+ kIndex = kTrans[kIndex]
+ else
+ kStarts[kIndex] = (kStarts[kIndex] + 1) % ktTotalSteps[kIndex]
+ endif
+ kTab = kTabNext
+ else
+ kStop = 1
+ endif
+endif
+
+kFadeEnv loopseg (1 / iDur), kTrig, 0, 1, 0.99, 1, 0.01, 0
+
+if (kStop == 0 && kStart >= kDel && kStart < kLim) then
+ aRes tableikt ((kStart - kDel) * iDur + aNdx) / kTotalDur, kTab, 1
+ aRes = aRes * kClipVolume * kFadeEnv
+else
+ aRes = 0
+endif
+
+xout aRes
+endop
diff --git a/data/opcodes/LiveRows.udo b/data/opcodes/LiveRows.udo
new file mode 100644
index 0000000..57bff73
--- /dev/null
+++ b/data/opcodes/LiveRows.udo
@@ -0,0 +1,226 @@
+; Anton Kholomiov, 2019
+
+; UDO to play row of toggle clip like in Ableton Live
+;
+; Stere version of liveRow. Toggle of stereo-audio clips syncronised with BPM.
+;
+; > aOut liveRows iTabSize, iLeftTabs, iRightTabs, iBpm, iBeatDur, kUserIndex, iAuxParams
+;
+; * iTabSize - how many audio clips in the row
+; * iLeftTabs, iRightTabs - tables that contains indices to left and right channels
+; of tables with monophonic audio clips (loaded with GEN01). Supposed that we load specific channels with GEN01.
+; * iBpm - BPM of the track
+; * iBeatDur - duration of the bar relative to quaters. So 4 - means 4/4, 3 means 3/4, 3.5 means 7/8 etc.
+; * kUserIndex - index of the played clip, if it's out of bounds silence is played back.
+;
+; The clip switch happens only in even iBeatDur times. So that it's always in sync.
+; It's supposed that audio clips of right and left channels are taken from single
+; stereo source so they have the same length and they are aligned with specified tempo.
+; So no automatic rescaling is done.
+;
+; Basic functionality is to switch the clips. But there are also aux-params that
+; can control the length and spacing of playback.
+;
+; The aux-params are packed into single table. It's last parameter and we can omit it.
+; The params follow by packets of 6 digits per audio-clip in the row.
+;
+; We can create the aux-param table with GEN02 like this
+;
+; > ; Aux params Size Del Tail AutoSwitch NeedRetrig Volume
+; > f201 0 10 -2 1 0 1 -1 1 1
+; 1 0 0 -1 0 1
+;
+; in the example above we can see two 5-packets sets for two audio clips.
+;
+; There are params:
+; * Size (Int) - the size of the audio in bars
+; * Delay (Int) - how many bars to skip on clip start
+; * Tail delay (Int) - how many empty bara to play at the end of the clip
+; * AutoSwitch (Int) - what audio-clip to switch when the current is over
+; if it equals to -1 than we continue to play the current clip.
+; * NeedRetrig - if we switch the clips we can continue to play from where we left out (default behaviour)
+; or we can start from beginning on switch (if NeedRetrig equals 1).
+; * Volume scale per audio-clip
+;
+opcode liveRows, aa, iiiiikjj
+iTabSize, iLeftTabs, iRightTabs, iBpm, iBeatDur, kUserIndex, iAuxParams, isDebugPrint xin
+kUserIndex = floor(kUserIndex)
+
+iDur = iBeatDur / (iBpm / 60)
+
+ii = 0
+; iTabSize = ftlen(iTabs)
+itTotalSteps[] init iTabSize
+itTotalDurs[] init iTabSize
+itTrans[] init iTabSize
+itDels[] init iTabSize
+itTailDels[] init iTabSize
+itRetrig[] init iTabSize
+itClipVolume[] init iTabSize
+while ii < iTabSize do
+ iTab tab_i ii, iLeftTabs
+ itCurrentFileSteps = floor((ftlen(iTab) / ftsr(iTab)) / iDur)
+
+ if (iAuxParams < 0) then
+ itTotalSteps[ii] = itCurrentFileSteps
+ else
+ itUserTotalSteps tab_i (ii * 6), iAuxParams
+ if (itUserTotalSteps > 0) then
+ itTotalSteps[ii] = itUserTotalSteps
+ else
+ itTotalSteps[ii] = itCurrentFileSteps
+ endif
+ endif
+
+ itTotalDurs[ii] = itTotalSteps[ii] * iDur * itCurrentFileSteps / itTotalSteps[ii]
+
+ if (iAuxParams < 0) then
+ itDels[ii] = 0
+ else
+ itDels[ii] tab_i (ii * 6 + 1), iAuxParams
+ if (itDels[ii] <= 0) then
+ itDels[ii] = 0
+ endif
+ endif
+
+ if (iAuxParams < 0) then
+ itTailDels[ii] = 0
+ else
+ itTailDels[ii] tab_i (ii * 6 + 2), iAuxParams
+ if (itTailDels[ii] <= 0) then
+ itTailDels[ii] = 0
+ endif
+ endif
+
+ if (iAuxParams < 0) then
+ itTrans[ii] = ii
+ else
+ itTrans[ii] tab_i (ii * 6 + 3), iAuxParams
+ if (itTrans[ii] < 0) then
+ itTrans[ii] = ii
+ endif
+ endif
+
+ if (iAuxParams < 0) then
+ itRetrig[ii] = ii
+ else
+ itRetrig[ii] tab_i (ii * 6 + 4), iAuxParams
+ if (itRetrig[ii] < 0) then
+ itRetrig[ii] = 0
+ endif
+ endif
+
+ if (iAuxParams < 0) then
+ itClipVolume[ii] = 1
+ else
+ itClipVolume[ii] tab_i (ii * 6 + 5), iAuxParams
+ if (itClipVolume[ii] < 0) then
+ itClipVolume[ii] = 1
+ endif
+ endif
+
+
+ ii = ii + 1
+od
+
+ki init 0
+iLeftInitTab tab_i 0, iLeftTabs
+iRightInitTab tab_i 0, iRightTabs
+iInitDur = itTotalDurs[0]
+kLeftTab init iLeftInitTab
+kRightTab init iRightInitTab
+kTotalDur init iInitDur
+kStart init 0
+kDel init 0
+kLim init 0
+kClipVolume init 1
+kStarts[] init iTabSize
+kTrans[] init iTabSize
+kStop init 0
+ktTotalSteps[] init iTabSize
+ktTotalDurs[] init iTabSize
+ktDels[] init iTabSize
+ktTailDels[] init iTabSize
+ktRetrig[] init iTabSize
+ktClipVolume[] init iTabSize
+while ki < iTabSize do
+ kStarts[ki] = 0
+ kTrans[ki] = itTrans[ki]
+ ktRetrig[ki] = itRetrig[ki]
+ ktClipVolume[ki] = itClipVolume[ki]
+ ktDels[ki] = itDels[ki]
+ ktTailDels[ki] = itTailDels[ki]
+ ktTotalSteps[ki] = itTotalSteps[ki] + ktDels[ki] + ktTailDels[ki]
+ ktTotalDurs[ki] = itTotalDurs[ki]
+ ki = ki + 1
+od
+
+aNdx phasor (1 / iDur)
+aNdx = iDur * aNdx
+
+kIndex init 0
+kTrigIndex changed kUserIndex
+if (kTrigIndex == 1) then
+ if (kUserIndex != kIndex) then
+ kIndex = kUserIndex
+
+ ; should we retriger audio clip from the start or continue (default: continue)
+ if ktRetrig[kIndex] == 1 then
+ kStarts[kIndex] = 0
+ endif
+ endif
+endif
+
+
+kTrig metro (1 / iDur)
+if (kTrig == 1) then
+ if kIndex >= 0 && kIndex <= (iTabSize - 1) then
+ kStop = 0
+ kLeftTabNext tab kIndex, iLeftTabs
+ kRightTabNext tab kIndex, iRightTabs
+ kStart = kStarts[kIndex]
+ kDel = ktDels[kIndex]
+ kLim = ktTotalSteps[kIndex] - ktTailDels[kIndex]
+ kTotalDur = ktTotalDurs[kIndex]
+ kClipVolume = ktClipVolume[kIndex]
+
+ if (isDebugPrint > 0) then
+ printks "kTabLeft %d\n", 0, kLeftTab
+ printks "kTabright %d\n", 0, kRightTab
+ printks "kLeftTabNext %d\n", 0, kLeftTabNext
+ printks "kRightTabNext %d\n", 0, kRightTabNext
+ printks "kStart %d\n", 0, kStart
+ printks "kLim %d\n", 0, (ktTotalSteps[kIndex] - 1)
+ printks "kTotalDur %f\n", 0, kTotalDur
+ printks "kDel %f\n", 0, kDel
+ endif
+
+ if (kStart == ktTotalSteps[kIndex] - 1) then
+ kStarts[kIndex] = 0
+ kIndex = kTrans[kIndex]
+ else
+ kStarts[kIndex] = (kStarts[kIndex] + 1) % ktTotalSteps[kIndex]
+ endif
+ kLeftTab = kLeftTabNext
+ kRightTab = kRightTabNext
+ else
+ kStop = 1
+ endif
+endif
+
+kFadeEnv loopseg (1 / iDur), kTrig, 0, 1, 0.99, 1, 0.01, 0
+
+if (kStop == 0 && kStart >= kDel && kStart < kLim) then
+ aPtr = ((kStart - kDel) * iDur + aNdx) / kTotalDur
+ aLeft tableikt aPtr, kLeftTab, 1
+ aRight tableikt aPtr, kRightTab, 1
+
+ aLeft = aLeft * kClipVolume * kFadeEnv
+ aRight = aRight * kClipVolume * kFadeEnv
+else
+ aLeft = 0
+ aRight = 0
+endif
+
+xout aLeft, aRight
+endop
diff --git a/src/Csound/Typed/GlobalState/Elements.hs b/src/Csound/Typed/GlobalState/Elements.hs
index 49ba9c7..052d026 100644
--- a/src/Csound/Typed/GlobalState/Elements.hs
+++ b/src/Csound/Typed/GlobalState/Elements.hs
@@ -44,6 +44,8 @@ module Csound.Typed.GlobalState.Elements(
ringModulatorPlugin, stChorusPlugin, stereoPingPongDelayPlugin,
tapeEchoPlugin,
delay1kPlugin,
+ liveRowPlugin, liveRowsPlugin,
+ ambiRowPlugin, ambiRowMp3Plugin
) where
import Data.List
@@ -96,7 +98,14 @@ newGen = saveGenId
newTabOfGens :: [Gen] -> State GenMap Int
newTabOfGens = (saveGenId . intTab =<<) . mapM saveGenId
- where intTab ns = Gen (length ns) (IntGenId (-2)) (fmap fromIntegral ns) Nothing
+ where intTab ns = Gen (nextPowOfTwo $ length ns) (IntGenId (-2)) (fmap fromIntegral ns) Nothing
+
+nextPowOfTwo :: Int -> Int
+nextPowOfTwo n
+ | frac == 0 = n
+ | otherwise = 2 ^ (integ + 1)
+ where
+ (integ, frac) = properFraction $ logBase 2 (fromIntegral n)
saveGenId :: Ord a => a -> State (IdMap a) Int
saveGenId a = state $ \s ->
@@ -602,3 +611,10 @@ stereoPingPongDelayPlugin = UdoPlugin "MultiFX/StereoPingPongDelay"
tapeEchoPlugin = UdoPlugin "MultiFX/TapeEcho"
delay1kPlugin = UdoPlugin "Utility/Delay1k"
+
+liveRowPlugin = UdoPlugin "LiveRow" -- live like trigger, mono
+liveRowsPlugin = UdoPlugin "LiveRows" -- stereo
+
+ambiRowPlugin = UdoPlugin "AmbiRow" -- ambi trigger, wav
+ambiRowMp3Plugin = UdoPlugin "AmbiRowMp3" -- mp3
+
diff --git a/src/Csound/Typed/Plugins.hs b/src/Csound/Typed/Plugins.hs
index cf16356..f174d77 100644
--- a/src/Csound/Typed/Plugins.hs
+++ b/src/Csound/Typed/Plugins.hs
@@ -39,6 +39,12 @@ module Csound.Typed.Plugins(
-- * Tape echo
tapeRead, tapeWrite, tapeEcho,
+ -- * Live row
+ liveRow, liveRows,
+
+ -- * Ambi row
+ ambiRow, ambiRowMp3,
+
-- utilities
delay1k
@@ -52,5 +58,7 @@ import Csound.Typed.Plugins.Korg35
import Csound.Typed.Plugins.SolinaChorus
import Csound.Typed.Plugins.ZeroDelayConvolution
import Csound.Typed.Plugins.Iain
+import Csound.Typed.Plugins.AmbiRow
+import Csound.Typed.Plugins.LiveRow
import Csound.Typed.Plugins.TapeEcho
import Csound.Typed.Plugins.Utilities
diff --git a/src/Csound/Typed/Plugins/AmbiRow.hs b/src/Csound/Typed/Plugins/AmbiRow.hs
new file mode 100644
index 0000000..8ec7ab0
--- /dev/null
+++ b/src/Csound/Typed/Plugins/AmbiRow.hs
@@ -0,0 +1,25 @@
+module Csound.Typed.Plugins.AmbiRow(
+ ambiRow, ambiRowMp3
+) where
+
+import Control.Monad.Trans.Class
+import Control.Applicative
+
+import Csound.Dynamic
+
+import Csound.Typed.Types
+import Csound.Typed.GlobalState
+import qualified Csound.Typed.GlobalState.Elements as E(ambiRowPlugin, ambiRowMp3Plugin)
+
+ambiRow :: Arr1 Str -> Sig -> Sig -> D -> Sig2
+ambiRow (Arr sFiles) kSpeed kIndex iFadeTime = toTuple $ fmap ($ 2) $ do
+ addUdoPlugin E.ambiRowPlugin
+ f sFiles <$> toGE kSpeed <*> toGE kIndex <*> toGE iFadeTime
+ where f sFiles kSpeed kIndex iFadeTime = mopcs "AmbiRow" ([Ar, Ar], [Sr, Kr, Kr, Ir]) [inlineVar $ head sFiles, kSpeed, kIndex, iFadeTime]
+
+ambiRowMp3 :: Arr1 Str -> Sig -> Sig -> D -> Sig2
+ambiRowMp3 (Arr sFiles) kSpeed kIndex iFadeTime = toTuple $ fmap ($ 2) $ do
+ addUdoPlugin E.ambiRowMp3Plugin
+ f sFiles <$> toGE kSpeed <*> toGE kIndex <*> toGE iFadeTime
+ where f sFiles kSpeed kIndex iFadeTime = mopcs "AmbiRowMp3" ([Ar, Ar], [Sr, Kr, Kr, Ir]) [inlineVar $ head sFiles, kSpeed, kIndex, iFadeTime]
+
diff --git a/src/Csound/Typed/Plugins/LiveRow.hs b/src/Csound/Typed/Plugins/LiveRow.hs
new file mode 100644
index 0000000..7aa834c
--- /dev/null
+++ b/src/Csound/Typed/Plugins/LiveRow.hs
@@ -0,0 +1,25 @@
+module Csound.Typed.Plugins.LiveRow(
+ liveRow,
+ liveRows
+) where
+
+import Control.Monad.Trans.Class
+import Control.Applicative
+
+import Csound.Dynamic
+
+import Csound.Typed.Types
+import Csound.Typed.GlobalState
+import qualified Csound.Typed.GlobalState.Elements as E(liveRowPlugin, liveRowsPlugin)
+
+liveRow :: D -> TabList -> D -> D -> Sig -> Tab -> Sig
+liveRow iTabSize iTabs iBpm iBeatDur kUserIndex iAuxParams = fromGE $ do
+ addUdoPlugin E.liveRowPlugin
+ f <$> toGE iTabSize <*> toGE iTabs <*> toGE iBpm <*> toGE iBeatDur <*> toGE kUserIndex <*> toGE iAuxParams
+ where f iTabSize iTabs iBpm iBeatDur kUserIndex iAuxParams = opcs "liveRow" [(Ar, [Ir, Ir, Ir, Ir, Kr, Ir])] [iTabSize, iTabs, iBpm, iBeatDur, kUserIndex, iAuxParams]
+
+liveRows :: D -> TabList -> TabList -> D -> D -> Sig -> Tab -> Sig2
+liveRows iTabSize iLeftTabs iRightTabs iBpm iBeatDur kUserIndex iAuxParams = toTuple $ fmap ($ 2) $ do
+ addUdoPlugin E.liveRowsPlugin
+ f <$> toGE iTabSize <*> toGE iLeftTabs <*> toGE iRightTabs <*> toGE iBpm <*> toGE iBeatDur <*> toGE kUserIndex <*> toGE iAuxParams
+ where f iTabSize iLeftTabs iRightTabs iBpm iBeatDur kUserIndex iAuxParams = mopcs "liveRows" ([Ar, Ar], [Ir, Ir, Ir, Ir, Ir, Kr, Ir]) [iTabSize, iLeftTabs, iRightTabs, iBpm, iBeatDur, kUserIndex, iAuxParams]
diff --git a/src/Csound/Typed/Plugins/ZeroDelayConvolution.hs b/src/Csound/Typed/Plugins/ZeroDelayConvolution.hs
index d8ed643..3b2130d 100644
--- a/src/Csound/Typed/Plugins/ZeroDelayConvolution.hs
+++ b/src/Csound/Typed/Plugins/ZeroDelayConvolution.hs
@@ -1,4 +1,4 @@
-module Csound.Typed.Plugins.ZeroDelayConvolution(
+module Csound.Typed.Plugins.ZeroDelayConvolution(
ZConvSpec(..), zconv, zconv'
) where
@@ -33,7 +33,7 @@ zconv :: Tab -> Sig -> Sig
zconv = zconv' def
-- | zero delay convolution.
---
+--
-- > zconv' (ZConvSpec ipart irat inp) ifn ain
--
-- Original UDO code by Victor Lazzarini.