Csound Csound-dev Csound-tekno Search About

[Csnd] 'wrap around' looping with flooper2

Date2023-09-14 15:25
FromPhilipp Neumann
Subject[Csnd] 'wrap around' looping with flooper2
Hello everybody!

I’m working on a little instrument and i have some problems with it. 
More or less a question if this functioning with flooper2 or not:
i want to to have flexible control over the loopstart point and loopend point. flooper2 seems to be the right opcode for this.
i introduced the variable kLoopSize which multiplies the soundfile length with a factor between 0.1 and 1.
this is then added to the loopstart point to define the loopend point. to keep these numbers in range i working with the modulo operation.
so from time to time the loopstart point is higher then the loopend point. and it seems like flooper2 doesn’t like it like this. i call whit wrap around looping.
is flooper2 not capable of doing this? or is there a problem  with my code?

Greetings,
Philipp






-d -odac -W -3 -+rtmidi=coremidi -Ma


sr = 48000
ksmps = 64
nchnls = 2
0dbfs = 1.0


gSFile = "" ; add to global section
giSndfl ftgen 0, 0, 0, 1, gSFile, 0, 0, 0

instr 1
  iFileLengthSec filelen gSFile  
  ;; play a soundfile from function table with looping
  kPlaybackSpeed = 1
  kAmp = 0.9
  ;; loop position
  initc7 1,1,0
  kStart ctrl7 1,1,0,1
  kStart port kStart, 0.01
  printks2 "Loop-Start: %f\n", kStart
  kLoopStart = (kStart*iFileLengthSec) % iFileLengthSec
  
  initc7 1,2,1
  kLoopSize ctrl7 1,2,0.1,1
  kLoopSize = kLoopSize * iFileLengthSec
  printks2 "Loop-Size in Seconds: %f\n", kLoopSize
  kLoopSize port kLoopSize, 0.01
  kLoopEnd = kLoopStart+kLoopSize % iFileLengthSec
  printks2 "Loop-End: %f\n", kLoopEnd
;  iFileLengthSmps = iFileLengthSec*sr


  kFadeTime = 0.025
  iSndflTable = giSndfl
  iNumChnls filenchnls gSFile
  if iNumChnls == 1 then
    aSndfl1 flooper2 kAmp, kPlaybackSpeed, kLoopStart, kLoopEnd, \
      kFadeTime, iSndflTable
    aSndfl2 = aSndfl1
  elseif iNumChnls == 2 then
    aSndfl1, aSndfl2 flooper2 kAmp, kPlaybackSpeed, kLoopStart, \
      kLoopEnd, kFadeTime, iSndflTable
  endif
  
  ;; output
  initc7 8,1,0
  kAmp ctrl7 8, 1, -90, 0
  printks2 "Amp: %d\n", kAmp
  kAmp port kAmp, 0.025
  aOut1 = aSndfl1 * ampdbfs(kAmp)
  aOut2 = aSndfl2 * ampdbfs(kAmp)
  outs aOut1, aOut2
endin
;-----------------------------------------------------------


i1 0 z


Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here

Date2023-09-14 15:58
From"Jeanette C."
SubjectRe: [Csnd] 'wrap around' looping with flooper2
Hi Philipp!
Sep 14 2023, Philipp Neumann has written:
...
> so from time to time the loopstart point is higher then the loopend point. and it seems like flooper2 doesn’t like it like this.
If you want looping like that, flooper2 might not be your opcode. AFAIK
it will loop from a start point (early) to an endpoint (late). You can
use one of the table opcodes (table, tablei, table3, ...). You would
have to manage your own crossfading then, but they can wrap around. If
you read a file with GEN01 you can get all the information you need.
With table opcodes, you best read one audio channel into one table. You
can then use ftsr (find the samplerate) and nsamp (the number of
samples/ table length) and then calculate the time of the audiofile. A
table can be read by a phasor, which uses a frequency. Well Frequency =
1/duration of file. Then you can add an offset to your phasor and scale
the phasor itself. The offset is your starting point, the scaling of the
phasor tells you how much of the table is read. If you have 1000 sample
in your table aPhasor * 1000 will read the whole table. That can be
scaled with a factor between .1 and 1. The offset (loop start) in
seconds must be multiplied by the tables samplerate.

This approach should work to loop one audio channel without crossfade.
If you want crossfades, you could loop through the table in parallel
with a slight offset. Take into acount the crossfade time.

