ساختار و کار کردن با فایل ها برای برنامه نویسی

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بر اساس زمانی که الان هست کار انجام میدهند، نه اینکه ترتیبی داده رو با یک نرخ مشخص بخونند. شما وقتی در حالت ترتیبی هر بار N نمونه به جلو پیشرفت می کنید کاری به زمان ندارید، چشم بسته دارید بر اساس یک ترتیبی عمل می کنید که مستقل از زمانه. وقتی در زمان 12.4 هستید باید نمونه ای رو بخونید که در زمان 12.4 بهش میرسه. با زمان فعلی کار کنید، کاری نداشته باشید که چند تا نمونه از دفعه جلوتر رفتید. ببینید الان چقدر زمان از شروع پخش گذشته و نوبت چه نمونه ای شده.

ممنون استاد علی
آها
یعنی هر بار نسبت به زمان شروع ، محاسبه کنم ؛ نه نسبت به دفعه ی قبل اش
ممنون


دقیق؟ هیچ مشخصات دقیقی از پارامتر های دخیل در این مورد رو ندارید که بخواهید رویش زمان دقیقی محاسبه کنید. در ضمن زمان لازم خوندن هدر فایل اهمیت خاصی نداره، وقتی شما یک فایل mp3 رو باز می کنید مدتی طول میکشه تا Player باز بشه و فایل خونده بشه و بعد تازه پخش اش شروع بشه، نه زمان مشخص و ثابتیه و نه اهمیتی داره. خیلی ساده منتظر میشید تا پخش شروع بشه. تازه شما که هم متد مناسب برای Load کردن رو دارید و هم رخداد لازم برای فهمیدن اینکه کی Loading به پایان رسید.

ولی قبل از کد play ، کد load (در همون نخ . یعنی loadAsync نه) را اضافه کردم ولی اصلا منتظر خوندن هدر فایل نمیشه (یا دوباره در کد play ، هدر فایل خونده میشه یا کلا یه مشکلی هست که نمیدونم) :

کد:
            wavPlayer.Load();
            wavPlayer.Play();

اگه منظورتون رویداد LoadCompleted هست ، این رویداد ، بعد ازتمام شدن هدر فایل و زمان خوندن دیتای فایل که اجرا نمیشه (زمان خوندن هدر فایل اجرا میشه) . تازه اونم در شی SoundPlayer اگه پروپرتی Stream شو مقدار بدیم

شما که واقعا کاری به پخش صوت ندارید که بگید صوت تموم شد پس باید یه اتفاقی بیافته، پخش صوت جدا است، پیمایش داده شما جدا. یک داده صوتی رو کند تر از سرعت پخشش پیمایش می کنید و رویش مانور میدید. میتوانید اونقدر کند اینکار رو انجام بدید که خیلی بیشتر طول بکشه ولی این ربطی به زمان عادی پخش که نداره، کند میخونیدش، همین.

نه کند پخش نمیشد
کل زمان آهنگم 406 ثانیه هست
اطلاعات شو که داده بودم :

مشخصات آهنگ ، فرمت wav هه و sample rate 44100 hz و bit depth 16 bite و 2 کانال هه هست و حجم کل فایل 71,769,100 بایت هست به مدت 6 دقیقه و 46 ثانیه (کلا 406 ثانیه)
سودوکدش رو این جوری تحلیل کردم که بیت ریت برای 1 ثانیه اش (1000 میلی ثانیه) میشه :
44,100 * 2 * 2 = 176,400 بایت بر ثانیه
که میشه همون 7056 بایت در هر 40 میلی ثانیه

بنابراین 176,400 * 406 میشه 71,618,400 بایت که حجم کل فایل ام هم 71,769,100 بایت هست که تقریبا 150 کیلوبایت اختلاف شون هم برای هدرش هست و بلکه هم بخاطر میلی ثانیه های اضافی که در آهنگ محاسبه نمیشه
 
آخرین ویرایش:

the_king

مدیرکل انجمن
ولی قبل از کد play ، کد load (در همون نخ . یعنی loadAsync نه) را اضافه کردم ولی اصلا منتظر خوندن هدر فایل نمیشه (یا دوباره در کد play ، هدر فایل خونده میشه یا کلا یه مشکلی هست که نمیدونم) :

کد:
            wavPlayer.Load();
            wavPlayer.Play();

