Sample Import Tutorial - It's Broken!
-
I've been following the Custom Sample Import tutorial over the last week, extending it to work with multiple samplers, and I started noticing some quirky behaviour. After failing to troubleshoot it for a week, I went back to the original tutorial, and the example project has the same issues!
The problems are from the Loop point editor.
Go ahead and create these settings after loading in a sample, and you'll see what I mean.
The visuals don't line up with what we are hearing.
The sample was stored on my fast ssd so it's not a streaming issue.Additionally there is some very odd behaviour when dragging the loop points. Grab one of the loop handles and move it close to the other handle, when you release the handle the loop points will suddenly rearrange themselves.
My guess is that something in Hise has changed. The tutorial was made quite a while ago:
https://github.com/christophhart/hise_tutorial/tree/master/CustomSampleImport
-
@griffinboy said in Sample Import Tutorial - It's Broken!:
Additionally there is some very odd behaviour when dragging the loop points. Grab one of the loop handles and move it close to the other handle, when you release the handle the loop points will suddenly rearrange themselves.
-
@griffinboy said in Sample Import Tutorial - It's Broken!:
Additionally there is some very odd behaviour when dragging the loop points. Grab one of the loop handles and move it close to the other handle, when you release the handle the loop points will suddenly rearrange themselves.
Try replacing LoopPointDagger.js with this new implementation - I think I solved the problem, not sure.
/** This defines a panel that will mimic the loop dragging facilities from the sampler */ namespace LoopPointDragger { // Create the path for the fade in const var fadePath = Content.createPath(); fadePath.startNewSubPath(0.0, 1.0); fadePath.lineTo(1.0, 0.0); fadePath.lineTo(1.0, 1.0); fadePath.closeSubPath(); const var fadeOutPath = Content.createPath(); fadeOutPath.startNewSubPath(0.0, 1.0); fadeOutPath.lineTo(0.0, 0.0); fadeOutPath.lineTo(1.0, 1.0); fadeOutPath.closeSubPath(); /** this will update the internal data for the panel and must be called whenever one of the sample property changes. */ inline function updateLoopPoints() { if(!isDefined(sound)) { LoopPanel.data.sx = 0; LoopPanel.data.sw = 0; LoopPanel.data.lx = 0; LoopPanel.data.lw = 0; LoopPanel.data.dx = 0; LoopPanel.data.dw = 0; LoopPanel.data.xfw = 0; LoopPanel.repaint(); return; } local w = LoopPanel.getWidth(); local ss = sound.get(Sampler.SampleStart) / totalSamples; local se = sound.get(Sampler.SampleEnd) / totalSamples; local ls = sound.get(Sampler.LoopStart) / totalSamples; local le = sound.get(Sampler.LoopEnd) / totalSamples; LoopPanel.data.sx = ss * w; LoopPanel.data.sw = (se - ss) * w; LoopPanel.data.lx = ls * w; LoopPanel.data.lw = (le - ls) * w; LoopPanel.data.dx = LoopPanel.data.lx; LoopPanel.data.dw = LoopPanel.data.lw; LoopPanel.data.xfw = parseInt(sound.get(Sampler.LoopXFade) / totalSamples * w); LoopPanel.repaint(); } SampleLoadSave.initAfterSampleLoad(); const var MINIMUM_LOOP_LENGTH = 5; LoopPanel.setMouseCallback(function(event) { this.data.hover = event.hover || event.drag; var midX = this.data.dx + 0.5 * this.data.dw; if(!event.drag) this.data.setLeft = event.x < midX; if(event.drag || event.mouseUp) { if(this.data.setLeft) { var right = this.data.dx + this.data.dw; var newLeft = Math.range(event.x, this.data.sx, right - MINIMUM_LOOP_LENGTH); this.data.dx = newLeft; this.data.dw = right - newLeft; } else { var maxRight = this.data.sx + this.data.sw; var newRight = Math.range(event.x, this.data.dx + MINIMUM_LOOP_LENGTH, maxRight); this.data.dw = newRight - this.data.dx; } } if(event.mouseUp) { var totalWidth = this.getWidth(); var loopStart = Math.round((this.data.dx / totalWidth) * totalSamples); var loopEnd = Math.round(((this.data.dx + this.data.dw) / totalWidth) * totalSamples); SampleLoadSave.setAndStore(Sampler.LoopStart, loopStart); SampleLoadSave.setAndStore(Sampler.LoopEnd, loopEnd); updateLoopPoints(); } this.repaint(); }); LoopPanel.setPaintRoutine(function(g) { var alpha = 0.2; var h = this.getHeight(); if(this.data.hover) alpha += 0.1; if(this.data.down) alpha += 0.1; var loopColour = Colours.withAlpha(Colours.cornflowerblue, alpha); var sampleColour = Colours.withAlpha(Colours.white, alpha); g.setColour(sampleColour); g.fillRect([this.data.sx, 0, this.data.sw, h]); if(!isDefined(sound)) return; if(sound.get(Sampler.LoopEnabled)) { g.setColour(loopColour); g.fillRect([this.data.dx, 0, this.data.dw, h]); if(this.data.xfw > 0) { var isReversed = Reverse.getValue(); var fadeInRect = [this.data.dx - this.data.xfw, 0, this.data.xfw, h]; var fadeOutRect = [this.data.dx - this.data.xfw + this.data.dw, 0, this.data.xfw, h]; if(isReversed) { fadeInRect[0] += this.data.dw + this.data.xfw; fadeOutRect[0] -= this.data.dw - this.data.xfw; } g.setColour(0x55447788); g.fillPath(isReversed ? fadeOutPath : fadePath, fadeInRect); g.setColour(0x33447788); g.fillPath(fadePath, fadeOutRect); g.fillPath(fadeOutPath, fadeOutRect); } if(this.data.hover) { g.setColour(Colours.withAlpha(loopColour, 1.0)); var handleX = this.data.dx; if(!this.data.setLeft) handleX += this.data.dw - 5; g.fillRect([handleX, 0, 5, h]); } } }); }
-
Thanks, that's definitely closer, but the main issue persists.
The interesting thing, is that this situation does not work, playback does not match up with the loop points. But when you hit REVERSE and then REVERSE again to flip it back to normal... Hurrah, suddenly it works perfectly.
It's very strange. I wonder if I need to raise this as a bug with Hise, because I can't spot what I'm doing wrongly.
-
-
What's really odd is that the functionality for the 'reverse' button aren't visible. I am struggling to find any place where it is actually used to reverse the playback, yet, it mysteriously works.
Perhaps this topic is too advanced for me! I need to learn more about the inner workings of Hise.It would be really nice to get this fixed.
A lot of my Kontakt products involved doing wacky things with sampling, it would be fantastic to get this stuff working in Hise. It all works apart from the loop stuff. I wonder if something changed in Hise to cause this issue, or if the template always had this problem and it just hadn't been tested robustly.Looking at the History, it seems that the Sampler isn't really intended to be used for dynamically controlling for external samples.
-
@griffinboy said in Sample Import Tutorial - It's Broken!:
Looking at the History, it seems that the Sampler isn't really intended to be used for dynamically controlling for external samples.
Yes you're right with that assumption. The priority of the sampler module is to allow high performant streaming of large sample sets and while you can bend it a little bit into the direction of a "creative" sampler tool, it will quickly show its limitations in this regard.
If you really want to go crazy with sample manipulation, I would actually encourage you to dive into the C++ side and create your custom sample playback node (you can get a basic starting point from the file_player and granulator nodes). This might be even a good part 3 of your tutorial series after the filter :)
Also, this:
https://docs.hise.dev/tutorials/scriptnode/index.html#snex-oneshot-player
-
@Christoph-Hart
Thanks for the response, I was hoping to tap into the sampler to make use of the disk streaming and other fancy optimisations, but you are right.
A custom solution will allow for much more direct control over the buffer(s), which will probably be much more beneficial in the long run. -
@griffinboy said in Sample Import Tutorial - It's Broken!:
@Christoph-Hart
Thanks for the response, I was hoping to tap into the sampler to make use of the disk streaming and other fancy optimisations, but you are right.
A custom solution will allow for much more direct control over the buffer(s), which will probably be much more beneficial in the long run.But actually @Christoph-Hart - getting the loop points to work correctly is something I'm really going to need in an up-coming project so sorting this to be consistent would eb a win for me.
-
@Lindon said in Sample Import Tutorial - It's Broken!:
@griffinboy said in Sample Import Tutorial - It's Broken!:
@Christoph-Hart
Thanks for the response, I was hoping to tap into the sampler to make use of the disk streaming and other fancy optimisations, but you are right.
A custom solution will allow for much more direct control over the buffer(s), which will probably be much more beneficial in the long run.But actually @Christoph-Hart - getting the loop points to work correctly is something I'm really going to need in an up-coming project so sorting this to be consistent would eb a win for me.
+1 - I would love to make use of the tutorial project for this as well. as an alternative, adding a crossfade function to the audio loop player would be a great solution
-
In case He doesn't fix it, I'm working on a custom solution now.
I'll upload it when it's working. -
-
Edit, we are halfway there. I've got polyphonic playback with Cubic interpolation.
Working on the looping now.@Christoph-Hart By the way, what are you finding works well for antialising the sampler? I've not written one of these before and I'm wondering if you have a particular method.
I'm guessing interpolation + oversampling then a filter at nyquist then downsampling? As like the first things that can be done. -
@griffinboy actually I‘m doing linear interpolation with no oversampling on most sample playback algorithms. Yes there is a drastic difference if you look for it with artificial signals and a high repitch ratio but for the usual use case it‘s not worth the performance IMHO.
Don‘t bother about oversampling (you can always wrap your node later), but if you‘re using the index classes from SNEX then you can just swap linear and hermite and check the difference between linear and cubic interpolation.
-
@Christoph-Hart
Uh oh! In that case I must be doing something badly because I'm getting worse aliasing than you, with more advanced interpolation
I was getting it so bad I even tried windowed sinc AND oversampling.
Back to the drawing board then.Edit: Fixed it, thanks that was helpful to know. I'm getting almost no visible aliasing now. I can probably back off it a bunch. No wonder I couldn't find any articles online about antialiasing samplers. I was surprised if it was such an issue xD