There maybe better solutions. There are oscillators particularly geared
towards samle reading, allowing even stereo tables.

HTH.

Best wishes,

Jeanette

-- 
  * Website: http://juliencoder.de - for summer is a state of sound
  * Youtube: https://www.youtube.com/channel/UCMS4rfGrTwz8W7jhC1Jnv7g
  * Audiobombs: https://www.audiobombs.com/users/jeanette_c
  * GitHub: https://github.com/jeanette-c

If only I could trade the fancy cars
For a chance today,
it's incomparable <3
(Britney Spears)

Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here

Date2023-09-14 18:20
FromPhilipp Neumann
SubjectRe: [Csnd] 'wrap around' looping with flooper2
Thanks, Jeanette!

This one works perfectly fine now!

Now i’m asking how to implement a windowing function to eleminate clicks while looping. 

Can someone help me a give me a hint?




-d -odac -W -3 -+rtmidi=coremidi -Ma


sr = 48000
ksmps = 64
nchnls = 2
0dbfs = 1.0


gSfile = "/Users/philippneumann/Library/Mobile Documents/com~apple~CloudDocs/Sound-Library/Elektromagnetisches/Elektromagnetisch_ElektroUsi_Stereo-01.wav" ; add to 
;-----------------------------------------------------------
#include "/Users/philippneumann/Documents/Csound/UDOs/UDOs-pn.csd"
;-----------------------------------------------------------
instr 1
  iSndflSec filelen gSfile
  iSndflSr filesr gSfile
  iSndflSamps = iSndflSec*iSndflSr

  initc7 1,1,0
  kLoopStart ctrl7 1,1,0,1
  kStart = (kLoopStart*iSndflSamps)
  initc7 1,2,1
  kLoopSize ctrl7 1,2,0.005 ,1
  kSize = kLoopSize*iSndflSamps
  
  ;; read a soundfile into a table and read it with a phasor
  ;; mono and stereo files

  kSpeed ctrl7 1,3, -2, 4

  iSndflNumChnls filenchnls gSfile
  if iSndflNumChnls == 1 	goto monoFile
  goto stereoFile

  monoFile:
    iSndflTblLeft ftgen 0, 0, 0, 1, gSfile, 0, 0, 1
    iSndflTblRight = iSndflTblLeft
    aIndex phasor kSpeed/(kSize/ftsr(iSndflTblLeft))
    aIndex = aIndex*kSize
    aIndex = aIndex+kStart
    aSmpL table aIndex, iSndflTblLeft, 0,0,1
    aSmpR table aIndex, iSndflTblRight, 0,0,1
    goto output

  stereoFile:
    iSndflTblLeft ftgen 0, 0, 0, 1, gSfile, 0, 0, 1
    iSndflTblRight ftgen 0, 0, 0, 1, gSfile, 0, 0, 2
    aIndex = (kSize*aIndex)+kStart
    aIndex phasor kSpeed/(kSize/ftsr(iSndflTblLeft))
    aIndex = aIndex*kSize
    aIndex = aIndex+kStart
    aSmpL table aIndex, iSndflTblLeft, 0,0,1
    aSmpR table aIndex, iSndflTblLeft, 0,0,1

  output:
    aOutL = aSmpL
    aOutR = aSmpR
    outs aOutL, aOutR

endin
;-----------------------------------------------------------


i1 0 z