اگه منظورتون رویداد LoadCompleted هست ، این رویداد ، بعد ازتمام شدن هدر فایل و زمان خوندن دیتای فایل که اجرا نمیشه (زمان خوندن هدر فایل اجرا میشه) . تازه اونم در شی SoundPlayer اگه پروپرتی Stream شو مقدار بدیم
زمان خوندن میشه Loading، این رخداد بعد از خاتمه Loading اتفاق می افته، وقتی Completed شده. هیچ جایی اش هم نگفته این رخداد مختص Stream ئه.
Remarks
This event is raised when loading of a .wav file is complete. The event arguments indicate whether the load of the sound was completed successfully or failed
یک همچین کدی رو امتحان کنید و ببینید که LoadCompleted مختص Stream نیست :
کد:
        private void button1_Click(object sender, EventArgs e)
        {
            var sndPlayer = new SoundPlayer { SoundLocation = Application.ExecutablePath };
            sndPlayer.LoadCompleted+= SndPlayerOnLoadCompleted;
            sndPlayer.LoadAsync();
        }

        private void SndPlayerOnLoadCompleted(object sender, AsyncCompletedEventArgs asyncCompletedEventArgs)
        {
            MessageBox.Show("LoadCompleted");
        }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بر اساس زمانی که الان هست کار انجام میدهند، نه اینکه ترتیبی داده رو با یک نرخ مشخص بخونند. شما وقتی در حالت ترتیبی هر بار N نمونه به جلو پیشرفت می کنید کاری به زمان ندارید، چشم بسته دارید بر اساس یک ترتیبی عمل می کنید که مستقل از زمانه. وقتی در زمان 12.4 هستید باید نمونه ای رو بخونید که در زمان 12.4 بهش میرسه. با زمان فعلی کار کنید، کاری نداشته باشید که چند تا نمونه از دفعه جلوتر رفتید. ببینید الان چقدر زمان از شروع پخش گذشته و نوبت چه نمونه ای شده..

سلامی مجدد
استاد علی ، منظورتون اینه که y2 در کدی که دادم را بجای محاسبه به اون صورت ، بصورت this.y2 = ((44100 * 2 * 2) / 40) * this.MiliSecandElapsedCount; حساب کنم؟ :


کد:
        private Bitmap BitmapDanceLight;
        private byte[] AllWavHeaderData;
        private byte[] WaveDatas;
        private int TimerWaveInterval;
        private int MiliSecandElapsedCount;
        private int x1;
        private int y1;
        private int x2;
        private int y2;

        public FormTest2()
        {
            InitializeComponent();
            this.panelCustDanceLight.DoubleBuffered = true;
            this.BitmapDanceLight = new Bitmap(this.panelCustDanceLight.ClientSize.Width, this.panelCustDanceLight.ClientSize.Height);
            this.x1 = 0;
            this.y1 = this.BitmapDanceLight.Height;
            this.MiliSecandElapsedCount = 0;
        }


        private void btnWaveAudio_Click(object sender, EventArgs e)
        {
            string filePath = @"E:\Mp3\WAV\Khabari Hast (128).wav";
            AllWavHeaderData = File.ReadAllBytes(filePath);
            FileStream fileStream = new FileStream(filePath, FileMode.Open);
            BinaryReader binaryReader = new BinaryReader(fileStream);


            int chunkID = binaryReader.ReadInt32();
            int fileSize = binaryReader.ReadInt32();
            int riffType = binaryReader.ReadInt32();
            int fmtID = binaryReader.ReadInt32();
            int fmtSize = binaryReader.ReadInt32();
            int fmtCode = binaryReader.ReadInt16();
            int channels = binaryReader.ReadInt16();
            int sampleRate = binaryReader.ReadInt32();
            int fmtAvgBPS = binaryReader.ReadInt32();
            int fmtBlockAlign = binaryReader.ReadInt16();
            int bitDepth = binaryReader.ReadInt16();

            if (fmtSize == 18)
            {
                // Read any extra values
                int fmtExtraSize = binaryReader.ReadInt16();
                binaryReader.ReadBytes(fmtExtraSize);
            }

            int dataID = binaryReader.ReadInt32();
            int dataSize = binaryReader.ReadInt32();
            WaveDatas = binaryReader.ReadBytes(dataSize);

            ////////////////////////////////////////
            MemoryStream memoryStream = new MemoryStream(AllWavHeaderData);
            SoundPlayer wavPlayer = new SoundPlayer(memoryStream);
            wavPlayer.LoadCompleted += new AsyncCompletedEventHandler(this.wavPlayer_LoadCompleted);
            wavPlayer.Play();
            fileStream.Close();
            Thread.Sleep(1300);
        }

        private void wavPlayer_LoadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            System.Windows.Forms.Timer tmrWav = new System.Windows.Forms.Timer();
            tmrWav.Enabled = true;
            tmrWav.Interval = 25; //
            this.TimerWaveInterval = tmrWav.Interval;
            tmrWav.Tick += new EventHandler(this.tmrWav_Tick);
            this.tmrWav_Tick(tmrWav, new EventArgs());
        }
       
        private void tmrWav_Tick(object sender, EventArgs e)
        {
            // AllWavHeaderData WaveDatas   25 ms    7056 Bp40ms = AllWavHeaderData[7056]
            using (Graphics grBitmapDanceLight = Graphics.FromImage(this.BitmapDanceLight))
            using (Pen pen = new Pen(Color.Blue))
            {
                this.x2 = this.x1 + 2;
                if (this.x2 > this.BitmapDanceLight.Width)
                {
                    grBitmapDanceLight.Clear(Color.Transparent);
                    this.x1 = 0;
                    this.x2 = this.x1 + 2;
                }
                this.y2 = ((44100 * 2 * 2) / 40) * this.MiliSecandElapsedCount;

                grBitmapDanceLight.DrawLine(pen, this.x1, this.y1, this.x2, this.y2);

                this.x1 = this.x2;
                this.y1 = this.y2;

                this.MiliSecandElapsedCount ++;
            }

            this.panelCustDanceLight.Invalidate();
        }

        private void panelCustDanceLight_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawImageUnscaled(this.BitmapDanceLight, new Point(0, 0));
        }
 

