<?xml version="1.0" encoding="UTF-8"?>
	<rss version="2.0"
		xmlns:content="http://purl.org/rss/1.0/modules/content/"
		xmlns:wfw="http://wellformedweb.org/CommentAPI/"
		xmlns:dc="http://purl.org/dc/elements/1.1/"
		xmlns:atom="http://www.w3.org/2005/Atom"

			>

	<channel>
		<title>Cycling 74  &#187;  Topic: Writing a sinc-interpolating playback object</title>
		<atom:link href="http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/feed" rel="self" type="application/rss+xml" />
		<link>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/feed</link>
		<description></description>
		<pubDate>Wed, 19 Jun 2013 12:12:34 +0000</pubDate>
		<generator>http://bbpress.org/?v=2.2.4</generator>
		<language></language>

		
														
					
				<item>
					<guid>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/#post-59236</guid>
					<title><![CDATA[Writing a sinc-interpolating playback object]]></title>
					<link>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/#post-59236</link>
					<pubDate>Mon, 10 Oct 2011 14:03:50 +0000</pubDate>
					<dc:creator>christripledot</dc:creator>

					<description>
						<![CDATA[
						<p>Hello,</p>
<p>After a lot of reading and head-scratching, I&#8217;ve begun to write a sample playback engine using windowed sinc interpolation. The idea is, it will work a bit like [groove~] (taking a signal to determine playback speed), but it will be click-triggerable and have built-in ADSRs and a variety of looping options.</p>
<p>The ADSR and loop logic is all done, but the interpolator is giving me grief. Maybe somebody on here is savvy enough to see where I&#8217;m going wrong&#8230;</p>
<p>When I pass integer values into my &#8220;interp(playhead)&#8221; function, everything is hunky-dory. But when I pass fractional values I get hideous ringing and the interpolated values are WAY off.</p>
<p>First off, I populate a table with the right-hand wing of a sinc function. I then multiply this table with the right-hand wing of a windowing function (Blackman-Harris in my case). I&#8217;m pretty damn sure that I&#8217;m populating and windowing my table correctly. There are (SINC_POINTS + 1) lobes in it.</p>
<p>Here is my naive implementation so far:</p>
<pre><code>#define SINC_RES 512   // resolution of each lobe of the sinc table
#define SINC_POINTS 16 // number of samples to use for interpolation
                       // on either side of the sample in question

float interp(double playhead) {

  long playheadint = floor(playhead);
  double playheadfrac = playhead - playheadint;

  double accum = 0.0;

  // Loop through every sample we&#39;re interested in...
  int i;
  for(i = -SINC_POINTS; i < SINC_POINTS + 1; i ++) {

    long thissample = playheadint + i;

    //  HACK: To handle start and end points,
    //  we just duplicate the start and end samples.
    //  POSSIBLE FIX: mirror start/end of input?
    if(thissample < 0) thissample = 0;
    if(thissample >= frames) thissample = frames - 1;

    double moo = samplebuffer[thissample];

    // Get index into sinc table
    // This could be moved outside the loop but it&#39;s left here for clarity
    long sincindex = round(playheadfrac * SINC_RES);

    // Offset index relative to centre sample
    sincindex += abs(i) * SINC_RES;

    moo *= sinctable[sincindex];
    accum += moo;
  }

  return (float)accum;
}</code></pre><p>If anybody can help figure out where I&#8217;m going wrong, I&#8217;d be extremely grateful. Here&#8217;s what I&#8217;m trying to do:</p>
<p>1. Conceptually, replace each input sample with a sinc function.<br />
2. Take the fractional part of my desired &#8216;sub-sample&#8217; and scale this so it can be used as an offset into the first (or main) lobe of the sinc function.<br />
3. Take the relevant value from the sinc function and multiply this by the input sample (as determined by the integer part).<br />
4. Do the same for an arbitrary number of samples on either side of the sample we&#8217;re interested in, but offset the index into the sinc function accordingly; i.e. if we&#8217;re looking at one sample away from the main sample, we have to offset the sinc function index by one zero-crossing.<br />
5. Sum the results of the above table lookups.</p>
<p>Is this the right approach? I think my code above reflects this, but maybe I&#8217;ve just gone code-blind&#8230; </p>
<p>P.S. Maybe I should mention that the eventual goal for this is to create a vari-speed sample player. I don&#8217;t think this ought to affect the results of my simple function, but perhaps there are other issues to worry about further down the line? Some of the source I&#8217;ve seen for resampling libraries processes the source in chunks, rather than updating on a per-sample basis. However, I suspect this may be for performance reasons. For now I&#8217;d just like a slow-but-easy-to-follow piece of code that works&#8230;</p>
<p>If debugging the above is too much of an ask, does anyone have a similar interpolation function they wouldn&#8217;t mind sharing? One that reports the interpolated value at an arbitrary location in an input buffer?</p>
<p>Thanks for looking,</p>
<p>Chris</p>
						]]>
					</description>

					
					
				</item>

			
				<item>
					<guid>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/#post-212836</guid>
					<title><![CDATA[Re: Writing a sinc-interpolating playback object]]></title>
					<link>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/#post-212836</link>
					<pubDate>Mon, 10 Oct 2011 16:50:06 +0000</pubDate>
					<dc:creator>Timothy Place</dc:creator>

					<description>
						<![CDATA[
						<p>I haven&#8217;t looked at the details of your code to know exactly what might be going wrong, but I will mention that in Max 6 you can have a sinc-based interpolation in the groove~ object by turning on a new @resample attribute.  FWIW, in our case we are windowing the sinc with a Kaiser function.</p>
<p>There are also some features in buffer~ to make generating the sinc and windowing it super-easy.</p>
<p>We generally aren&#8217;t sharing Max 6 details just yet, but will be sharing more soon.  I thought I&#8217;d give you a heads-up given that it may impact your (really interesting and cool!) project.</p>
<p>Cheers,<br />
  Tim</p>
						]]>
					</description>

					
					
				</item>

			
				<item>
					<guid>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/#post-212837</guid>
					<title><![CDATA[Re: Writing a sinc-interpolating playback object]]></title>
					<link>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/#post-212837</link>
					<pubDate>Mon, 10 Oct 2011 17:44:42 +0000</pubDate>
					<dc:creator>christripledot</dc:creator>

					<description>
						<![CDATA[
						<p>Thanks, Tim! That&#8217;s wicked news.</p>
<p>I&#8217;m still hoping someone with more knowledge than me might chime in though, &#8216;cos I&#8217;d like to trigger this at audio rate, and I&#8217;m interested in more advanced looping than groove~ currently offers (fwd, reverse, pingpong). I&#8217;ll share once I&#8217;ve got to the bottom of this! :)</p>
						]]>
					</description>

					
					
				</item>

			
				<item>
					<guid>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/#post-212838</guid>
					<title><![CDATA[Re: Writing a sinc-interpolating playback object]]></title>
					<link>http://cycling74.com/forums/topic/writing-a-sinc-interpolating-playback-object/#post-212838</link>
					<pubDate>Tue, 11 Oct 2011 13:35:07 +0000</pubDate>
					<dc:creator>christripledot</dc:creator>

					<description>
						<![CDATA[
						<p>A kind soul pointed out my error. Because I&#8217;m only using half a sinc function to save memory, I&#8217;m mirroring the index into the table. But I was only mirroring the integer part of the index.</p>
<p>This is the offending line:</p>
<pre><code>// Offset index relative to centre sample
sincindex += abs(i) * SINC_RES;</code></pre><p>It should be:</p>
<p><code>sincindex = abs(sincindex - (i * SINC_RES));</code></p>
<p>I can&#8217;t test at work, but I think that&#8217;s cracked it. I&#8217;ll share the external once it&#8217;s tidied up a bit.</p>
						]]>
					</description>

					
					
				</item>

					
		
	</channel>
	</rss>