> Am 14.09.2023 um 16:58 schrieb Jeanette C. :
> 
> Hi Philipp!
> Sep 14 2023, Philipp Neumann has written:
> ...
>> so from time to time the loopstart point is higher then the loopend point. and it seems like flooper2 doesn’t like it like this.
> If you want looping like that, flooper2 might not be your opcode. AFAIK
> it will loop from a start point (early) to an endpoint (late). You can
> use one of the table opcodes (table, tablei, table3, ...). You would
> have to manage your own crossfading then, but they can wrap around. If
> you read a file with GEN01 you can get all the information you need.
> With table opcodes, you best read one audio channel into one table. You
> can then use ftsr (find the samplerate) and nsamp (the number of
> samples/ table length) and then calculate the time of the audiofile. A
> table can be read by a phasor, which uses a frequency. Well Frequency =
> 1/duration of file. Then you can add an offset to your phasor and scale
> the phasor itself. The offset is your starting point, the scaling of the
> phasor tells you how much of the table is read. If you have 1000 sample
> in your table aPhasor * 1000 will read the whole table. That can be
> scaled with a factor between .1 and 1. The offset (loop start) in
> seconds must be multiplied by the tables samplerate.
> 
> This approach should work to loop one audio channel without crossfade.
> If you want crossfades, you could loop through the table in parallel
> with a slight offset. Take into acount the crossfade time.
> 
> There maybe better solutions. There are oscillators particularly geared
> towards samle reading, allowing even stereo tables.
> 
> HTH.
> 
> Best wishes,
> 
> Jeanette
> 
> -- 
> * Website: http://juliencoder.de - for summer is a state of sound
> * Youtube: https://www.youtube.com/channel/UCMS4rfGrTwz8W7jhC1Jnv7g
> * Audiobombs: https://www.audiobombs.com/users/jeanette_c
> * GitHub: https://github.com/jeanette-c
> 
> If only I could trade the fancy cars
> For a chance today,
> it's incomparable <3
> (Britney Spears)
> 
> Csound mailing list
> Csound@listserv.heanet.ie
> https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
> Send bugs reports to
>       https://github.com/csound/csound/issues
> Discussions of bugs and features can be posted here

Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here

Date2023-09-14 21:03
From"Jeanette C."
SubjectRe: [Csnd] 'wrap around' looping with flooper2
Hi Philipp,
a classic windowing function may not help. but perhaps construct a phasor of 
the same frequency, though just scheduled 0-1, i.e. the normal phasor output, 
and let it read a linear (GEN07) table, or something similar, that starts with 
a very short ramp up and ends with a very short ramp down. Not ideal, because 
when you change the frequency, i.e. the amount of the file you play, the fade 
time will change. I can't think of anything else though.

If you adjust all the scaling and offsetting of your current phasor in a 
separate statement, you can even use the same phasor. Otherwise, if you can 
think of ways to do the proper calculations, you might try loopseg? Or if you 
can manage to set off triggers at the right time, you could use triglinseg. If 
you use a syncphasor (with 0 input for its sync input), you can get one 
trigger when the phasor starts at 0.

HTH.

Best wishes,

Jeanette

-- 
  * Website: http://juliencoder.de - for summer is a state of sound
  * Youtube: https://www.youtube.com/channel/UCMS4rfGrTwz8W7jhC1Jnv7g
  * Audiobombs: https://www.audiobombs.com/users/jeanette_c
  * GitHub: https://github.com/jeanette-c

Can't make you love me
I'm just a girl with a crush on you <3
(Britney Spears)

Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here

Date2023-09-15 08:15
FromPhilipp Neumann
SubjectRe: [Csnd] 'wrap around' looping with flooper2
I guess this is the way to do it and i hope i calculated the speed of the window phasor correctly. It sounds right to me. Maybe someone want’s to try it out?

Now i’m at the point where i want to avoid these clicking sounds when i change the reading offset or loopsize.
I think they occur because i’m changing the values during the playback. So maybe i will have to implement the right time for updating the values. E.g. when the phasor is at 0. 
Or is there a other solution?

opcode sndfl_looper, aaa, Skkkii
  SFile, kSpeed, kLoopStart, kLoopSize, iStereoOffset, iWndwFt xin

  ;; read data from soundfile
  iSndflSec filelen SFile
  iSndflSr filesr SFile
  iSndflSamps = iSndflSec*iSndflSr
  
  ;; create the tables for the soundfile
  iSndflNumChnls filenchnls SFile
  if iSndflNumChnls == 1 then
  iSndflTbl1 ftgen 0,0,0,1,SFile,0,0,1
  iSndflTbl2 = iSndflTbl1 
  elseif iSndflNumChnls == 2 then
  iSndflTbl1 ftgen 0,0,0,1,SFile,0,0,1
  iSndflTbl2 ftgen 0,0,0,1,SFile,0,0,2
  endif

  ;; parameter for the table reading
  kSpeed = kSpeed
  kStart = (kLoopStart*iSndflSamps)
  kSize = kLoopSize*iSndflSamps
  kPhasorSpeed = kSpeed/(kSize/iSndflSr)
  aIndex1 phasor kPhasorSpeed
  aIndex2 phasor kPhasorSpeed,iStereoOffset
  aSndfl1 table3 (aIndex1*kSize)+kStart,iSndflTbl1,0,0,1
  aSndfl2 table3 (aIndex2*kSize)+kStart,iSndflTbl2,0,0,1
  aWin1 table3 aIndex1,iWndwFt,1
  aWin2 table3 aIndex2,iWndwFt,1

  ;; output
  aSndfl1 *= aWin1
  aSndfl2 *= aWin2
  xout aIndex1,aSndfl1,aSndfl2 