the_king

مدیرکل انجمن
سلامی مجدد
استاد علی ، منظورتون اینه که y2 در کدی که دادم را بجای محاسبه به اون صورت ، بصورت this.y2 = ((44100 * 2 * 2) / 40) * this.MiliSecandElapsedCount; حساب کنم؟ :


کد:
        private Bitmap BitmapDanceLight;
        private byte[] AllWavHeaderData;
        private byte[] WaveDatas;
        private int TimerWaveInterval;
        private int MiliSecandElapsedCount;
        private int x1;
        private int y1;
        private int x2;
        private int y2;

        public FormTest2()
        {
            InitializeComponent();
            this.panelCustDanceLight.DoubleBuffered = true;
            this.BitmapDanceLight = new Bitmap(this.panelCustDanceLight.ClientSize.Width, this.panelCustDanceLight.ClientSize.Height);
            this.x1 = 0;
            this.y1 = this.BitmapDanceLight.Height;
            this.MiliSecandElapsedCount = 0;
        }


        private void btnWaveAudio_Click(object sender, EventArgs e)
        {
            string filePath = @"E:\Mp3\WAV\Khabari Hast (128).wav";
            AllWavHeaderData = File.ReadAllBytes(filePath);
            FileStream fileStream = new FileStream(filePath, FileMode.Open);
            BinaryReader binaryReader = new BinaryReader(fileStream);


            int chunkID = binaryReader.ReadInt32();
            int fileSize = binaryReader.ReadInt32();
            int riffType = binaryReader.ReadInt32();
            int fmtID = binaryReader.ReadInt32();
            int fmtSize = binaryReader.ReadInt32();
            int fmtCode = binaryReader.ReadInt16();
            int channels = binaryReader.ReadInt16();
            int sampleRate = binaryReader.ReadInt32();
            int fmtAvgBPS = binaryReader.ReadInt32();
            int fmtBlockAlign = binaryReader.ReadInt16();
            int bitDepth = binaryReader.ReadInt16();

            if (fmtSize == 18)
            {
                // Read any extra values
                int fmtExtraSize = binaryReader.ReadInt16();
                binaryReader.ReadBytes(fmtExtraSize);
            }

            int dataID = binaryReader.ReadInt32();
            int dataSize = binaryReader.ReadInt32();
            WaveDatas = binaryReader.ReadBytes(dataSize);

            ////////////////////////////////////////
            MemoryStream memoryStream = new MemoryStream(AllWavHeaderData);
            SoundPlayer wavPlayer = new SoundPlayer(memoryStream);
            wavPlayer.LoadCompleted += new AsyncCompletedEventHandler(this.wavPlayer_LoadCompleted);
            wavPlayer.Play();
            fileStream.Close();
            Thread.Sleep(1300);
        }

        private void wavPlayer_LoadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            System.Windows.Forms.Timer tmrWav = new System.Windows.Forms.Timer();
            tmrWav.Enabled = true;
            tmrWav.Interval = 25; //
            this.TimerWaveInterval = tmrWav.Interval;
            tmrWav.Tick += new EventHandler(this.tmrWav_Tick);
            this.tmrWav_Tick(tmrWav, new EventArgs());
        }
      
        private void tmrWav_Tick(object sender, EventArgs e)
        {
            // AllWavHeaderData WaveDatas   25 ms    7056 Bp40ms = AllWavHeaderData[7056]
            using (Graphics grBitmapDanceLight = Graphics.FromImage(this.BitmapDanceLight))
            using (Pen pen = new Pen(Color.Blue))
            {
                this.x2 = this.x1 + 2;
                if (this.x2 > this.BitmapDanceLight.Width)
                {
                    grBitmapDanceLight.Clear(Color.Transparent);
                    this.x1 = 0;
                    this.x2 = this.x1 + 2;
                }
                this.y2 = ((44100 * 2 * 2) / 40) * this.MiliSecandElapsedCount;

                grBitmapDanceLight.DrawLine(pen, this.x1, this.y1, this.x2, this.y2);

                this.x1 = this.x2;
                this.y1 = this.y2;

                this.MiliSecandElapsedCount ++;
            }

            this.panelCustDanceLight.Invalidate();
        }

        private void panelCustDanceLight_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawImageUnscaled(this.BitmapDanceLight, new Point(0, 0));
        }
