Exemple #1
0
        static void play(string bpcmfile, float volume, double rate, int output_device = 0, bool enDither = true)
        {
            Console.WriteLine("{0,-20} {1}", "File path:", new FileInfo(bpcmfile).Directory.FullName);
            Console.WriteLine("{0,-20} {1}", "File name:", new FileInfo(bpcmfile).Name);

            //Analyse stream
            FileStream s = new FileStream(bpcmfile, FileMode.Open, FileAccess.Read, FileShare.Read, 1048576, false);

            void AnalyisisProgress(float percentDone)
            {
                Console.CursorLeft = 0;
                Console.Write(String.Concat(Enumerable.Repeat(" ", Console.BufferWidth - 1)));
                Console.CursorLeft = 0;
                Console.Write("{0,-20} {1, -4:0.00} percent done.", "Analyzing file:", percentDone);
            }

            BitstreamReader p = new BitstreamReader(s, aupevt: AnalyisisProgress);

            p.EnableDither = enDither;

            Console.CursorLeft = 0;
            Console.Write(String.Concat(Enumerable.Repeat(" ", Console.BufferWidth - 1)));
            Console.CursorLeft = 0;

            //Print info
            Console.WriteLine("{0,-20} {1}", "File size:", Helpers.ByteFormatter.FormatBytes(s.Length));
            printInfo(p.Analysis);
            Console.WriteLine(String.Concat(Enumerable.Repeat("\x2509", 80)));

            //Box line and corner as well as connection chars
            const string strFcF = "\x250C", strFc7 = "\x2510", strFcL = "\x2514", strFcJ = "\x2518"
            , strFbI = "\x2502", strFbL = "\x2500", strFbT = "\x252C", strFbUMT = "\x2534"
            , strFbLT = "\x251C", strFbMMT = "\x253C", strFbRT = "\x2524", strAUD = "\x2195", strALR = "\x2194";

            //VU meter chars
            string[,] arrVU = { { " ", "\x2580" }, { " ", "\x2584" } };
            //string[,] arrVU = { { " ", "\x25AE" }, { " ", "\x25AE" } };

            int nBuffers = 16;
            int fnumLen  = p.Analysis.FrameSet.Count.ToString().Length;

            if (fnumLen < 6)
            {
                fnumLen = 6;
            }
            int    currFrame = 0;
            double currTS    = 0;

            double           speed    = rate;
            bool             dontExit = false;
            WaveOutEvent     wavOut;
            BPCMWaveProvider bpcmWP = new BPCMWaveProvider(p, speed);

            //Prepare lines
            string strTsLine = String.Concat(Enumerable.Repeat(strFbL, 22))
            , strFNumLine    = String.Concat(Enumerable.Repeat(strFbL, fnumLen))
            , strBitRateLine = String.Concat(Enumerable.Repeat(strFbL, 6))
            , strComprLine   = String.Concat(Enumerable.Repeat(strFbL, 10))
            , strVolumeLine  = String.Concat(Enumerable.Repeat(strFbL, 6))
            , strRateLine    = String.Concat(Enumerable.Repeat(strFbL, 5))
            , strVULine      = String.Concat(Enumerable.Repeat(strFbL, 58))
            , strVUScale     = "-\x221e\x2508"
                               + "-60" + string.Concat(Enumerable.Repeat("\x2508", 6))
                               + "-50" + string.Concat(Enumerable.Repeat("\x2508", 6))
                               + "-40" + string.Concat(Enumerable.Repeat("\x2508", 7))
                               + "-30" + string.Concat(Enumerable.Repeat("\x2508", 6))
                               + "-20" + string.Concat(Enumerable.Repeat("\x2508", 4))
                               + "-12" + string.Concat(Enumerable.Repeat("\x2508", 2))
                               + "-6\x2508-3\x25080"
            , strVUBlank = String.Concat(Enumerable.Repeat(" ", 58));


            void readDone(Frame CurrentFrame)
            {
                currFrame = CurrentFrame.FrameNumber;
                ADPCM.ADPCM4BIT.VolumeInfo vi = CurrentFrame.VolumeInfo;

                currTS = CurrentFrame.TimeStamp;
                TimeSpan tsnPos = TimeSpan.FromSeconds(currTS);
                int      days   = tsnPos.Days; if (days > 9)
                {
                    days = 9;                                   //Clamp days never to be more than 9.
                }
                string strPos = String.Format("{0}d {1:00}h {2:00}m {3:00}s {4:000}ms", days, tsnPos.Hours, tsnPos.Minutes, tsnPos.Seconds, tsnPos.Milliseconds);

                //Debug.WriteLine(strPos);

                //Refresh the status line
                Console.CursorLeft = 0;
                Console.Write(strFbI + strALR + "{0,21}" + strFbI + "{1," + fnumLen + "}" + strFbI + "{2,6}" + strFbI + "{3,-10}" + strFbI + strAUD + "{4,4}%" + strFbI + "x{5,4}" + strFbI,
                              strPos, currFrame + 1, Math.Round(((CurrentFrame.DataLength + CurrentFrame.HederLength) / CurrentFrame.Duration) * 8, 0), CurrentFrame.CompressionTypeDescr, Math.Round(wavOut.Volume * 100, 1), speed);

                //Calculate bar length from dB value.
                const int max = 57, lowpoint = 62; //lowpoint is the positive value of the minus dB the scale will start
                int       L = (int)Math.Round(((vi.dbPeakL + lowpoint) / lowpoint) * max);

                if (L < 0)
                {
                    L = 0;        //clamp
                }
                int R = (int)Math.Round(((vi.dbPeakR + lowpoint) / lowpoint) * max);

                if (R < 0)
                {
                    R = 0;        //clamp
                }
                string strVUMeterL = arrVU[0, 1] + String.Concat(Enumerable.Repeat(arrVU[0, 1], L)) + String.Concat(Enumerable.Repeat(arrVU[0, 0], max - L));
                string strVUMeterR = arrVU[1, 1] + String.Concat(Enumerable.Repeat(arrVU[1, 1], R)) + String.Concat(Enumerable.Repeat(arrVU[1, 0], max - R));

                Console.CursorLeft = 0;
                Console.CursorTop += 2;
                Console.WriteLine(strFbI + "L " + strVUMeterL + strFbI);

                Console.CursorLeft = 0;
                Console.CursorTop += 1;
                Console.WriteLine(strFbI + "R " + strVUMeterR + strFbI);

                Console.CursorLeft = 0;
                Console.CursorTop -= 5;
            }

            void woutInit()
            {
                wavOut = new WaveOutEvent();
                wavOut.DeviceNumber     = output_device;
                wavOut.DesiredLatency   = 100 * wavOut.NumberOfBuffers;
                wavOut.PlaybackStopped += stopped;
                wavOut.Init(bpcmWP);
                wavOut.Volume         = volume;
                nBuffers              = wavOut.NumberOfBuffers;
                Console.CursorVisible = false;
            }

            woutInit();

            bpcmWP.readDone = readDone;
            bpcmWP.volume   = 1;

            void changeRate()
            {
                if (WaveOut.GetCapabilities(wavOut.DeviceNumber).SupportsPlaybackRateControl&& 1 == 2)
                {
                    wavOut.Rate = (float)speed;
                }
                else
                {
                    reinitBPCMWaveSrc();
                }
            }

            void reinitBPCMWaveSrc()
            {
                dontExit = true;
                volume   = wavOut.Volume;
                wavOut.Stop();
                wavOut.Dispose();
                wavOut = null;
                bpcmWP = null;
                GC.Collect();
                bpcmWP          = new BPCMWaveProvider(p, speed);
                bpcmWP.volume   = 1;
                bpcmWP.readDone = readDone;
                p.Seek(currFrame - 1); //fix for skipping
                woutInit();
                wavOut.Play();
            }

            string DeviceName = "";

            for (int x = 0; x < WaveOut.DeviceCount; x++)
            {
                if (x == wavOut.DeviceNumber)
                {
                    DeviceName = "[" + x + "] " + WaveOut.GetCapabilities(x).ProductName;
                    break;
                }
            }

            //Playback stopped event handler method
            void stopped(object sender, StoppedEventArgs e)
            {
                if (!dontExit)
                {
                    exitNow();
                }
                else
                {
                    dontExit = false;
                }
            }

            //Drawing status box
            Console.WriteLine("{0,-20} {1}", "Playing on:", DeviceName);
            Console.WriteLine("");

            //Upper corner of box
            Console.WriteLine(strFcF + strTsLine + strFbT + strFNumLine + strFbT + strBitRateLine + strFbT + strComprLine + strFbT + strVolumeLine + strFbT + strRateLine + strFc7);
            //Descriptions
            Console.WriteLine(strFbI + "{0,-22}" + strFbI + "{1,-" + fnumLen + "}" + strFbI + "{2,6}" + strFbI + "{3,-10}" + strFbI + "{4,-6}" + strFbI + "{5,-5}" + strFbI, "timestamp", "frame#", "bit/s", "compr.", "volume", "rate");
            //Divider lines
            Console.WriteLine(strFbLT + strTsLine + strFbMMT + strFNumLine + strFbMMT + strBitRateLine + strFbMMT + strComprLine + strFbMMT + strVolumeLine + strFbMMT + strRateLine + strFbRT);
            //Status line (empty here)
            Console.WriteLine(strFbI + strALR + "{0,21}" + strFbI + "{1," + fnumLen + "}" + strFbI + "{2,6}" + strFbI + "{3,-10}" + strFbI + strAUD + "{4,4}%" + strFbI + "{5,5}" + strFbI, "N/A", "N/A", "N/A", "N/A", "N/A", "N/A");
            //Bottom corner of box
            Console.WriteLine(strFbLT + strTsLine + strFbUMT + strFNumLine + strFbUMT + strBitRateLine + strFbUMT + strComprLine + strFbUMT + strVolumeLine + strFbUMT + strRateLine + strFbRT);

            //VU top
            //Console.WriteLine(strFcF + strFbL + strFbL + strVULine + strFc7);
            Console.WriteLine(strFbI + "L " + strVUBlank + strFbI);
            //VU middle
            Console.WriteLine(strFbI + " " + strVUScale + strFbI);
            Console.WriteLine(strFbI + "R " + strVUBlank + strFbI);
            //VU bottom
            Console.WriteLine(strFcL + strFbL + strFbL + strVULine + strFcJ);

            Console.WriteLine("");
            Console.WriteLine("Volume:  Up/Down 1% steps, Hold CTRL 0.1% steps, PgUp/PgDwn 10% steps");
            Console.WriteLine("Seeking: Left/Right 5 secs, Hold CTRL 1 sec steps, Home for beginning");
            Console.WriteLine("Speed:   S, D and F. You'll figure it out. ;) You can also use CTRL!");

            //Set cursor top position to the status line.
            Console.CursorTop -= 10;



            bool exit = false;

            void exitNow()
            {
                try
                {
                    Console.CursorTop    += 10;
                    Console.CursorLeft    = 0;
                    Console.CursorVisible = true;
                    wavOut?.Dispose();
                    p = null;
                } catch
                {
                }
                Environment.Exit(0);
            }

            //Start playback
            wavOut.Play();

            //Crude key scanning
            while (!exit)
            {
                ConsoleKeyInfo key = Console.ReadKey(true);
                switch (key.Modifiers)
                {
                case ConsoleModifiers.Control:
                    switch (key.Key)
                    {
                    case ConsoleKey.UpArrow:
                    case ConsoleKey.VolumeUp:
                        if (wavOut.Volume + 0.001f >= 1.0f)
                        {
                            wavOut.Volume = 1.0f;
                        }
                        else
                        {
                            wavOut.Volume += 0.001f;
                        }
                        break;

                    case ConsoleKey.DownArrow:
                    case ConsoleKey.VolumeDown:
                        if (wavOut.Volume - 0.001f <= 0.0f)
                        {
                            wavOut.Volume = 0.0f;
                        }
                        else
                        {
                            wavOut.Volume -= 0.001f;
                        }
                        break;

                    case ConsoleKey.LeftArrow:
                        p.Seek(currTS - 1);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.RightArrow:
                        p.Seek(currTS + 1);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.S:
                        if (speed - 0.01 <= 0.01f)
                        {
                            speed = 0.01;
                        }
                        else
                        {
                            speed -= 0.01;
                        }
                        changeRate();
                        break;

                    case ConsoleKey.F:
                        if (speed + 0.01 >= 4.0f)
                        {
                            speed = 4.0;
                        }
                        else
                        {
                            speed += 0.01;
                        }
                        changeRate();
                        break;
                    }
                    break;

                default:
                    switch (key.Key)
                    {
                    case ConsoleKey.UpArrow:
                    case ConsoleKey.VolumeUp:
                        if (wavOut.Volume + 0.01f >= 1.0f)
                        {
                            wavOut.Volume = 1.0f;
                        }
                        else
                        {
                            wavOut.Volume += 0.01f;
                        }
                        break;

                    case ConsoleKey.DownArrow:
                    case ConsoleKey.VolumeDown:
                        if (wavOut.Volume - 0.01f <= 0.0f)
                        {
                            wavOut.Volume = 0.0f;
                        }
                        else
                        {
                            wavOut.Volume -= 0.01f;
                        }
                        break;

                    case ConsoleKey.PageUp:
                        if (wavOut.Volume + 0.1f >= 1.0f)
                        {
                            wavOut.Volume = 1.0f;
                        }
                        else
                        {
                            wavOut.Volume += 0.1f;
                        }
                        break;

                    case ConsoleKey.PageDown:
                        if (wavOut.Volume - 0.1f <= 0.0f)
                        {
                            wavOut.Volume = 0.0f;
                        }
                        else
                        {
                            wavOut.Volume -= 0.1f;
                        }
                        break;

                    case ConsoleKey.LeftArrow:
                        p.Seek(currTS - 5d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.RightArrow:
                        p.Seek(currTS + 5d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D1:
                        p.Seek(60d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D2:
                        p.Seek(120d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D3:
                        p.Seek(180d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D4:
                        p.Seek(240d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D5:
                        p.Seek(300d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D6:
                        p.Seek(360d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D7:
                        p.Seek(420d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D8:
                        p.Seek(480d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D9:
                        p.Seek(540d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.D0:
                        p.Seek(600d);
                        bpcmWP.DropRingBuffer();
                        break;

                    case ConsoleKey.S:
                        if (speed - 0.1 <= 0.01f)
                        {
                            speed = 0.01;
                        }
                        else
                        {
                            speed -= 0.1;
                        }
                        changeRate();
                        break;

                    case ConsoleKey.D:
                        speed = 1f;
                        changeRate();
                        break;

                    case ConsoleKey.F:
                        if (speed + 0.1 >= 4.0f)
                        {
                            speed = 4.0;
                        }
                        else
                        {
                            speed += 0.1;
                        }
                        changeRate();
                        break;

                    case ConsoleKey.Home:
                        p.Seek(0);
                        break;

                    case ConsoleKey.Spacebar:
                        switch (wavOut.PlaybackState)
                        {
                        case PlaybackState.Playing:
                            wavOut.Pause();
                            break;

                        case PlaybackState.Paused:
                            wavOut.Play();
                            break;
                        }
                        break;

                    case ConsoleKey.Escape:
                    case ConsoleKey.Q:
                        Console.CursorTop -= 10;
                        exitNow();
                        break;
                    }
                    break;
                }
            }
            p = null;
        }
Exemple #2
0
        public byte[] decode(byte[] adpcmIn, out ADPCM4BIT.VolumeInfo vi, bool enableInloopVolumeStats, float volume = 1f)
        {
            uint i, pO;

            byte[] Output = new byte[(adpcmIn.Length - 3) * 4];

            int t;
            int sign;      // Current adpcm sign bit
            int delta;     // Current adpcm output value Mid
            int step;      // Stepsize
            int valprev;   // virtual previous output value Mid
            int vpdiff;    // Current change to valprev Side
            int index;     // Current step change index Mid
            int bitbuffer; // place to keep next 4-bit value

            uint pv = 0;   //peak volume
            uint av = 0;   //average volume

            vi         = new ADPCM4BIT.VolumeInfo();
            vi.dbPeakL = double.NegativeInfinity;
            vi.dbPeakR = double.NegativeInfinity;
            vi.dbAvgL  = double.NegativeInfinity;
            vi.dbAvgR  = double.NegativeInfinity;

            try
            {
                valprev = BitConverter.ToInt16(adpcmIn, 0);

                index = adpcmIn[2];
                step  = stepsizeTable[index];

                for (i = 3; i <= adpcmIn.Length - 1; i++)
                {
                    pO = (i - 3) * 4;

                    //**** Step 1 - get the delta value
                    bitbuffer = adpcmIn[i];
                    delta     = bitbuffer >> 4;

                    //**** Step 2 - Find new index value (for later)
                    index += indexTable[delta];
                    if (index < 0)
                    {
                        index = 0;
                    }
                    else if (index > 88)
                    {
                        index = 88;
                    }

                    //**** Step 3 - Separate sign and magnitude
                    sign  = delta & 8;
                    delta = delta & 7;

                    //**** Step 4 - update output value
                    vpdiff = (delta * step) >> 2;
                    if (sign == 8)
                    {
                        valprev -= vpdiff;
                    }
                    else
                    {
                        valprev += vpdiff;
                    }

                    //**** Step 5 - clamp output value
                    if (valprev > short.MaxValue)
                    {
                        valprev = short.MaxValue;
                    }
                    else if (valprev < short.MinValue)
                    {
                        valprev = short.MinValue;
                    }

                    //**** Step 6 - Update step value
                    step = stepsizeTable[index];

                    //Volume processing (crude but it works!!)
                    t = valprev;
                    if (volume != 1)
                    {
                        t = (int)Math.Round(t * volume, 0);
                    }

                    if (t < Int16.MinValue)
                    {
                        t = Int16.MinValue;
                    }
                    if (t > Int16.MaxValue)
                    {
                        t = Int16.MaxValue;
                    }
                    BitConverter.GetBytes((short)t).CopyTo(Output, pO);

                    //NEXT SAMPLE

                    //**** Step 1 - get the delta value
                    delta = bitbuffer & 0xF;

                    //**** Step 2 - Find new index value (for later)
                    index += indexTable[delta];
                    if (index < 0)
                    {
                        index = 0;
                    }
                    else if (index > 88)
                    {
                        index = 88;
                    }

                    //**** Step 3 - Separate sign and magnitude
                    sign  = delta & 8;
                    delta = delta & 7;

                    //**** Step 4 - update output value
                    vpdiff = (delta * step) >> 2;
                    if (sign == 8)
                    {
                        valprev -= vpdiff;
                    }
                    else
                    {
                        valprev += vpdiff;
                    }

                    //**** Step 5 - clamp output value
                    if (valprev > short.MaxValue)
                    {
                        valprev = short.MaxValue;
                    }
                    else if (valprev < short.MinValue)
                    {
                        valprev = short.MinValue;
                    }

                    //**** Step 6 - Update step value
                    step = stepsizeTable[index];
                    t    = valprev;

                    //If desired, do the audio analyisis
                    //Inloop volume analysis!
                    if (enableInloopVolumeStats)
                    {
                        //Converting to absolute value
                        //Abs and conversion may be slow, so we do this once and write it into variables
                        uint tt = (uint)Math.Abs(t);

                        //determine peak value
                        if (pv < tt)
                        {
                            pv = tt;
                        }

                        //calculating average volume
                        av = (uint)Math.Round((av + tt * 2) / 3d);
                    }

                    //Volume processing (crude but it works!!)
                    if (volume != 1)
                    {
                        t = (int)Math.Round(t * volume, 0);
                    }

                    if (t < Int16.MinValue)
                    {
                        t = Int16.MinValue;
                    }
                    if (t > Int16.MaxValue)
                    {
                        t = Int16.MaxValue;
                    }

                    BitConverter.GetBytes((short)t).CopyTo(Output, pO + 2);
                }

                if (enableInloopVolumeStats)
                {
                    vi.dbPeakL = 20 * Math.Log10((double)pv / short.MaxValue);
                    vi.dbPeakR = 20 * Math.Log10((double)pv / short.MaxValue);
                    vi.dbAvgL  = 20 * Math.Log10((double)av / short.MaxValue);
                    vi.dbAvgR  = 20 * Math.Log10((double)av / short.MaxValue);
                }
            }
            catch {  }
            return(Output);
        }