endop
 

> Am 14.09.2023 um 22:03 schrieb Jeanette C. :
> 
> Hi Philipp,
> a classic windowing function may not help. but perhaps construct a phasor of the same frequency, though just scheduled 0-1, i.e. the normal phasor output, and let it read a linear (GEN07) table, or something similar, that starts with a very short ramp up and ends with a very short ramp down. Not ideal, because when you change the frequency, i.e. the amount of the file you play, the fade time will change. I can't think of anything else though.
> 
> If you adjust all the scaling and offsetting of your current phasor in a separate statement, you can even use the same phasor. Otherwise, if you can think of ways to do the proper calculations, you might try loopseg? Or if you can manage to set off triggers at the right time, you could use triglinseg. If you use a syncphasor (with 0 input for its sync input), you can get one trigger when the phasor starts at 0.
> 
> HTH.
> 
> Best wishes,
> 
> Jeanette
> 
> -- 
> * Website: http://juliencoder.de - for summer is a state of sound
> * Youtube: https://www.youtube.com/channel/UCMS4rfGrTwz8W7jhC1Jnv7g
> * Audiobombs: https://www.audiobombs.com/users/jeanette_c
> * GitHub: https://github.com/jeanette-c
> 
> Can't make you love me
> I'm just a girl with a crush on you <3
> (Britney Spears)
> 
> Csound mailing list
> Csound@listserv.heanet.ie
> https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
> Send bugs reports to
>       https://github.com/csound/csound/issues
> Discussions of bugs and features can be posted here
> 

Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here

Date2023-09-15 08:38
From"Jeanette C."
SubjectRe: [Csnd] 'wrap around' looping with flooper2
Hi Philipp,
that's something I thought about yesterday night. If you use a syncphasor to 
go through your table, it will set off a sync impulse in one of its two 
outputs. You can use that to allow changes. You might have changes at any time 
to the variables you have and then at this sync point, copy them to something 
like kRealLoopStart and kRealLoopEnd.

Given that, you can now avoid the window function and use a trigger envelope 
like triglinseg. Because you can trigger one envelope immediately and you can 
delay the sync impulse with some delay opcode by the current loop length. 
Since you don't allow update at any time, you will know the loop length at 
beginning of the loop. Then you can decide on a crossfade time and maybe on 
the exact shape of your envelope. Tip: I like to adapt such envelope shapes by 
passing them through logcurve or expcurve.

Best wishes,

Jeanette

-- 
  * Website: http://juliencoder.de - for summer is a state of sound
  * Youtube: https://www.youtube.com/channel/UCMS4rfGrTwz8W7jhC1Jnv7g
  * Audiobombs: https://www.audiobombs.com/users/jeanette_c
  * GitHub: https://github.com/jeanette-c

And I love the way with just one whisper
You tell me everything <3
(Britney Spears)

Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here

Date2023-09-15 12:53
FromPhilipp Neumann
Subject[Csnd] WARNING: init phase truncation - 'wrap around' looping with flooper2
Thanks Jeanette again!

Now this works perfectly fine and i have a lot of fun!

Can someone tell me what this warning means?
i implemented a reinit inside the udo so i can change the phase offset of one of the phasors.
WARNING: init phase truncation