خیر. MiliSecandElapsedCount چیه جز متغیری که شما ساختید، شما از یک تا 100 بشمرید دقیقا 100 ثانیه طول می کشه؟ دقیق نیست چون فاصله بین شمارش هاتون دقیقا یک ثانیه نیست. خوبه خودتون Timer رو تست کردید و میدونید که tmrWav_Tick دقیق نیست، وقتی خود tmrWav_Tick دقیق نیست، چطور MiliSecandElapsedCount داخلش دقیق باشه؟ MiliSecandElapsedCount که کاری به زمان فعلی و زمان شروع نداره، داره؟ MiliSecandElapsedCount چیزی جز یک شماره مستقل از زمان نیست. هر چقدر تیک ها کندتر اتفاق بیافته MiliSecandElapsedCount هم هماهنگ با اون کند میشماره. شما همون روال قبلی رو دارید طی می کنید، اینکه وابسته به زمان فعلی نیست. زمان فعلی در DateTime.Now ئه، نه متغیری مثل MiliSecandElapsedCount
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیر. MiliSecandElapsedCount چیه جز متغیری که شما ساختید، شما از یک تا 100 بشمرید دقیقا 100 ثانیه طول می کشه؟ دقیق نیست چون فاصله بین شمارش هاتون دقیقا یک ثانیه نیست. خوبه خودتون Timer رو تست کردید و میدونید که tmrWav_Tick دقیق نیست، وقتی خود tmrWav_Tick دقیق نیست، چطور MiliSecandElapsedCount داخلش دقیق باشه؟ MiliSecandElapsedCount که کاری به زمان فعلی و زمان شروع نداره، داره؟ MiliSecandElapsedCount چیزی جز یک شماره مستقل از زمان نیست. هر چقدر تیک ها کندتر اتفاق بیافته MiliSecandElapsedCount هم هماهنگ با اون کند میشماره. شما همون روال قبلی رو دارید طی می کنید، اینکه وابسته به زمان فعلی نیست. زمان فعلی در DateTime.Now ئه، نه متغیری مثل MiliSecandElapsedCount

آها منظورتون DateTime.Now هه (زمان ساعت ویندوز) . زودتر بگین ها :green:
من فکر کردم همزمان با play کردن ، یه تایمری به عنوان زمان در نظر بگیرم :green:
منم میگم خدایا ، این هم که همون میشه :green: ولی من که متوجه نشدم پس چرا توی رویداد LoadCompleted ، اگه نخ را قبل از رسم و بعد از play کردن ، 1 ثانیه متوقف نکنم ، اصلا با صدا (Data ی آهنگ) همون اول هم هماهنگ نمیشه چرا؟
ممنون . تست اش کنم
درباره ی توضیحات لودینگ هم ممنون
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد علی این کد رو نوشتم :


کد:
        private Bitmap BitmapDanceLight;
        private byte[] AllWavHeaderData;
        private byte[] WaveDatas;
        private DateTime WaveStartTime;
        private int x1;
        private int y1;
        private int x2;
        private int y2;

        public FormTest2()
        {
            InitializeComponent();
            this.panelCustDanceLight.DoubleBuffered = true;
            this.BitmapDanceLight = new Bitmap(this.panelCustDanceLight.ClientSize.Width, this.panelCustDanceLight.ClientSize.Height);
            this.x1 = 0;
            this.y1 = this.BitmapDanceLight.Height;
        }


        private void btnWaveAudio_Click(object sender, EventArgs e)
        {
            string filePath = @"E:\Mp3\WAV\Khabari Hast (128).wav";
            AllWavHeaderData = File.ReadAllBytes(filePath);
            FileStream fileStream = new FileStream(filePath, FileMode.Open);
            BinaryReader binaryReader = new BinaryReader(fileStream);


            int chunkID = binaryReader.ReadInt32();
            int fileSize = binaryReader.ReadInt32();
            int riffType = binaryReader.ReadInt32();
            int fmtID = binaryReader.ReadInt32();
            int fmtSize = binaryReader.ReadInt32();
            int fmtCode = binaryReader.ReadInt16();
            int channels = binaryReader.ReadInt16();
            int sampleRate = binaryReader.ReadInt32();
            int fmtAvgBPS = binaryReader.ReadInt32();
            int fmtBlockAlign = binaryReader.ReadInt16();
            int bitDepth = binaryReader.ReadInt16();

            if (fmtSize == 18)
            {
                // Read any extra values
                int fmtExtraSize = binaryReader.ReadInt16();
                binaryReader.ReadBytes(fmtExtraSize);
            }

            int dataID = binaryReader.ReadInt32();
            int dataSize = binaryReader.ReadInt32();
            WaveDatas = binaryReader.ReadBytes(dataSize);

            ////////////////////////////////////////
            MemoryStream memoryStream = new MemoryStream(AllWavHeaderData);
            SoundPlayer wavPlayer = new SoundPlayer(memoryStream);
            wavPlayer.LoadCompleted += new AsyncCompletedEventHandler(this.wavPlayer_LoadCompleted);
            wavPlayer.Play();
            fileStream.Close();
            Thread.Sleep(1300);
        }
       
        private void wavPlayer_LoadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            WaveStartTime = DateTime.Now;
           
            System.Windows.Forms.Timer tmrWav = new System.Windows.Forms.Timer();
            tmrWav.Enabled = true;
            tmrWav.Interval = 25; // 40 fps
            tmrWav.Tick += new EventHandler(this.tmrWav_Tick);
            this.tmrWav_Tick(tmrWav, new EventArgs());
        }
       
        private void tmrWav_Tick(object sender, EventArgs e)
        {
            // AllWavHeaderData WaveDatas   25 ms
            using (Graphics grBitmapDanceLight = Graphics.FromImage(this.BitmapDanceLight))
            using (Pen pen = new Pen(Color.Blue))
            {
                this.x2 = this.x1 + 2;
                if (this.x2 > this.BitmapDanceLight.Width)
                {
                    grBitmapDanceLight.Clear(Color.Transparent);
                    this.x1 = 0;
                    this.x2 = this.x1 + 2;
                }
                DateTime dateTimeEver25MiliSec = DateTime.Now;
                long elaspedWavTimeMiliSecRounded = (long)Math.Round(dateTimeEver25MiliSec.Subtract(this.WaveStartTime).TotalMilliseconds);
                double oneMiliSecBytRate = (44100 * 2 * 2) / 1000.0;
                long WaveDatasIndexer = (long)(oneMiliSecBytRate * elaspedWavTimeMiliSecRounded);
                this.y2 = this.BitmapDanceLight.Height - this.WaveDatas[WaveDatasIndexer];

                grBitmapDanceLight.DrawLine(pen, this.x1, this.y1, this.x2, this.y2);

                this.x1 = this.x2;
                this.y1 = this.y2;
               
            }

            this.panelCustDanceLight.Invalidate();
        }

        private void panelCustDanceLight_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawImageUnscaled(this.BitmapDanceLight, new Point(0, 0));
        }

