Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
1.6.0-bacon10
Allow greater granular stretching using LPOF
Documentation in tips and tricks
1.6.0-bacon11
Slices decoupled from loop mode
* Slices are no longer a loop mode — they are now an independent parameter
* Set slices > 1 to enable slicing; loop mode (none/loop/ping pong/etc.) applies within each slice
* Enables looped slices, e.g. for amen breaks and other timed loops
* Old projects with "slicer" loop mode load correctly: slices count is preserved, loop mode resets to "none"
1.6.0-bacon10
Allow greater granular stretching using LPOF
Documentation in tips and tricks
1.6.0-bacon10
Slices decoupled from loop mode
* Slices are no longer a loop mode — they are now an independent parameter
* Set slices > 1 to enable slicing; loop mode (none/loop/ping pong/etc.) applies within each slice
* Enables looped slices, e.g. for amen breaks and other timed loops
* Old projects with "slicer" loop mode load correctly: slices count is preserved, loop mode resets to "none"
1.6.0-bacon5
Auto-load last project on startup
* Application can now load the last project automatically on startup
Expand Down
14 changes: 8 additions & 6 deletions docs/wiki/tips_and_tricks.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,14 @@ Here's a nice example, courtesy of jonbro, chopping drums he had recorded previo

[Jonbro - the thing is the thing](https://battleofthebits.com/arena/Entry/the+thing+is+the+thing/1479/)

### Slice! (new chopping method)
Since version 1.3o there is a new loop mode called Slice
Using this, you can assign up to 256 individual slices from C-2 (C minus two) up to the amount of slices you set. How handy!

Of course, you are not limited to drum loops. Just chop anything away !
The example project BETA uses Slice mode to chop up a dank AF sample by Basscarrier
### Slices (sample chopping)
Set the **slices** parameter in the instrument to divide a sample into equal parts,
mapped chromatically from C-2 (the lowest note, not C2) upward. The **loop mode** parameter then applies
independently within each slice — set it to "loop" or "ping pong" to get looped
slices, great for amen breaks and timed loops. Set to Oscillator for very grainy rhythmic noises

You can assign up to 256 individual slices. Of course, you are not limited to drum
loops — just chop anything away!

### Granular timestretching with LPOF

Expand Down
312 changes: 151 additions & 161 deletions sources/Application/Instruments/SampleInstrument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,46 +231,53 @@ bool SampleInstrument::Start(int channel,unsigned char midinote,bool cleanstart)
rp->reverse_=false ;

float driverRate = float(Audio::GetInstance()->GetSampleRate());

switch (loopmode) {
case SILM_ONESHOT:
case SILM_LOOP:
case SILM_LOOP_PINGPONG:

// Compute speed factor
// if instrument sampled below 44.1Khz, should
// travel slower in sample

rp->rendFirst_ = start_->GetInt();
rp->position_ = float(rp->rendFirst_);
rp->baseSpeed_ =
fl2fp(source_->GetSampleRate(rp->midiNote_) / driverRate);
rp->reverse_ = (rp->rendLoopEnd_ < rp->position_);

break;

case SILM_OSC:
// case SILM_OSCFINE:
{

float freq = 261.6255653006f; // C3
/* if (loopmode==SILM_OSCFINE) {
freq=float(pow(2.0,-0.75))*440; // C3
}*/
int length = rp->rendLoopEnd_ - rp->rendLoopStart_;
if (length == 0)
length = 1;
if (length < 0) {
rp->reverse_=true ;
length=-length ;
} ;
rp->baseSpeed_=fl2fp((freq*length)/driverRate) ;
rp->rendFirst_ = rp->rendLoopStart_;
if (cleanstart) {
rp->position_= float(rp->rendFirst_);
}
break ;
}
int isSliced = slices_->GetInt() > 1;
if (isSliced) {
if (rp->midiNote_ > slices_->GetInt() - 1) return false; // No sound outside of slice range
int slice = rp->rendLoopEnd_ / slices_->GetInt();
rp->rendLoopStart_ = rp->midiNote_ * slice;
rp->rendLoopEnd_ = (rp->midiNote_ + 1) * slice;
}

switch (loopmode) {
case SILM_ONESHOT:
case SILM_LOOP:
case SILM_LOOP_PINGPONG:
// Compute speed factor
// if instrument sampled below 44.1Khz, should
// travel slower in sample

rp->rendFirst_ =
(isSliced) ? rp->rendLoopStart_ : start_->GetInt();
rp->position_ = float(rp->rendFirst_);
rp->baseSpeed_ =
fl2fp(source_->GetSampleRate(rp->midiNote_) / driverRate);
rp->reverse_ = (rp->rendLoopEnd_ < rp->position_);

break;

case SILM_OSC:
// case SILM_OSCFINE:
{

float freq = 261.6255653006f; // C3
/* if (loopmode==SILM_OSCFINE) {
freq=float(pow(2.0,-0.75))*440; // C3
}*/
int length = rp->rendLoopEnd_ - rp->rendLoopStart_;
if (length == 0)
length = 1;
if (length < 0) {
rp->reverse_ = true;
length = -length;
};
rp->baseSpeed_ = fl2fp((freq * length) / driverRate);
rp->rendFirst_ = rp->rendLoopStart_;
if (cleanstart) {
rp->position_ = float(rp->rendFirst_);
}
break;
}
case SILM_LOOPSYNC:
{
int length=rp->rendLoopEnd_-rp->rendLoopStart_ ;
Expand All @@ -287,38 +294,24 @@ bool SampleInstrument::Start(int channel,unsigned char midinote,bool cleanstart)
rp->position_= float(rp->rendFirst_);
}
break ;
}
case SILM_SLICE: {
if (rp->midiNote_ > slices_->GetInt()-1) break; // No sound outside of slice range
int note = rp->midiNote_;
int wavSize=rp->rendLoopEnd_;
int slice = wavSize/slices_->GetInt();

rp->position_= float(note*slice);
rp->baseSpeed_=fl2fp(source_->GetSampleRate(rp->midiNote_)/driverRate) ;
rp->speed_ = rp->baseSpeed_;
rp->rendLoopEnd_ = (note+1)*slice;
break ;
}
case SILM_LAST:
}
case SILM_LAST:
NAssert(0) ;
break ;
}

