public void append(double[] left, double[] right, int length)
 {
     while (RateConvertContext.convert(mContext, left, right, length))
     {
         mReceiver.append(mContext.bufferLeft, mContext.bufferRight, mContext.length);
     }
 }
        /// <summary>
        /// コンストラクタ.変換後のサンプリング周波数は,receiverのgetSampleRate()で自動的に取得される
        /// </summary>
        /// <param name="receiver">変換した波形を送る相手先</param>
        /// <param name="sample_rate">変換前のサンプリング周波数</param>
        public WaveRateConvertAdapter(IWaveReceiver receiver, int sample_rate)
        {
            mReceiver = receiver;
            int rate_from = sample_rate;
            int rate_to   = receiver.getSampleRate();

            try {
                mContext = new RateConvertContext(rate_from, rate_to);
            } catch (Exception ex) {
                mContext = null; // m9(@q@)
            }
        }
 /// <summary>
 /// 次にlengthサンプル分のデータを処理した時,結果として得られる変換データのサンプル数を計算します
 /// </summary>
 /// <param name="context"></param>
 /// <param name="length"></param>
 /// <returns></returns>
 public static int estimateResultSamples(RateConvertContext context, int length)
 {
     if (context.aRate == context.bRate)
     {
         // 変換を行わなくてもいい場合
         return(length);
     }
     else
     {
         // 変換しなくちゃならん
         long astart = context.aEnd + 1;
         long aend   = calculateNextEnd(context, length);
         return((int)(aend - astart + 1));
     }
 }
        private static long calculateNextEnd(RateConvertContext context, int length)
        {
            double secStart = context.bCount * context.invBRate;
            double secEnd   = (context.bCount + length - 1) * context.invBRate;

            // 送られてきたデータで、aStartからaEndまでのデータを作成できる
            long next_astart = context.aEnd + 1;// (long)(context.secStart * context.aRate);
            long next_aend   = (long)(secEnd * context.aRate);

            double tx         = next_aend * context.invARate;
            long   btRequired = (long)(tx * context.bRate);
            int    tindx1     = (int)(btRequired - context.bCount) + 1;

            if (tindx1 >= length)
            {
                next_aend--;
            }
            return(next_aend);
        }
        public static void run()
        {
            string    dir    = System.Windows.Forms.Application.StartupPath;
            const int LEN    = 100000;
            const int BUFLEN = 1000;
            // 元データのサンプルレート
            int rate_from = 48000;
            // 変換するサンプルレート
            int rate_to = 44100;
            // 何ヘルツの音のサイン波を作るか
            const double hz = 440.0;
            // 周期
            double             period = 1.0 / hz;
            RateConvertContext c      = new RateConvertContext(rate_from, rate_to);

            double[] left    = new double[BUFLEN];
            double[] right   = new double[BUFLEN];
            int      j       = 0;
            int      total_s = 0;
            int      total_d = 0;

            using (System.IO.StreamWriter sw_src = new System.IO.StreamWriter(System.IO.Path.Combine(dir, "TestRateConvertContext_src.txt")))
                using (System.IO.StreamWriter sw_dst = new System.IO.StreamWriter(System.IO.Path.Combine(dir, "TestRateConvertContext_dst.txt"))) {
                    for (int i = 0; i < LEN; i++)
                    {
                        double x = i / (double)rate_from;
                        double y = Math.Sin(2.0 * Math.PI * x / period);
                        left[j]  = y;
                        right[j] = y;
                        j++;
                        if (j >= BUFLEN)
                        {
                            // srcログに時系列データを書き込み
                            for (int k = 0; k < BUFLEN; k++)
                            {
                                double sx = total_s / (double)rate_from;
                                sw_src.WriteLine(sx + "\t" + left[k]);
                                total_s++;
                            }
                            while (RateConvertContext.convert(c, left, right, j))
                            {
                                for (int k = 0; k < c.length; k++)
                                {
                                    double dx = total_d / (double)rate_to;
                                    sw_dst.WriteLine(dx + "\t" + c.bufferRight[k]);
                                    total_d++;
                                }
                            }
                            j = 0;
                        }
                    }
                    if (j > 0)
                    {
                        // srcログに時系列データを書き込み
                        for (int k = 0; k < BUFLEN; k++)
                        {
                            double sx = total_s / (double)rate_from;
                            sw_src.WriteLine(sx + "\t" + left[k]);
                            total_s++;
                        }
                        while (RateConvertContext.convert(c, left, right, j))
                        {
                            for (int k = 0; k < c.length; k++)
                            {
                                double dx = total_d / (double)rate_to;
                                sw_dst.WriteLine(dx + "\t" + c.bufferRight[k]);
                                total_d++;
                            }
                        }
                    }
                }
        }
        /// <summary>
        /// 変換を実行する.変換結果は,context.aBufSendLeft, aBufSendRightに格納される.
        /// 変換後のデータの長さはaBufSendLengthに格納される.
        /// 戻り値がfalseの場合,もう一度convertを呼ぶ必要はない.
        /// 戻り値がtrueの場合,変換後のデータがaBufSendLeftなどに入りきらない場合なので,続けてもう一度convertを呼ばなくてはならない.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="length"></param>
        public static bool convert(RateConvertContext context, double[] left, double[] right, int length)
        {
            if (context.mStatus == Status.COMPLETE)
            {
                context.length  = 0;
                context.mStatus = Status.NORMAL;
                return(false);
            }

            // 変換前後で周波数が同じ,という指定の場合
            if (context.aRate == context.bRate)
            {
                if (context.mStatus == Status.NORMAL)
                {
                    context.a      = context.aCount;
                    context.aStart = context.aCount;
                    context.aEnd   = context.aCount + length;
                }
                int i      = 0;
                int offset = (int)(context.a - context.aStart);
                for (; context.a < context.aEnd; context.a++)
                {
                    context.bufferLeft[i]  = left[i + offset];
                    context.bufferRight[i] = right[i + offset];

                    i++;
                    if (i >= BUFLEN)
                    {
                        context.length  = BUFLEN;
                        context.mStatus = Status.CONTINUE;
                        return(true);
                    }
                }

                context.length  = i;
                context.aCount += length;
                context.bCount += length;
                context.mStatus = Status.COMPLETE;
                return(true);
            }
            else
            {
                if (context.mStatus == Status.NORMAL)
                {
                    // 送られてきたデータで、aStartからaEndまでのデータを作成できる
                    context.aStart = context.aEnd + 1;
                    context.aEnd   = calculateNextEnd(context, length);//
                    context.a      = context.aStart;
                }

                int i = 0;
                for (; context.a <= context.aEnd; context.a++)
                {
                    double x         = context.a * context.invARate;
                    long   bRequired = (long)(x * context.bRate);
                    double x0        = bRequired * context.invBRate;
                    double x1        = (bRequired + 1) * context.invBRate;
                    int    indx0     = (int)(bRequired - context.bCount);
                    int    indx1     = indx0 + 1;

                    // 左チャンネル
                    double y0 = 0.0;
                    if (0 <= indx0)
                    {
                        if (indx0 < length)
                        {
                            y0 = left[indx0];
                        }
                    }
                    else
                    {
                        int j = (int)(bRequired - context.bBufBase);
                        if (0 <= j && j < context.bBufLeft.Length)
                        {
                            y0 = context.bBufLeft[j];
                        }
                    }
                    double y1 = 0.0;
                    if (indx1 >= 0)
                    {
                        if (indx1 < length)
                        {
                            y1 = left[indx1];
                        }
                    }
                    else
                    {
                        int j = (int)(bRequired + 1 - context.bBufBase);
                        if (0 <= j && j < context.bBufLeft.Length)
                        {
                            y1 = context.bBufLeft[j];
                        }
                    }
                    double s = (y1 - y0) / (x1 - x0);
                    double y = y0 + s * (x - x0);
                    context.bufferLeft[i] = y;

                    // 右チャンネル
                    if (indx0 >= 0)
                    {
                        if (indx0 < length)
                        {
                            y0 = right[indx0];
                        }
                    }
                    else
                    {
                        int j = (int)(bRequired - context.bBufBase);
                        if (0 <= j && j < context.bBufRight.Length)
                        {
                            y0 = context.bBufRight[j];
                        }
                    }
                    if (indx1 >= 0)
                    {
                        if (indx1 < length)
                        {
                            y1 = right[indx1];
                        }
                    }
                    else
                    {
                        int j = (int)(bRequired + 1 - context.bBufBase);
                        if (0 <= j && j < context.bBufRight.Length)
                        {
                            y1 = context.bBufRight[j];
                        }
                    }
                    s = (y1 - y0) / (x1 - x0);
                    y = y0 + s * (x - x0);
                    context.bufferRight[i] = y;

                    // 事後処理
                    i++;
                    if (i >= BUFLEN)
                    {
                        // バッファがいっぱいだったら送信
                        context.length  = BUFLEN;
                        context.mStatus = Status.CONTINUE;
                        context.a++;
                        return(true);
                    }
                }

                // 未送信のバッファがあれば送信
                context.length = i;

                // 次回に繰り越すデータを確保
                // 次に送られてくるデータはbCount + length + 1から
                long aNext = (long)((context.bCount + length + 1) * context.invBRate * context.aRate) + 1;
                //long aNext = (long)((context.bCount + length + 1) * context.invBRate * context.aRate);
                if (context.aEnd + 1 < aNext)
                {
                    context.bBufBase = (long)((context.aEnd + 1) * context.invARate * context.bRate) - 2; // aEnd + 1番目のデータを作成するのに必要なデータ点のインデクス
                    int num = (int)(context.bCount + length - context.bBufBase);
                    if (num > 0)
                    {
                        if (context.bBufLeft == null)
                        {
                            context.bBufLeft = new double[num];
                        }
                        else if (context.bBufLeft.Length < num)
                        {
                            Array.Resize(ref context.bBufLeft, num);
                        }
                        if (context.bBufRight == null)
                        {
                            context.bBufRight = new double[num];
                        }
                        else if (context.bBufRight.Length < num)
                        {
                            Array.Resize(ref context.bBufRight, num);
                        }
                        for (int j = 0; j < num; j++)
                        {
                            int indx = (int)(context.bBufBase + j - context.bCount);
                            context.bBufLeft[j]  = left[indx];
                            context.bBufRight[j] = right[indx];
                        }
                    }
                }

                context.bCount += length;
                context.aCount  = context.aEnd;
                context.mStatus = Status.COMPLETE;
                return(true);
            }
        }