اما باز هم مجبور شدم نخ را بعد از play و قبل از رسم ، 1300 میلی ثانیه متوقف کنم
اما این انگار بهتر کار کرد . حداقل بعد از آهنگ ، ارور تجاوز از اعضای آرایه را داد
ولی من آخر قضیه ی توقف نخ و خوندن هدر فایل (با اونکه توضیح دادین) را متوجه نشدم چرا با این حال واسه من مشکل داره و چجوری باید حل اش کرد
ممنون
 

the_king

مدیرکل انجمن
یک نگاهی به کدتون بندازید، حالا اسامی نامناسب متغیر ها و شیوه رسم غیر عادی و پیاده سازی ناقص هدر Wav بکنار، 1000.0 / ( 2* 2 * 44100) یعنی چی؟ یعنی 44100 نمونه در هر 1000 میلی ثانیه برای دو کانال که هر نمونه دو بایت ئه. درست؟ شما نمونه دو بایتی رو چطور از توی WaveDatas خوندید؟ اون this.WaveDatas[WaveDatasIndexer] دو بایت ئه؟ شما طوری با داده صوتی رفتار کردید که انگار این خطوط یک داده تصادفی ئه. نمونه هایی که اعداد علامت دار 16 بیتی هستند رو که نمی توانید با خوندن یک بایت بدون علامت تجزیه و تحلیل کنید.
شما در کدتون نه دامنه و نه فرکانس نمونه رسم شده رو در نظر نگرفتید. حالا شاید فرکانس برای کد شما مهم نباشه چون کشیده یا جمع بودن منحنی خیلی براتون مهم نیست اما بدون در نظر گرفتن دامنه 16 بیتی اش که نمی توانید رسمش کنید. و یک مورد دیگه، اگه قرار باشه با Stream کار کنید و همه داده ها رو یکجا لازم ندارید، چرا همه محتویات رو در حافظه آرایه نگه میدارید؟
برای Pen های پیشفرض یک پیکسلی هم نیازی به ساختن شون ندارید. آماده شون در Pens هست.