// Compute octave & note difference from root

float fineTune = float(fineTune_->GetInt() - 0x7F);
fineTune /= float(0x80);
int offset = midinote - rootNote;
if (loopmode == SILM_SLICE) {
if (isSliced) {
offset = rootNote - source_->GetRootNote(rp->midiNote_);
}
while (offset>127)
{
offset-=12 ;
}

fixed freqFactor=fl2fp(float(pow(2.0,(offset+fineTune)/12.0))) ;
}
while (offset > 127) {
offset -= 12;
}

fixed freqFactor=fl2fp(float(pow(2.0,(offset+fineTune)/12.0))) ;
rp->baseSpeed_=fp_mul(rp->baseSpeed_,freqFactor) ;
rp->speed_=rp->baseSpeed_ ;

Expand Down Expand Up @@ -427,16 +420,15 @@ void SampleInstrument::updateFeedback(renderParams *rp) {
switch(loopMode) {
case SILM_ONESHOT:
case SILM_LOOP:
case SILM_LOOP_PINGPONG:
case SILM_SLICE:
case SILM_LOOPSYNC:
rp->feedbackMode_=FB_ADD ;
if (offset<0x80) {
offset=FB_BUFFER_LENGTH-offset-1 ;
} else {
offset=FB_BUFFER_LENGTH-offset*10-1 ;
} ;
break ;
case SILM_LOOP_PINGPONG:
case SILM_LOOPSYNC:
rp->feedbackMode_ = FB_ADD;
if (offset < 0x80) {
offset = FB_BUFFER_LENGTH - offset - 1;
} else {
offset = FB_BUFFER_LENGTH - offset * 10 - 1;
}
break;
case SILM_OSC:
// case SILM_OSCFINE:
if (offset<0x80) {
Expand Down Expand Up @@ -662,99 +654,97 @@ bool SampleInstrument::Render(int channel,fixed *buffer,int size,bool updateTick
if (!rpReverse) { //Looping forward
if (input>=lastSample/*-((loopMode==SILM_OSCFINE)?1:0)*/) {
switch(loopMode) {
case SILM_ONESHOT:
case SILM_SLICE:
*rpFinished=true ;
break ;
case SILM_LOOP:
case SILM_OSC:
case SILM_LOOPSYNC:
input=loopPosition ;
rpReverse=(loopPosition>lastSample) ;
if (rpReverse) {
fpSpeed=-rp->speed_ ;
} else {
fpSpeed=rp->speed_ ;
}
break ;
case SILM_LOOP_PINGPONG:
if ((loopPosition > lastSample)) {
if (input <= lastSample || input >= loopPosition) {
rpReverse = !rpReverse;
fpSpeed = -fpSpeed;
}
} else {
if (input>=lastSample || input <= loopPosition) {
rpReverse = !rpReverse;
fpSpeed = -fpSpeed;
}
}
break;
/* case SILM_OSCFINE:
{
int offset=(input-lastSample)/channelCount ;
rpReverse=(loopPosition>lastSample) ;
if (rpReverse) {
fpSpeed=-rp->speed_ ;
input=loopPosition-offset ;
} else {
fpSpeed=rp->speed_ ;
input=loopPosition+offset ;
}
break ;
}*/
case SILM_LAST:
NAssert(0) ;
break ;
case SILM_ONESHOT:
*rpFinished = true;
break;
case SILM_LOOP:
case SILM_OSC:
case SILM_LOOPSYNC:
input = loopPosition;
rpReverse = (loopPosition > lastSample);
if (rpReverse) {
fpSpeed = -rp->speed_;
} else {
fpSpeed = rp->speed_;
}
break;
case SILM_LOOP_PINGPONG:
if ((loopPosition > lastSample)) {
if (input <= lastSample || input >= loopPosition) {
rpReverse = !rpReverse;
fpSpeed = -fpSpeed;
}
} else {
if (input >= lastSample || input <= loopPosition) {
rpReverse = !rpReverse;
fpSpeed = -fpSpeed;
}
}
break;
/* case SILM_OSCFINE:
{
int
offset=(input-lastSample)/channelCount ;
rpReverse=(loopPosition>lastSample)
; if (rpReverse) { fpSpeed=-rp->speed_ ;
input=loopPosition-offset
; } else { fpSpeed=rp->speed_ ;
input=loopPosition+offset
;
}
break ;
}*/
case SILM_LAST:
NAssert(0);
break;
} ;
}
} else { // Looping backward
if (input<lastSample) {
switch(loopMode) {
case SILM_ONESHOT:
case SILM_SLICE:
*rpFinished=true ;
break ;
case SILM_LOOP:
case SILM_OSC:
case SILM_LOOPSYNC:
input=loopPosition ;
rpReverse=(loopPosition>lastSample) ;
if (rpReverse) {
fpSpeed=-rp->speed_ ;
} else {
fpSpeed=rp->speed_ ;
}
break ;
case SILM_LOOP_PINGPONG:
if ((loopPosition > lastSample)) {
if (input <= lastSample || input >= loopPosition) {
rpReverse = !rpReverse;
fpSpeed = -fpSpeed;
}
} else {
if (input>=lastSample || input <= loopPosition) {
rpReverse = !rpReverse;
fpSpeed = -fpSpeed;
}
}
break;
/* case SILM_OSCFINE:
{
int offset=(lastSample-input)/channelCount ;
rpReverse=(loopPosition>lastSample) ;
if (rpReverse) {
fpSpeed=-rp->speed_ ;
input=loopPosition-offset ;
} else {
fpSpeed=rp->speed_ ;
input=loopPosition+offset ;
}
break ;
}*/
case SILM_LAST:
NAssert(0) ;
break ;
case SILM_ONESHOT:
*rpFinished = true;
break;
case SILM_LOOP:
case SILM_OSC:
case SILM_LOOPSYNC:
input = loopPosition;
rpReverse = (loopPosition > lastSample);
if (rpReverse) {
fpSpeed = -rp->speed_;
} else {
fpSpeed = rp->speed_;
}
break;
case SILM_LOOP_PINGPONG:
if ((loopPosition > lastSample)) {
if (input <= lastSample || input >= loopPosition) {
rpReverse = !rpReverse;
fpSpeed = -fpSpeed;
}
} else {
if (input >= lastSample || input <= loopPosition) {
rpReverse = !rpReverse;
fpSpeed = -fpSpeed;
}
}
break;
/* case SILM_OSCFINE:
{
int
offset=(lastSample-input)/channelCount ;
rpReverse=(loopPosition>lastSample)
; if (rpReverse) { fpSpeed=-rp->speed_ ;
input=loopPosition-offset
; } else { fpSpeed=rp->speed_ ;
input=loopPosition+offset
;
}
break ;
}*/
case SILM_LAST:
NAssert(0);
break;
} ;
}
};
Expand Down
Loading
Loading