misc/hermite.gp
\\========================================================================================
\\  hermite.gp
\\  Copyright (C) 2003-2019 Makoto Kamada
\\
\\  This file is part of the XEiJ (X68000 Emulator in Java).
\\  You can use, modify and redistribute the XEiJ if the conditions are met.
\\  Read the XEiJ License for more details.
\\  https://stdkmd.net/xeij/
\\========================================================================================

\\エルミート補間
\\p=hermite(a,p,v,x)
\\  x=a[1],...,a[n+1]における位置がp[1],...,p[n+1]速度がv[1],...,v[n+1]のときxにおける位置を求める
hermite(a,p,v,x)={
  my(n=#a-1);
  sum(k=0,n,(1-2*sum(m=0,n,if(m==k,0,1/(a[k+1]-a[m+1])))*(x-a[k+1]))*(prod(m=0,n,if(m==k,1,(x-a[m+1])/(a[k+1]-a[m+1]))))^2*p[k+1])+
    sum(k=0,n,(x-a[k+1])*(prod(m=0,n,if(m==k,1,(x-a[m+1])/(a[k+1]-a[m+1]))))^2*v[k+1])
}
\\p=hermite4(pm,p0,p1,p2,x)
\\  x=-1,0,1,2における位置がpm,p0,p1,p2のとき0<=x<=1における位置を求める
hermite4(pm,p0,p1,p2,x)={
  hermite([0,1],[p0,p1],[(p1-pm)/2,(p2-p0)/2],x)
}
\\hermite_code(s,n)
\\  s   1  モノラル
\\      2  ステレオ
\\  n  16   3906Hz
\\     12   5208Hz
\\      8   7812Hz
\\      6  10416Hz
\\      4  15625Hz
hermite_code(s,n)={
  my(k,d,h,cm,c0,c1,c2,g,e);
  print("        int i = pcmPointer;");
  print("        int mm = pcmDecodedData3;");
  print("        int m0 = pcmDecodedData2;");
  print("        int m1 = pcmDecodedData1;");
  for(j=0,s-1,
      print("        {");
      for(k=1,n,
          d=(2-n%2)*n^3;
          h=hermite4(pm,p0,p1,p2,k/n)*d;
          cm=polcoeff(h,1,pm);
          c0=polcoeff(h,1,p0);
          c1=polcoeff(h,1,p1);
          c2=polcoeff(h,1,p2);
          g=gcd(gcd(gcd(gcd(cm,c0),c1),c2),d);
          cm/=g;
          c0/=g;
          c1/=g;
          c2/=g;
          d/=g;
          e=floor(log(d)/log(2)+0.5);
          if(k==0,
             print1("          //                  "),
             if(k==1&&j==0,
                if(s*n<=10,
                   print1("          pcmBuffer[i    ] = "),
                   print1("          pcmBuffer[i     ] = ")),
                if(s*n<=10,
                   printf("          pcmBuffer[i + %d] = ",s*(k-1)+j),
                   printf("          pcmBuffer[i + %2d] = ",s*(k-1)+j))));
          if(d==1,
             print1("        "),
             if(d==2^e,
                print1("        "),
                print1("(int) ((")));
          if(cm==0,
             print1("          "),
             if(cm==-1,
                print1("       -"),
                printf("%5d * ",cm));
             print1("mm"));
          if(c0==c1,
             printf(" + %4d *      (",c0);
             print1("m0");
             print1(" + ");
             print1("m1");
             print1(")"),
             if(c0==0,
                print1("            "),
                if(cm==0,
                   print1("   "),
                   print1(" + "));
                if(c0==1,
                   print1("       "),
                   printf("%4d * ",c0));
                print1("m0"));
             if(c1==0,
                if(c2!=0,
                   print1("            ")),
                if(cm==0&&c0==0,
                   print1("   "),
                   print1(" + "));
                if(c1==1,
                   print1("       "),
                   printf("%4d * ",c1));
                print1("m1")));
          if(c2==0,
             print1(),
             if(c2==-1,
                print1(" -        "),
                printf(" - %4d * ",-c2));
             print1("m2"));
          if(d==1,
             print1(";"),
             if(d==2^e,
                printf(" >> %2d;",e),
                printf(") * %10dL >> 32);",floor(2^32/d+0.5))));
          print()
          );
      print("        }")
      );
  print("        pcmDecodedData3 = m0;");
  print("        pcmDecodedData2 = m1;");
  print("        pcmDecodedData1 = m2;");
  print("        pcmPointer = i + ",s*n,";")
}