کد:
        private FileStream _fileStream;
        private long _waveDataPosition;
        private long _lastSampleIndex;
        private BinaryReader _binaryReader;
        private SoundPlayer _wavPlayer;
        private DateTime _waveStartTime;
        private int _samplePerSecond;
        private int _sampleSize;
        private readonly List<int> _waveSamples = new List<int>();

        private void btnWaveAudio_Click(object sender, EventArgs e)
        {
            var filePath = @"E:\Mp3\WAV\Khabari Hast (128).wav";
            _fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            _binaryReader = new BinaryReader(_fileStream);
            var chunkId = _binaryReader.ReadInt32();
            if (chunkId != 0x46464952) // RIFF
            {
                throw new Exception("Invalid file format!");
            }
            var fileSize = _binaryReader.ReadInt32();
            var riffType = _binaryReader.ReadInt32();
            while (_fileStream.Position <= _fileStream.Length - 8)
            {
                var subId = _binaryReader.ReadInt32();
                var subSize = _binaryReader.ReadInt32();
                var nextPos = _fileStream.Position + subSize;
                var channels = 0;
                switch (subId)
                {
                    case 0x20746D66: //fmt
                        var fmtCode = _binaryReader.ReadInt16();
                        if (fmtCode != 1) //pcm
                        {
                            throw new Exception("Audio format must be PCM!");
                        }
                        channels = _binaryReader.ReadInt16();
                        var sampleRate = _binaryReader.ReadInt32();
                        var fmtAvgBps = _binaryReader.ReadInt32();
                        var fmtBlockAlign = _binaryReader.ReadInt16();
                        var bitDepth = _binaryReader.ReadInt16();
                        if (bitDepth != 16)
                        {
                            throw new Exception("Samples must be 16-bit!");
                        }
                        _sampleSize = bitDepth / 8;
                        _samplePerSecond = sampleRate * channels;
                        break;
                    case 0x61746164: //data
                        _waveDataPosition = _fileStream.Position;
                        _lastSampleIndex = subSize / _sampleSize - channels;
                        break;
                }
                _fileStream.Position = nextPos;
            }
            ////////////////////////////////////////
            _wavPlayer = new SoundPlayer(File.OpenRead(filePath));
            _wavPlayer.LoadCompleted += new AsyncCompletedEventHandler(this.wavPlayer_LoadCompleted);
            _wavPlayer.LoadAsync();
        }

        private void wavPlayer_LoadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            _waveStartTime = DateTime.Now;
            _wavPlayer.Play();
            var tmrWav = new System.Windows.Forms.Timer();
            tmrWav.Enabled = true;
            tmrWav.Interval = 25; // 40 fps
            tmrWav.Tick += new EventHandler(this.tmrWav_Tick);
            this.tmrWav_Tick(tmrWav, new EventArgs());
        }

        private void tmrWav_Tick(object sender, EventArgs e)
        {
            // AllWavHeaderData WaveDatas   25 ms
            var curTime = DateTime.Now;
            var elaspedWavTimeSec = curTime.Subtract(this._waveStartTime).TotalSeconds;
            var sampleIndex = (int)Math.Round(_samplePerSecond * elaspedWavTimeSec * _sampleSize) / _sampleSize;
            if (sampleIndex >= _lastSampleIndex)
            {
                var tmrWav = (System.Windows.Forms.Timer)sender;
                tmrWav.Enabled = false;
                _binaryReader.Close();
                return;
            }
            _fileStream.Position = _waveDataPosition + sampleIndex * _sampleSize;
            var sample = _binaryReader.ReadInt16();
            var sampleY = this.panelCustDanceLight.Height / 2 - (int)(panelCustDanceLight.Height / 2f * sample / short.MaxValue);
            if (_waveSamples.Count >= panelCustDanceLight.Width / 2)
            {
                _waveSamples.RemoveAt(0);
            }
            _waveSamples.Add(sampleY);
            this.panelCustDanceLight.Invalidate();
        }

        private void panelCustDanceLight_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawLine(Pens.DarkGreen, 0, panelCustDanceLight.Height / 2, panelCustDanceLight.Width, panelCustDanceLight.Height / 2);
            for (var i = 1; i < _waveSamples.Count; i++)
            {
                var x = i * 2;
                e.Graphics.DrawLine(Pens.Blue, x - 2, _waveSamples[i - 1], x, _waveSamples[i]);
            }
        }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
یک نگاهی به کدتون بندازید، حالا اسامی نامناسب متغیر ها و شیوه رسم غیر عادی و پیاده سازی ناقص هدر Wav بکنار، 1000.0 / ( 2* 2 * 44100) یعنی چی؟ یعنی 44100 نمونه در هر 1000 میلی ثانیه برای دو کانال که هر نمونه دو بایت ئه. درست؟ شما نمونه دو بایتی رو چطور از توی WaveDatas خوندید؟ اون this.WaveDatas[WaveDatasIndexer] دو بایت ئه؟ شما طوری با داده صوتی رفتار کردید که انگار این خطوط یک داده تصادفی ئه. نمونه هایی که اعداد علامت دار 16 بیتی هستند رو که نمی توانید با خوندن یک بایت بدون علامت تجزیه و تحلیل کنید.
شما در کدتون نه دامنه و نه فرکانس نمونه رسم شده رو در نظر نگرفتید. حالا شاید فرکانس برای کد شما مهم نباشه چون کشیده یا جمع بودن منحنی خیلی براتون مهم نیست اما بدون در نظر گرفتن دامنه 16 بیتی اش که نمی توانید رسمش کنید. و یک مورد دیگه، اگه قرار باشه با Stream کار کنید و همه داده ها رو یکجا لازم ندارید، چرا همه محتویات رو در حافظه آرایه نگه میدارید؟
برای Pen های پیشفرض یک پیکسلی هم نیازی به ساختن شون ندارید. آماده شون در Pens هست.