And feel free to use this little UDO:
opcode sndfl_looper, aa, Skkkki
  SFile, kSpeed, kLoopStart, kLoopSize, kStereoOffset, iWndwFt xin
  setksmps 1
  ;; read data from soundfil
  iSndflSec filelen SFile
  iSndflSr filesr SFile
  iSndflSamps = iSndflSec*iSndflSr
  
  ;; create the tables for the soundfile
  iSndflNumChnls filenchnls SFile
  if iSndflNumChnls == 1 then
  iSndflTbl1 ftgen 0,0,0,1,SFile,0,0,1
  iSndflTbl2 = iSndflTbl1 
  elseif iSndflNumChnls == 2 then
  iSndflTbl1 ftgen 0,0,0,1,SFile,0,0,1
  iSndflTbl2 ftgen 0,0,0,1,SFile,0,0,2
  endif

  ;; parameter for the table reading
  kChange changed kStereoOffset
  if kChange == 1 then
    reinit UPDATE
  endif

  kSpeed = kSpeed
  kStart = (kLoopStart*iSndflSamps)
  kSize = kLoopSize*iSndflSamps
  kPhasorSpeed = kSpeed/(kSize/iSndflSr)
  aSyncIn init 0
  aSyncOut1 init 1
  aSyncOut2 init 1
  kPhasorSpeed1 = (k(aSyncOut1) == 1 ? kPhasorSpeed : kPhasorSpeed1)
  kPhasorSpeed2 = (k(aSyncOut2) == 1 ? kPhasorSpeed : kPhasorSpeed2)
  UPDATE:
  aIndex1,aSyncOut1 syncphasor kPhasorSpeed1,aSyncIn

  aIndex2,aSyncOut2 syncphasor kPhasorSpeed2,aSyncIn,i(kStereoOffset)
  kSize1 = (k(aSyncOut1) == 1 ? kSize : kSize1)
  kSize2 = (k(aSyncOut2) == 1 ? kSize : kSize2)
  kStart1 = (k(aSyncOut1) == 1 ? kStart : kStart1)
  kStart2 = (k(aSyncOut2) == 1 ? kStart : kStart2)
  aSndfl1 table3 (aIndex1*kSize1)+kStart1,iSndflTbl1,0,0,1
  aSndfl2 table3 (aIndex2*kSize2)+kStart2,iSndflTbl2,0,0,1
  aWin1 table3 aIndex1,iWndwFt,1
  aWin2 table3 aIndex2,iWndwFt,1

  ;; output
  aSndfl1 *= aWin1
  aSndfl2 *= aWin2
  xout aSndfl1,aSndfl2 
endop

> Am 15.09.2023 um 09:38 schrieb Jeanette C. :
> 
> Hi Philipp,
> that's something I thought about yesterday night. If you use a syncphasor to go through your table, it will set off a sync impulse in one of its two outputs. You can use that to allow changes. You might have changes at any time to the variables you have and then at this sync point, copy them to something like kRealLoopStart and kRealLoopEnd.
> 
> Given that, you can now avoid the window function and use a trigger envelope like triglinseg. Because you can trigger one envelope immediately and you can delay the sync impulse with some delay opcode by the current loop length. Since you don't allow update at any time, you will know the loop length at beginning of the loop. Then you can decide on a crossfade time and maybe on the exact shape of your envelope. Tip: I like to adapt such envelope shapes by passing them through logcurve or expcurve.
> 
> Best wishes,
> 
> Jeanette
> 
> -- 
> * Website: http://juliencoder.de - for summer is a state of sound
> * Youtube: https://www.youtube.com/channel/UCMS4rfGrTwz8W7jhC1Jnv7g
> * Audiobombs: https://www.audiobombs.com/users/jeanette_c
> * GitHub: https://github.com/jeanette-c
> 
> And I love the way with just one whisper
> You tell me everything <3
> (Britney Spears)
> 
> Csound mailing list
> Csound@listserv.heanet.ie
> https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
> Send bugs reports to
>       https://github.com/csound/csound/issues
> Discussions of bugs and features can be posted here
> 

Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here

Date2023-09-15 13:36
From"Jeanette C."
SubjectRe: [Csnd] WARNING: init phase truncation - 'wrap around' looping with flooper2
Hi Philipp,
I can't exactly say why this is happening, I never really worked with reinit. 
But couldn't you solve the problem in a different way?

aPhasor, aSyncOut syncphasor ...
if (k(aSyncOut) == 1) then ; set new values
   kLoopStart = kLoopStartLiveInput
   ...
endif

With setksmps 1 you can do that and thus use standard flow control with if, 
while, etc.

HTH.

Best wishes,

Jeanette

-- 
  * Website: http://juliencoder.de - for summer is a state of sound
  * Youtube: https://www.youtube.com/channel/UCMS4rfGrTwz8W7jhC1Jnv7g
  * Audiobombs: https://www.audiobombs.com/users/jeanette_c
  * GitHub: https://github.com/jeanette-c

And when you say those words
It's the sweetest thing I've ever heard <3
(Britney Spears)

Csound mailing list
Csound@listserv.heanet.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here