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

شروع موضوع توسط SajjadKhati ‏23 فوریه 2018 در انجمن برنامه‌نویسی C و هم خانواده‌هایش

  1. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83
    سلام
    این تاپیک رو زدم که سئوالات مربوط به ساختار و کار کردن فایل (فایل صوتی و عکس و تصویری) پرسیده شه

    ---------------------------------

    اولین سئوالم اینه استاد علی ، در پست 816 در تاپیک "گفتگوهایی در باب سی شارپ" ، توضیحاتی که درباره ی فایل صوتی دادین ، چون من اصلا نحوه ی اطلاعات ذخیره شده در فایل های صوتی را نمیدونم ، شکل زیر را رسم کردم و ببینین برداشتم از ذخیره سازی اطلاعات صوتی درسته؟ :

    1.jpg

    توی هر ثانیه ، عددی توی فایل صوتی ذخیره میشه که بهش میگن sample rate . مثلا sample rate 44.1 KHz یعنی 44100 تا از این نمودارها (البته منظور از نمودار ، یه چیز ذهنی و فرضی هست) در یک ثانیه در فایل صوتی ذخیره میشه . sample depth که اغلب 16 بیت هه (احتمال میره این 16 بیت ، بخاطر اکثر اوقات دو کاناله بودن باشه که هر کانال 8 بیت میشه . پس این عدد ، برای هر کانال صوتی ، 8 بیت هه . درسته؟) و بخاطر همین هم هر sample rate بین منفی 128 تا مثبت 127 حداکثر میتونه باشه . درسته؟ پس sample depth ای که 24 بیت هه این وسط قضیه اش چیه؟
    هر چی میزان sample rate بیشتر باشه ، فرکانس های بیشتری ذخیره و جزئیات فرکانس ها بیشتر ذخیره میشه و باعث میشه کیفیت و حجم افزایش پیدا کنه
    اگه نمودار بالا درست باشه ، sample rate باید همون دسیبل (فرکانس های مختلف که صدا رو تولید میکنه) باشه . پس دسیبل این وسط چیه؟
    اینا همه فرضیه ی من ان . اطلاعاتی ندارم چون منبع خوبی نیست که بخونم . منبع انگلیسی را خوندم ولی متوجه نشدم
     
    آخرین ویرایش: ‏23 فوریه 2018
    نوشته شده توسط SajjadKhati در ‏23 فوریه 2018
  2. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113

    چیزی که کشیدید بیشتر از اینکه کمک کننده باشه گمراه کننده است. نمیدونم مشکل تون با گوگل چیه ولی مطالبی که جستجو می کنید خیلی بهتر از تصویری که خودتون بکشید کمک می کنه.
    Sampling (signal processing)
    Hertz
    44.1kHZ یعنی 441000 بار نمونه برداری در ثانیه از منحنی، فرضا منحنی صوت. منحنی تشکیل شده از بی نهایت نقطه متصل به هم. طبیعتا بی نهایت نقطه رو نه نمیشه ذخیره کرد و نه چنین دقتی لازمه. برای همین با نمونه برداری صرفا موقعیت y نقاطی رو با فواصل مشخص از منحنی رو ثبت می کنند که بهش میگن Sample یا نمونه. هر چقدر این فواصل کمتر باشه Sample Rate بیشتر ئه و تعداد نمونه های ذخیره شده بیشتر میشه و دقت در نمونه برداری بیشتر ئه. نمونه، نه نمودار. نه اینکه 441000 تا نمودار در کار باشه.
    نه، درست نیست. احتمال رو ول کنید، Sample Rate برای هر کانالی مجزا است، چه مونو باشه و چه 5 کاناله، اون 16 بیت برای یک کاناله، نه اینکه تقسیم بشه بین کانالها.
    بخاطر هیچ مساله ای نیست بجز اینکه هر نمونه یک مقدار عددی علامت دار (Signed) ئه و نه Unsigned. مثل Int16 و Int32 و short و int و long و ... طبیعتا یک بیت برای علامت مقدار صرف شده. مثل تفاوت UInt16 و Int16 ئه.
    قضیه خاصی نداره، اونم یک کیفیت بهتر ئه دیگه که بجای دو بایتی 3 بایتی ئه و با دقت بهتری مقدار نمونه ها رو ثبت می کنه.

    هر چی میزان sample rate بیشتر باشه ،نمونه های بیشتری ذخیره و جزئیات منحنی بهتر ذخیره میشه و باعث میشه کیفیت و حجم افزایش پیدا کنه.


    خوبه خودتون میبینین واحدش HZ ئه، چطور میتونه dB باشه؟ فرکانس منحنی صوت هم مستقل از فرکانس نمونه برداری ئه. ممکنه فرکانس صوت کم باشه ولی با فرکانس بالا ازش نمونه برداری کنید. دسیبل توان نسبی نمونه ها است، یعنی مقدار نسبی همون نمونه ها که چقدر زیر صفر یا بالای صفر هستند. نسبی از این بابت ئه که کلا دسیبل یه واحد نسبی ئه، نه یه واحد مطلق. عملا فرقی بین 127 در نمونه برداری 8 بیتی و 32767 در نمونه برداری 16 بیتی و 1.0 در نمونه برداری float و ... نیست، کیفیت نمونه برداری متفاوته ولی این مقادیر نسبی حداکثری ربطی به قدرت واقعی صوت خروجی ندارند.
     
    نوشته شده توسط the_king در ‏23 فوریه 2018
    SajjadKhati از این پست تشکر کرده است.
  3. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83
    ممنون استاد علی
    با کلاس System.Media.SoundPlayer ، یه مثال کوچیک میزنین که در فایل wav ، مقدار sample depth (مقدار ثابتی هست در کل فایل دیگه؟) رو استخراج کنه، و بعد اطلاعات sample rate در 1 ثانیه ی اول از این فایل را هم استراج کنه؟
    -------------------------
    اون لینک sampling در ویکی پدیا را دیدم ولی متوجه نشدم . باز هم مفهوم دسیبل را خوب درک نکردم
    بعد اینکه وقتی sample depth هست ، این مقدار مثلا 128kbps یا 320kbps (کیلو بیت بر ثانیه) دیگه چرا مشخص میشه؟ خوب یکی شون مشخص بشه ، اون یکی اتوماتیک درمیاد دیگه . درسته؟
     
    نوشته شده توسط SajjadKhati در ‏23 فوریه 2018
  4. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113
    SoundPlayer پخش می کنه، چیزی رو براتون استخراج نمی کنه. بله. Sample Rate برای فایل های غیر فشرده PCM ثابته.
    WaveFormat

    حتی اگه بدونید Sample Depth ئه فرضا 16 بیتی است و فرکانس نمونه برداری 20kHZ ئه، باز هم بدون دانستن اینکه چند کانال صوتی داره نمی توانید Bit Rate اش رو تشخیص بدید. طبیعتا مشخص کردن همچین مقداری به وضوح حجمی که ذخیره کردن هر ثانیه اش نیاز داره مشخص می کنه و موردی نیست که بشه بسادگی ازش صرف نظر کرد.
     
    نوشته شده توسط the_king در ‏23 فوریه 2018
    SajjadKhati از این پست تشکر کرده است.
  5. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83
    ممنون استاد علی
    ولی من متوجه نشدم
    یه مثال کوچیک در حد همون قدری که گفتم ، نمیزنین؟
     
    نوشته شده توسط SajjadKhati در ‏24 فوریه 2018
  6. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113
    نه. عزیزم. اگر برای درک یک مطلب به قول خودتون به یک مثال کوچیک و کد نویسی نیاز باشه باید مطالعه کنید، جستجو کنید و یاد بگیرید که اون کد رو بنویسید، نه اینکه شخص دیگری برای اینکه چیزی رو بفهمید کد نویسی کنه. من اون شخصی نیستم که میخواد این موضوع رو یادبگیره که بیام کد نویسی کنم، قبلا زمان صرف شون کردم و یادگرفتم، کسی هم برام نمونه کد ننوشته یا همچین درخواستی هم نداشتم. مستندات فرمت رو دیدم و بر اساس مشخصاتش داده رو پردازش کردم. الان شما می خواهید یاد بگیرید و برای یادگیریش لازمه وقت صرف کنید. اگر به نظرتون یادگرفتن اش به زمان زیادی احتیاج داره که حقیقتا نداره و یا کلا حوصله و یا وقت اش رو ندارید ازش صرف نظر کنید، به خودتون بگید من برای یادگیری فلان موضوع وقت یا انگیزه کافی ندارم و بیخیالش بشید. تمام منابعی هم که برای انجامش بهش نیاز دارید خدا رو شکر موجود ئه، از مستندات فرمت و تعاریف و نمونه کد ها و ...
    صرفا باید وقت صرف مطالعه شون کنید.
     
    نوشته شده توسط the_king در ‏24 فوریه 2018
    SajjadKhati از این پست تشکر کرده است.
  7. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83

    شما هم عزیز منید استاد علی :rose:
    والا من دیدم چند منبع و مثال ها را مثل :

    Audio samples per second?

    ولی اون چیز مورد نظرم را نیافتم . الان طبق اون چیزی که در پست دوم گفتن ، total length (in bytes) یک فایل صوتی را تقسیم بر زمان اش duration (in seconds) کنیم ، تعداد sample rate هایی که در یک ثانیه اجرا میشن را برمیگردونه؟ تعدادِ sample rate با خودِ sample rate فرقی ندارن؟
     
    نوشته شده توسط SajjadKhati در ‏24 فوریه 2018
  8. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113
    کاربرد ها خیلی متفاوته، ممکنه wav رو فقط برای خواندن باز کنند، برای نمایش Properties باز کنند، برای پردازش صوت باز کنند، چیزی رو واضح جستجو کنید که لازم دارید نه یه بحث کلی.
    Reading & Writing .wav file (C# + .net)
    How to read the data in a wav file to an array
    Create valid wav file header for streams in memory
    هدر فایل به هر بخشی از حجم فایل رو تشکیل میده، اما Sample Bit Rate مستقل از حجم هدر ئه، پس اگر حجم هدر رو از حجم کلی فایل کسر اش نکنید مقدار محاسبه شده تخمینی ئه و دقیق نیست، خطا داره، مقدار خطاش هم بستگی به حجم صوتی داره، برای یک صوت چند صد مگابایتی ناچیزه و بچشم نمیاد، ولی وقتی خود صوت حجم کمی داره اون حجم هدر هم مقدار قابل توجهی محسوب میشه. مثل اینه که تعداد سرنشینان خودرو اعم از راننده و مسافر رو بجای تعداد مسافرین ملاک قرار بدین، مقدار دقیقی بدست نمیاد، ولی وقتی خودرو بزرگی مثل اتوبوس باشه خطا ناچیزه.
    تعداد Sample Rate یعنی چی؟ نداریم همچین چیزی.
     
    نوشته شده توسط the_king در ‏24 فوریه 2018
    SajjadKhati از این پست تشکر کرده است.
  9. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83
    ممنون استاد علی
    الان در لینک زیر :

    C# How to get Audio Decibel values with time span

    در پست دوم میگه :
    "With NAudio you can use the WaveFileReader and Mp3FileReader classes to get access to the sample data within the file as a byte array"
    منظورش کدوم عضو در کلاس Mp3FileReader در NAudio ، هست که باهاش میتونن sample data را بدست بیارن؟
    یا وقتی میگه :
    "Then you would need to read through the file and get the sample values"
    مقدار sample value که فکر کنم همون sample depth منظورشه را چجوری میشه بدست آورد؟
    کلا در کد زیر :

    کد (Text):
    short sample16Bit = BitConverter.ToShort(buffer,index);
    ورودی هاش یعنی buffer و index رو میگین از خروجی کدوم توابع بدست آورد و چی هستن؟
    ممنون
     
    نوشته شده توسط SajjadKhati در ‏25 فوریه 2018
  10. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113

    من مستنداتش رو ندیدم. باید مطالعه شون کنید، اما اینها Reader هستند، متد های Read دارند.

    Sample Values که نمیتونه Sample Depth باشه. Sample Depth فقط یک مقدار ئه، بیشتر از یک مورد که نیست. متنی که نوشته تفسیر همون آرایه ای از بایت ها است که بجای بایت بایت بصورت داده های متوالی از یک نوع داده خاص مثل Int16 تفسیر بشه.
    همون بحث تفسیر داده ای است که فرمت خام اش بصورت آرایه ای از بایت ها است. در حافظه buffer یک سری بایت قرار داره که نتیجه ذخیره سازی یک سری داده است که الزاما نوع داده شون شبیه هم نیست، ممکنه بیش از یک بایت هم باشند، هر قسمت اش ممکنه در اصل نوع داده متفاوتی بوده باشه اما در کنار هم بصورت یک آرایه از بایت ها است. وقتی می خواهید یک داده فرضا Short ئه 16 بیتی رو از این حافظه دریافت کنید، برای BitConverter اون حافظه buffer و موقعیت اولین خانه حافظه (index) مربوط به اون داده در اون buffer رو مشخص می کنید، به اون index عموما offset هم می گویند. BitConverter به اندازه طول اون نوع داده خاص (فرضا دو بایت برای short) رو از آرایه از اون موقعیت خاص میخونه و تفسیر می کنه و بیت هاشو با ترتیب درست ترکیب می کنه و بصورت یک داده فرضا Short بر میگردونه.
     
    نوشته شده توسط the_king در ‏25 فوریه 2018
    SajjadKhati از این پست تشکر کرده است.
  11. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83
    سلامی مجدد استاد علی
    من کد زیر را از لینک زیر گرفتم :


    Streaming Data from a WAV File

    کد (Text):
            private void btnWaveAudio_Click(object sender, EventArgs e)
            {
                string filePath = @"E:\Mp3\WAV\Khabari Hast (128).wav";
                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();
                byte[] waveDatas = binaryReader.ReadBytes(dataSize);
               

                //MessageBox.Show("chunkID  " + chunkID + "\nfileSize  " + fileSize + "\nriffType  " + riffType + "\nfmtID  " +
                //    fmtID + "\nfmtSize  " + fmtSize + "\nfmtCode  " +
                //    fmtCode + "\nchannels  " + channels + "\nsampleRate  " + sampleRate + "\nfmtAvgBPS  " + fmtAvgBPS + "\nfmtBlockAlign  " +
                //    fmtBlockAlign + "\nbitDepth  " + bitDepth + "\ndataID  " + dataID + "\ndataSize  " + dataSize);

                fileStream.Close();
            }

    در آرایه ی waveDatas ، محتوای فایل صوتی مورد نظر که میدونین
    اول اینکه این اطلاعاتی که توی حافظه رفت (همین آرایه ی waveDatas) ، زمانی که توی حافظه بره ، اسمش میشه استریم؟ یعنی یا فایل داریم ، یا توی حافظه ی رم اگه بارگذاری بشه ، اسمش استریم میشه؟
    بعد اینکه میخوام بدونم کلاسی هست که صوت را از حافظه ی بافر (یا اگه استریم درسته ، استریم) پخش کنه (که البته میدونم SoundPlayer از بافر هم پخش میکنه) و هم اینکه یه رویدادی داشته باشه که هر عضو از اون آرایه را که در حال خوندنش هست ، شماره ی اون عضو را به اون رویداد بده تا توسط اون شماره ی عضو ، به مقدار اون حافظه از بافری که در حال خوندن هست ، دسترسی داشته باشیم و طبق اون ، حالا مقدار اون بایت (که باید همون مقدار یک دونه sample باشه) را رسم کنیم؟
     
    نوشته شده توسط SajjadKhati در ‏13 می 2018
  12. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113

    خیر، اطلاعاتی که تماما از ابتدا تا انتها در حافظه ای قرار بگیره که دیگه Stream نیست. ممکنه منبع Stream اون حافظه باشه، ولی خود حافظه اصلا Stream محسوب نمیشه. Stream بصورت تدریجی داده ها رو از منبع اصلی اش بدست میاره که ممکنه یک تکه حافظه در RAM باشه، فایلی روی سیستم باشه، سروری در شبکه باشه، حاصل پردازش تدریجی یک اطلاعاتی باشه و ...، ممکنه اصلا بی انتها باشه، ممکنه حجمش چند برابر کل حافظه موجود در سیستم باشه. ممکنه Stream قابلیت برگشت به موقعیت داده های قبلی رو نداشته باشه. اون ویدئویی که آنلاین در یوتیوپ یا آپارات می بینید و بدون دانلود کامل در حال پخش ئه یک Stream ئه.
    این کلاس کجا باید باشه؟ من که لیست تمامی کلاس های دنیا رو که ندارم. در NET Framework. نیست، ولی موتور های پردازش صوتی گرافیکی زیادی هست که روی روال پخش صوت کنترل و رخداد هایی ایجاد می کنند که قبلا هم در موردشون صحبت کردیم. SoundPlayer صرفا یک پخش کننده داخلی ویندوز ئه که دخالتی در پردازش داده نداره. از طرف دیگه شما توقع دارید یک کلاسی بیاد برای هر Sample داده ای که پخش میکنه رخداد ایجاد کنه؟ برای یک دقیقه پخش صوتی چند ده میلیون رخداد ایجاد کنه؟ منطقیه همچین چیزی؟ در ضمن Sample که رسم نداره، فرضا عدد 117 باشه، به تنهایی چه رسمی داره؟ شما باید منحنی صوتی رو رسم کنید که متکی به همه داده های قبل و حتی بعد از اون موقعیت ئه. موقعیت پخش هم مشخصه، پخش تا زمانی تاخیر داره که رخداد LoadCompleted اتفاق بیافته و داده ها بصورت کامل فراخوانی بشه. وقتی زمان شروع پخش مشخص باشه شما در هر لحظه ای اراده کنید می توانید بفهمید چه زمانی از پخش گذشته. فرمت WAV و تفسیر Sample های داخلش رو هم که دیدید، مستنداتش هم که هست. در نظر هم بگیرید که صحبت از kHz ئه، نه فرضا یک Sample در ثانیه. تا شما بخواهید چیزی رو رسم کنید یک سری Sample دیگه پخش شده.
     
    نوشته شده توسط the_king در ‏13 می 2018
    SajjadKhati از این پست تشکر کرده است.
  13. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83

    ممنون استاد علی
    بله . منظورم منم رسم ای که خودمون انجام میدیم بود . میدونم sample ، عدد هه
    آها . پس شما میگید وقتی شروع به پخش شد (توسط اون رخداد) ، ما تایمری برای روند زمان ایجاد کنیم تا موقعیتی (ثانیه یا میلی ثانیه ای) که در حال پخش شدن هست را بدست بیاریم و sample ای که در حال خوندن هست (شماره ی آرایه) را توسط فرمول محاسبه اش که :
    Sample Rate * Bit Depth * Channel
    محاسبه کنیم؟
    بعد اینکه برای محاسبه ی رسم ، میانگین sample های چند میلی ثانیه ی قبل (مثلا 10 میلی ثانیه ی قبل) را محاسبه کنیم (و همینطور 10 میلی ثانیه ی بعد را) و میانگین شو رسم کنیم؟ چون در 100 میلی ثانیه ، تعداد sample ها زیاده (4100 تا sample هست) و نمیشه همه را یه دفعه رسم کرد (پردازنده کم میاره و ...)

    بعد اینکه در کانال های صوتی با تعداد دو کاناله ، یعنی همزمان ، دو صوت پخش میشه دیگه؟ (حالا یه کانال در یه بلدگو و یکی دیگه ، اون طرف بلندگو) . این دو کاناله بودن ، یعنی اینکه مثلا در اون آرایه ی waveDatas (در پست بالا که اطلاعات صوتی توش هست) ، صفر اُمین عضو از خونه ی waveDatas ، مربوط به یکی از کانال هاست (مثلا کانال اول) و اولین عضو از waveDatas ، مربوط به کانال دیگری (مثلا کانال دوم) که این دو کانال ، همزمان با هم پخش میشن؟ بعد دومین عضو از waveDatas مربوط به کانال اول و سومین عضو از waveDatas ، مربوط به کانال دوم هه؟ الی آخر؟
    یعنی دوتا دوتا از اعضای آرایه ، با هم اجرا و پخش میشن (در دو کاناله ها) ؟
     
    نوشته شده توسط SajjadKhati در ‏13 می 2018
  14. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83
    بعد اینکه زمانی که یه فایل رو در SoundPlayer لود میکنیم (play نه) ، در اون زمان ، فقط header فایل را میخونه؟ و وقتی play اش میکنیم ، شروع به خوندن قسمت data اش میکنه؟
     
    نوشته شده توسط SajjadKhati در ‏13 می 2018
  15. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113
    من که قصد ندارم بهتون پیشنهاد کنم چه روشی رو پیاده سازی کنید، صرفا خواستم مطلع تون کنم که پخش یک Sample موردی نیست که بشه برایش رخدادی تصور کرد و نباید در کتابخانه ها دنبال همچین موردی بگردید.

    بله.

    نه فقط header اش، به اندازه بافر ای که برای پخش بی وقفه اش در نظر گرفته داده صوتی میخونه، اگر داده صوتی طولانی نباشه برای فراخوانی کل اش کافیه اما در کل قرار نیست کل داده صوتی رو بیاره تو بافر. غیر از این نمیتونه باشه، بافر صوتی سیستم یک فضای محدودی حافظه بافر داره و کارت صوتی یک فضای محدودتری حافظه فیزیکی برای بافر خودش. این بافر ها برای جلوگیری از قطع شدن روال پخش هستند وگرنه لزومی نداره به اندازه کل صوت ورودی بافر وجود داشته باشه. نباید توقع داشت که کل داده های یک wave غیر فشرده که ممکنه چند صد مگابایت بشه رو یکجا داخل بافر نگهداره. ماهیت پخش صوتی و تصویری همیشه بر مبنای Stream بوده.
     
    نوشته شده توسط the_king در ‏14 می 2018
    SajjadKhati از این پست تشکر کرده است.
  16. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83
    سلام
    ممنون استاد علی
    من کد زیر را نوشتم ولی درست کار نمیکنه . جالب اینجاست که آهنگ تموم میشه ، رسم اش باز هم انجام میشه :green:


    کد (Text):
        public partial class FormTest2 : Form
        {
            private DataGridView _grid;
            private Bitmap BitmapDanceLight;
            private byte[] AllWavHeaderData;
            private byte[] WaveDatas;
            private int WaveArrayCounter;
            private int x1;
            private int y1;
            private int x2;
            private int y2;

            public FormTest2()
            {
                InitializeComponent();
                this.BitmapDanceLight = new Bitmap(this.panelDanceLight.ClientSize.Width, this.panelDanceLight.ClientSize.Height);
                this.x1 = 0;
                this.y1 = this.BitmapDanceLight.Height;
                this.WaveArrayCounter = 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();
            }

            private void wavPlayer_LoadCompleted(object sender, AsyncCompletedEventArgs e)
            {
                System.Windows.Forms.Timer tmrWav = new System.Windows.Forms.Timer();
                tmrWav.Enabled = true;
                tmrWav.Interval = 40;
                tmrWav.Tick += new EventHandler(this.tmrWav_Tick);
                this.tmrWav_Tick(tmrWav, new EventArgs());
            }
         
            private void tmrWav_Tick(object sender, EventArgs e)
            {
                // AllWavHeaderData WaveDatas   40 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 = this.BitmapDanceLight.Height - this.WaveDatas[this.WaveArrayCounter]; //

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

                    this.x1 = this.x2;
                    this.y1 = this.y2;
                    this.WaveArrayCounter += 7056;
                }

                this.panelDanceLight.Invalidate();
            }

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

    یه panel هم اضافه کردم که توی پنل رسم میشه
    مشخصات آهنگ ، فرمت wav هه و sample rate 44100 hz و bit depth 16 bite و 2 کانال هه هست و حجم کل فایل 71,769,100 بایت هست به مدت 6 دقیقه و 46 ثانیه (کلا 406 ثانیه)
    سودوکدش رو این جوری تحلیل کردم که بیت ریت برای 1 ثانیه اش (1000 میلی ثانیه) میشه :
    44100 * 2 * 2 = 176400 بایت بر ثانیه
    من میخوام هر 40 میلی ثانیه ، رسم انجام بشه پس بیت ریت برای 40 میلی ثانیه اش را باید حساب میکردم که میشد 176400 / 25 که میشه 7056 بایت در هر 40 میلی ثانیه پس باید هر بار که تایمر (40 میلی ثانیه) اجرا میشه ، در اون آرایه ی WaveDatas که اطلاعات دیتای فایل هست ، 7056 تا عضو ، از اون عضوی که در حال حاضر هست ، بالاتر بره و رسم کنه
    درسته؟
    اگه درست نیست (که نتایج نشون میده انگار درست نیست) ، پس باید با چه روشی رفت؟
    ممنون
     
    نوشته شده توسط SajjadKhati در ‏15 می 2018
  17. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113
    پله پله کار کنید، اول یک همچین کدی رو اجرا کنید و ببینید دو Timer با Interval های 40 و 400 میلی ثانیه ای چقدر دقت دارند :
    کد (Text):
            private readonly Timer _timer1 = new Timer() { Interval = 40 };
            private readonly Timer _timer2 = new Timer() { Interval = 400 };
            private readonly ListBox _listBox1 = new ListBox() { Dock = DockStyle.Fill };
            private int c1 = 0, c2 = 0;
            private DateTime _startTime;

            private void button1_Click(object sender, EventArgs e)
            {
                button1.Visible = false;
                _listBox1.Parent = this;
                _timer1.Tick += timer1_Tick;
                _timer2.Tick += timer2_Tick;
                _startTime = DateTime.Now;
                _timer1.Enabled = true;
                _timer2.Enabled = true;
            }

            private void timer2_Tick(object sender, EventArgs e)
            {
                c2 += 400;
                _listBox1.Items.Add($"{c1}\t{c2}\t{DateTime.Now.Subtract(_startTime).TotalMilliseconds:0}");
                _listBox1.TopIndex = _listBox1.Items.Count - 1;
            }

            private void timer1_Tick(object sender, EventArgs e)
            {
                c1 += 40;
            }
    شما می توانید توقع داشته باشید که 40 میلی ثانیه بعد رخدادی برای اجرا شدن کدتون بوجود بیاد ولی نمی توانید توقع داشته باشید که نخ فرم تون همیشه اونقدر بیکار باشه که هیچ تاخیری بین رخداد ها اتفاق نیافته. هر چقدر که زمان بیشتری از اجرا کدتون میگذره خطاهای زمانی بیشتر خودشو نشون میده. در نظر بگیرید که تایمر مستقل از نخ کد شما نیست و کد شما هم بر اساس فرصت اجرایی که در نخ بهش داده میشه کد رخداد رو اجرا می کنه. تاخیر در اجرا اجتناب ناپذیره و کلا کار Timer از دقت بالایی برخوردار نیست.
     
    نوشته شده توسط the_king در ‏16 می 2018
    SajjadKhati از این پست تشکر کرده است.
  18. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83

    سلام
    ممنون استاد علی
    خوب پس با چه روشی باید رفت؟
    یعنی این رقص نورهایی که در pot player و ... بصورت همزمان با صوت ایجاد میشه ، از چه روشی میرن؟
     
    نوشته شده توسط SajjadKhati در ‏16 می 2018
  19. SajjadKhati

    SajjadKhati کاربر فعال <A href="http://forum.majidonline.com/f

    ارسال‌ها:
    1,063
    تشکر شده:
    373
    امتیاز دستاورد:
    83
    من الان بعد از play کردن (قبل از رسم) ، 1100 میلی ثانیه نخ مربوط به رسم را متوقف کردم تا هدر فایل خونده بشه . اوایل اش خیلی بهتر شد ولی همونطور که گفتین ، آخراش خراب تر میشد
    اما 2 تا سئوال :
    1) دقیق چقدر طول میکشه که بعد از play کردن ، فقط هدر فایل خونده بشه؟
    2) چرا وقتی آهنگ تموم میشه ، رسم هنوز ادامه داره؟ (من تا 2 تا 3 دقیقه دیدم ادامه داشت) . باید بعد از پخش ، ارور بده چون از تعداد اعضای آرایه ، تجاوز میکنه!
     
    آخرین ویرایش: ‏16 می 2018
    نوشته شده توسط SajjadKhati در ‏16 می 2018
  20. the_king

    the_king مدیرکل انجمن

    ارسال‌ها:
    10,632
    تشکر شده:
    10,648
    امتیاز دستاورد:
    113
    بر اساس زمانی که الان هست کار انجام میدهند، نه اینکه ترتیبی داده رو با یک نرخ مشخص بخونند. شما وقتی در حالت ترتیبی هر بار N نمونه به جلو پیشرفت می کنید کاری به زمان ندارید، چشم بسته دارید بر اساس یک ترتیبی عمل می کنید که مستقل از زمانه. وقتی در زمان 12.4 هستید باید نمونه ای رو بخونید که در زمان 12.4 بهش میرسه. با زمان فعلی کار کنید، کاری نداشته باشید که چند تا نمونه از دفعه جلوتر رفتید. ببینید الان چقدر زمان از شروع پخش گذشته و نوبت چه نمونه ای شده.

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

به اشتراک بگذارید