کد:
        private FileStream _fileStream;
        private long _waveDataPosition;
        private long _lastSampleIndex;
        private BinaryReader _binaryReader;
        private SoundPlayer _wavPlayer;
        private DateTime _waveStartTime;
        private int _samplePerSecond;
        private int _sampleSize;
        private readonly List<int> _waveSamples = new List<int>();

        private void btnWaveAudio_Click(object sender, EventArgs e)
        {
            var filePath = @"E:\Mp3\WAV\Khabari Hast (128).wav";
            _fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            _binaryReader = new BinaryReader(_fileStream);
            var chunkId = _binaryReader.ReadInt32();
            if (chunkId != 0x46464952) // RIFF
            {
                throw new Exception("Invalid file format!");
            }
            var fileSize = _binaryReader.ReadInt32();
            var riffType = _binaryReader.ReadInt32();
            while (_fileStream.Position <= _fileStream.Length - 8)
            {
                var subId = _binaryReader.ReadInt32();
                var subSize = _binaryReader.ReadInt32();
                var nextPos = _fileStream.Position + subSize;
                var channels = 0;
                switch (subId)
                {
                    case 0x20746D66: //fmt
                        var fmtCode = _binaryReader.ReadInt16();
                        if (fmtCode != 1) //pcm
                        {
                            throw new Exception("Audio format must be PCM!");
                        }
                        channels = _binaryReader.ReadInt16();
                        var sampleRate = _binaryReader.ReadInt32();
                        var fmtAvgBps = _binaryReader.ReadInt32();
                        var fmtBlockAlign = _binaryReader.ReadInt16();
                        var bitDepth = _binaryReader.ReadInt16();
                        if (bitDepth != 16)
                        {
                            throw new Exception("Samples must be 16-bit!");
                        }
                        _sampleSize = bitDepth / 8;
                        _samplePerSecond = sampleRate * channels;
                        break;
                    case 0x61746164: //data
                        _waveDataPosition = _fileStream.Position;
                        _lastSampleIndex = subSize / _sampleSize - channels;
                        break;
                }
                _fileStream.Position = nextPos;
            }
            ////////////////////////////////////////
            _wavPlayer = new SoundPlayer(File.OpenRead(filePath));
            _wavPlayer.LoadCompleted += new AsyncCompletedEventHandler(this.wavPlayer_LoadCompleted);
            _wavPlayer.LoadAsync();
        }

        private void wavPlayer_LoadCompleted(object sender, AsyncCompletedEventArgs e)
        {
            _waveStartTime = DateTime.Now;
            _wavPlayer.Play();
            var tmrWav = new System.Windows.Forms.Timer();
            tmrWav.Enabled = true;
            tmrWav.Interval = 25; // 40 fps
            tmrWav.Tick += new EventHandler(this.tmrWav_Tick);
            this.tmrWav_Tick(tmrWav, new EventArgs());
        }

        private void tmrWav_Tick(object sender, EventArgs e)
        {
            // AllWavHeaderData WaveDatas   25 ms
            var curTime = DateTime.Now;
            var elaspedWavTimeSec = curTime.Subtract(this._waveStartTime).TotalSeconds;
            var sampleIndex = (int)Math.Round(_samplePerSecond * elaspedWavTimeSec * _sampleSize) / _sampleSize;
            if (sampleIndex >= _lastSampleIndex)
            {
                var tmrWav = (System.Windows.Forms.Timer)sender;
                tmrWav.Enabled = false;
                _binaryReader.Close();
                return;
            }
            _fileStream.Position = _waveDataPosition + sampleIndex * _sampleSize;
            var sample = _binaryReader.ReadInt16();
            var sampleY = this.panelCustDanceLight.Height / 2 - (int)(panelCustDanceLight.Height / 2f * sample / short.MaxValue);
            if (_waveSamples.Count >= panelCustDanceLight.Width / 2)
            {
                _waveSamples.RemoveAt(0);
            }
            _waveSamples.Add(sampleY);
            this.panelCustDanceLight.Invalidate();
        }

        private void panelCustDanceLight_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawLine(Pens.DarkGreen, 0, panelCustDanceLight.Height / 2, panelCustDanceLight.Width, panelCustDanceLight.Height / 2);
            for (var i = 1; i < _waveSamples.Count; i++)
            {
                var x = i * 2;
                e.Graphics.DrawLine(Pens.Blue, x - 2, _waveSamples[i - 1], x, _waveSamples[i]);
            }
        }

خیلی ممنونم استاد علی :rose:
اما ای کاش بجای دادن کد ، نقص هام را به همون روالی که داشتیم میرفتیم ، میگفتین تا خودم کد را اصلاح کنم . این جوری خیلی بهتر و بیشتر میفهمم و تو ذهنم میمونه.
من همیشه از تجزیه و تحلیل کردن کدهای آماده ، غصه ام میگیره :green: حاضرم 1000 خط کد بنویسم ولی 100 خط کد را تجزیه و تحلیل نکنم :green: (منظورم کدهایی که این جوری محاسبات توش هست) . یه وهله تحلیل کردم . ای کاش یه چند تا کامنت توضیح هم کنار کدهای مهم مینوشتید :green:
------------------------------
درباره ی پیاده سازی ناقص هدر فایل wav ، من که چیزی از هدر و اینکه کدوم یک از اطلاعاتش در کدوم بایت قرار داره و مقادیرشون مشخص کننده ی چی هستن (مثلا همونfmtCode != 1 که نوشتین) ، نمیدونم . درباره ی هدر هم که گشتم ، فقط همون کدی که لینک دادم را پیدا کردم . اون هم سند رسمی نبود که مقادیرهای مختلف را بگه
1000.0 / ( 2* 2 * 44100) هم یعنی میزان بیت ریت (بر اساس بایت) اون فایل ، در هر یک میلی ثانیه
منظورتون از " شما نمونه دو بایتی رو چطور از توی WaveDatas خوندید؟ " اینه که باید اطلاعات 2 کانال را بصورت همزمان رسم میکردم ولی this.WaveDatas[WaveDatasIndexer] ، اطلاعات مریوط به یک کانال هه فقط؟ اگه آره ، میدونم . فعلا فقط یک کانال اش را خواستم تست کنم
اینکه گفتید "شما طوری با داده صوتی رفتار کردید که انگار این خطوط یک داده تصادفی ئه" ، دقیقا منظورتون را متوجه نشدم کجای کدم را میگید
دامنه چیه؟
اما من متوجه نشدم چرا در کد شما ، رویداد LoadComplete دقیق به موقع اجرا میشه ولی واسه من نه!
 

the_king

مدیرکل انجمن
درباره ی پیاده سازی ناقص هدر فایل wav ، من که چیزی از هدر و اینکه کدوم یک از اطلاعاتش در کدوم بایت قرار داره و مقادیرشون مشخص کننده ی چی هستن (مثلا همونfmtCode != 1 که نوشتین) ، نمیدونم . درباره ی هدر هم که گشتم ، فقط همون کدی که لینک دادم را پیدا کردم . اون هم سند رسمی نبود که مقادیرهای مختلف را بگه

شما یا باید همیشه کد یک نفر دیگه رو کپی کنید که نفهمید چی به چیه، یا باید مستنداتش رو بخونید و خودتون کدش رو بنویسید. اگر قرار بوده صرفا روی یک کد که یه بنده خدایی نوشته پیش برید باید روال رسم رو هم همونطور پیدا می کردید، نه اینکه داده فرمتی رو که هنوز نمی دونید چی داخلشه رو رسم کنید. رو روال پیش نرفتید که، شما که میخواهید خودتون کد خوندن و رسم فرمتی رو بنویسید، مستندات فرمت Wav رو باید بخونید، که مشخصه، فرضا این دو تا :
The WAVE File Format و WAVE PCM soundfile format
نمیشه که گفت حتما باید بعد از fmt ئه data بیاد، ممکنه LIST هم باشه، ممکنه طولشون متفاوت باشه. تشخیص اینکه byte طولش 16 بیت نیست هم که نیازی به گفتن من نداره.
منظورتون از " شما نمونه دو بایتی رو چطور از توی WaveDatas خوندید؟ " اینه که باید اطلاعات 2 کانال را بصورت همزمان رسم میکردم ولی this.WaveDatas[WaveDatasIndexer] ، اطلاعات مریوط به یک کانال هه فقط؟

خیر، یک کانال، شما مگه نمی گید اون فرمول 1000.0 / ( 2* 2 * 44100) ئه Bitrate در ثانیه است؟ خوب تعداد کانال که 2 ئه و استریو ئه. فرمول رو بر تعداد کانال که 2 ئه تقسیم کنید چی بدست میاد؟
میشه 1000.0 / ( 2 * 44100) ، حالا شما بگید اون 2 باقی مونده در فرمول الان چی هست؟ تعداد کانال که دیگه نیست، پس اون 2 برای چه منظوریه؟ هر Sample دو بایت ئه، 16 بیتی ئه و this.WaveDatas[WaveDatasIndexer] نصف داده است، یعنی از وسط یک مقدار 16 بیتی رو نصف کردید 8 بیت با ارزش اش رو ریختید دور، برای همین شده مثل داده های تصادفی که تطابقی با صوتی که پخش میشه نداره.


اگه آره ، میدونم . فعلا فقط یک کانال اش را خواستم تست کنم

خیر. کدی که من نوشتم هم صرفا با یک کانال کار می کنه.

چرا از جستجو کردن اجتناب می کنید؟ میترسید قبل از پرسیدن جستجو کنید اتفاق بدی بیافته؟ دامنه، طول موج، فرکانس و دوره تناوب موج
اما من متوجه نشدم چرا در کد شما ، رویداد LoadComplete دقیق به موقع اجرا میشه ولی واسه من نه!
شما در کدتون گفتید LoadComplete شد به نخ فرم ام اطلاع بده، درست؟ بعد پشت سرش خودتون با Sleep نخ تون رو بردید در کما که کلا فلج بشه و به هیچ رخدادی پاسخ نده، خوب انتظار دارید وقتی LoadComplete شد یهو نخ از هوش رفته سحر اش با معجزه باطل بشه نخ خود بخود Rusume بشه؟ نخی که در حال اجرا نیست چطور برای رخداد کاری رو به موقع انجام بده؟ ثانیا من در کد شما متدی برای Load کردن صوت قبل از پخش ندیدم، شما خودتون دوست نداشتید از Load و LoadAsync استفاده کنید، دلیل Sleep کردن نخ فرم تون رو هم متوجه نشدم. هیچوقت Sleep شدن یک نخ کمکی به اجرای نخ نمی کنه چون بدتر اجراشو به تاخیر میندازه.
 

جدیدترین ارسال ها

بالا