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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
این تاپیک رو زدم که سئوالات مربوط به ساختار و کار کردن فایل (فایل صوتی و عکس و تصویری) پرسیده شه

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

اولین سئوالم اینه استاد علی ، در پست 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 باید همون دسیبل (فرکانس های مختلف که صدا رو تولید میکنه) باشه . پس دسیبل این وسط چیه؟
اینا همه فرضیه ی من ان . اطلاعاتی ندارم چون منبع خوبی نیست که بخونم . منبع انگلیسی را خوندم ولی متوجه نشدم
 
آخرین ویرایش:

the_king

مدیرکل انجمن
توی هر ثانیه ، عددی توی فایل صوتی ذخیره میشه که بهش میگن sample rate . مثلا sample rate 44.1 KHz یعنی 44100 تا از این نمودارها (البته منظور از نمودار ، یه چیز ذهنی و فرضی هست) در یک ثانیه در فایل صوتی ذخیره میشه .

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

اگه نمودار بالا درست باشه ، sample rate باید همون دسیبل (فرکانس های مختلف که صدا رو تولید میکنه) باشه . پس دسیبل این وسط چیه؟

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ممنون استاد علی
با کلاس System.Media.SoundPlayer ، یه مثال کوچیک میزنین که در فایل wav ، مقدار sample depth (مقدار ثابتی هست در کل فایل دیگه؟) رو استخراج کنه، و بعد اطلاعات sample rate در 1 ثانیه ی اول از این فایل را هم استراج کنه؟
-------------------------
اون لینک sampling در ویکی پدیا را دیدم ولی متوجه نشدم . باز هم مفهوم دسیبل را خوب درک نکردم
بعد اینکه وقتی sample depth هست ، این مقدار مثلا 128kbps یا 320kbps (کیلو بیت بر ثانیه) دیگه چرا مشخص میشه؟ خوب یکی شون مشخص بشه ، اون یکی اتوماتیک درمیاد دیگه . درسته؟
 

the_king

مدیرکل انجمن
ممنون استاد علی
با کلاس System.Media.SoundPlayer ، یه مثال کوچیک میزنین که در فایل wav ، مقدار sample depth (مقدار ثابتی هست در کل فایل دیگه؟) رو استخراج کنه، و بعد اطلاعات sample rate در 1 ثانیه ی اول از این فایل را هم استراج کنه؟
-------------------------
اون لینک sampling در ویکی پدیا را دیدم ولی متوجه نشدم . باز هم مفهوم دسیبل را خوب درک نکردم
بعد اینکه وقتی sample depth هست ، این مقدار مثلا 128kbps یا 320kbps (کیلو بیت بر ثانیه) دیگه چرا مشخص میشه؟ خوب یکی شون مشخص بشه ، اون یکی اتوماتیک درمیاد دیگه . درسته؟
SoundPlayer پخش می کنه، چیزی رو براتون استخراج نمی کنه. بله. Sample Rate برای فایل های غیر فشرده PCM ثابته.
WaveFormat
بعد اینکه وقتی sample depth هست ، این مقدار مثلا 128kbps یا 320kbps (کیلو بیت بر ثانیه) دیگه چرا مشخص میشه؟ خوب یکی شون مشخص بشه ، اون یکی اتوماتیک درمیاد دیگه . درسته؟
حتی اگه بدونید Sample Depth ئه فرضا 16 بیتی است و فرکانس نمونه برداری 20kHZ ئه، باز هم بدون دانستن اینکه چند کانال صوتی داره نمی توانید Bit Rate اش رو تشخیص بدید. طبیعتا مشخص کردن همچین مقداری به وضوح حجمی که ذخیره کردن هر ثانیه اش نیاز داره مشخص می کنه و موردی نیست که بشه بسادگی ازش صرف نظر کرد.
 

SajjadKhati

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

the_king

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

SajjadKhati

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

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

Audio samples per second?

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

the_king

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

Audio samples per second?
کاربرد ها خیلی متفاوته، ممکنه 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
ولی اون چیز مورد نظرم را نیافتم . الان طبق اون چیزی که در پست دوم گفتن ، total length (in bytes) یک فایل صوتی را تقسیم بر زمان اش duration (in seconds) کنیم ، تعداد sample rate هایی که در یک ثانیه اجرا میشن را برمیگردونه؟
هدر فایل به هر بخشی از حجم فایل رو تشکیل میده، اما Sample Bit Rate مستقل از حجم هدر ئه، پس اگر حجم هدر رو از حجم کلی فایل کسر اش نکنید مقدار محاسبه شده تخمینی ئه و دقیق نیست، خطا داره، مقدار خطاش هم بستگی به حجم صوتی داره، برای یک صوت چند صد مگابایتی ناچیزه و بچشم نمیاد، ولی وقتی خود صوت حجم کمی داره اون حجم هدر هم مقدار قابل توجهی محسوب میشه. مثل اینه که تعداد سرنشینان خودرو اعم از راننده و مسافر رو بجای تعداد مسافرین ملاک قرار بدین، مقدار دقیقی بدست نمیاد، ولی وقتی خودرو بزرگی مثل اتوبوس باشه خطا ناچیزه.
تعدادِ sample rate با خودِ sample rate فرقی ندارن؟
تعداد Sample Rate یعنی چی؟ نداریم همچین چیزی.
 

SajjadKhati

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

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 منظورشه را چجوری میشه بدست آورد؟
کلا در کد زیر :

کد:
short sample16Bit = BitConverter.ToShort(buffer,index);
ورودی هاش یعنی buffer و index رو میگین از خروجی کدوم توابع بدست آورد و چی هستن؟
ممنون
 

the_king

مدیرکل انجمن
ممنون استاد علی
الان در لینک زیر :

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 را بدست بیارن؟

من مستنداتش رو ندیدم. باید مطالعه شون کنید، اما اینها Reader هستند، متد های Read دارند.
یا وقتی میگه :
"Then you would need to read through the file and get the sample values"
مقدار sample value که فکر کنم همون sample depth منظورشه را چجوری میشه بدست آورد؟

Sample Values که نمیتونه Sample Depth باشه. Sample Depth فقط یک مقدار ئه، بیشتر از یک مورد که نیست. متنی که نوشته تفسیر همون آرایه ای از بایت ها است که بجای بایت بایت بصورت داده های متوالی از یک نوع داده خاص مثل Int16 تفسیر بشه.
کلا در کد زیر :
کد:
short sample16Bit = BitConverter.ToShort(buffer,index);
ورودی هاش یعنی buffer و index رو میگین از خروجی کدوم توابع بدست آورد و چی هستن؟
ممنون
همون بحث تفسیر داده ای است که فرمت خام اش بصورت آرایه ای از بایت ها است. در حافظه buffer یک سری بایت قرار داره که نتیجه ذخیره سازی یک سری داده است که الزاما نوع داده شون شبیه هم نیست، ممکنه بیش از یک بایت هم باشند، هر قسمت اش ممکنه در اصل نوع داده متفاوتی بوده باشه اما در کنار هم بصورت یک آرایه از بایت ها است. وقتی می خواهید یک داده فرضا Short ئه 16 بیتی رو از این حافظه دریافت کنید، برای BitConverter اون حافظه buffer و موقعیت اولین خانه حافظه (index) مربوط به اون داده در اون buffer رو مشخص می کنید، به اون index عموما offset هم می گویند. BitConverter به اندازه طول اون نوع داده خاص (فرضا دو بایت برای short) رو از آرایه از اون موقعیت خاص میخونه و تفسیر می کنه و بیت هاشو با ترتیب درست ترکیب می کنه و بصورت یک داده فرضا Short بر میگردونه.
 

SajjadKhati

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


Streaming Data from a WAV File

کد:
        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 باشه) را رسم کنیم؟
 

the_king

مدیرکل انجمن
اول اینکه این اطلاعاتی که توی حافظه رفت (همین آرایه ی waveDatas) ، زمانی که توی حافظه بره ، اسمش میشه استریم؟ یعنی یا فایل داریم ، یا توی حافظه ی رم اگه بارگذاری بشه ، اسمش استریم میشه؟

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

SajjadKhati

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

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

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

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بعد اینکه زمانی که یه فایل رو در SoundPlayer لود میکنیم (play نه) ، در اون زمان ، فقط header فایل را میخونه؟ و وقتی play اش میکنیم ، شروع به خوندن قسمت data اش میکنه؟
 

the_king

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

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

بعد اینکه زمانی که یه فایل رو در SoundPlayer لود میکنیم (play نه) ، در اون زمان ، فقط header فایل را میخونه؟ و وقتی play اش میکنیم ، شروع به خوندن قسمت data اش میکنه؟
نه فقط header اش، به اندازه بافر ای که برای پخش بی وقفه اش در نظر گرفته داده صوتی میخونه، اگر داده صوتی طولانی نباشه برای فراخوانی کل اش کافیه اما در کل قرار نیست کل داده صوتی رو بیاره تو بافر. غیر از این نمیتونه باشه، بافر صوتی سیستم یک فضای محدودی حافظه بافر داره و کارت صوتی یک فضای محدودتری حافظه فیزیکی برای بافر خودش. این بافر ها برای جلوگیری از قطع شدن روال پخش هستند وگرنه لزومی نداره به اندازه کل صوت ورودی بافر وجود داشته باشه. نباید توقع داشت که کل داده های یک wave غیر فشرده که ممکنه چند صد مگابایت بشه رو یکجا داخل بافر نگهداره. ماهیت پخش صوتی و تصویری همیشه بر مبنای Stream بوده.
 

SajjadKhati

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


کد:
    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 تا عضو ، از اون عضوی که در حال حاضر هست ، بالاتر بره و رسم کنه
درسته؟
اگه درست نیست (که نتایج نشون میده انگار درست نیست) ، پس باید با چه روشی رفت؟
ممنون
 

the_king

مدیرکل انجمن
سلام
ممنون استاد علی
من کد زیر را نوشتم ولی درست کار نمیکنه . جالب اینجاست که آهنگ تموم میشه ، رسم اش باز هم انجام میشه :green:
یه 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 تا عضو ، از اون عضوی که در حال حاضر هست ، بالاتر بره و رسم کنه
درسته؟
اگه درست نیست (که نتایج نشون میده انگار درست نیست) ، پس باید با چه روشی رفت؟
ممنون
پله پله کار کنید، اول یک همچین کدی رو اجرا کنید و ببینید دو Timer با Interval های 40 و 400 میلی ثانیه ای چقدر دقت دارند :
کد:
        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 از دقت بالایی برخوردار نیست.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
پله پله کار کنید، اول یک همچین کدی رو اجرا کنید و ببینید دو Timer با Interval های 40 و 400 میلی ثانیه ای چقدر دقت دارند :
کد:
        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 از دقت بالایی برخوردار نیست.

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
من الان بعد از play کردن (قبل از رسم) ، 1100 میلی ثانیه نخ مربوط به رسم را متوقف کردم تا هدر فایل خونده بشه . اوایل اش خیلی بهتر شد ولی همونطور که گفتین ، آخراش خراب تر میشد
اما 2 تا سئوال :
1) دقیق چقدر طول میکشه که بعد از play کردن ، فقط هدر فایل خونده بشه؟
2) چرا وقتی آهنگ تموم میشه ، رسم هنوز ادامه داره؟ (من تا 2 تا 3 دقیقه دیدم ادامه داشت) . باید بعد از پخش ، ارور بده چون از تعداد اعضای آرایه ، تجاوز میکنه!
 
آخرین ویرایش:

the_king

مدیرکل انجمن
سلام
ممنون استاد علی
خوب پس با چه روشی باید رفت؟
یعنی این رقص نورهایی که در pot player و ... بصورت همزمان با صوت ایجاد میشه ، از چه روشی میرن؟
بر اساس زمانی که الان هست کار انجام میدهند، نه اینکه ترتیبی داده رو با یک نرخ مشخص بخونند. شما وقتی در حالت ترتیبی هر بار N نمونه به جلو پیشرفت می کنید کاری به زمان ندارید، چشم بسته دارید بر اساس یک ترتیبی عمل می کنید که مستقل از زمانه. وقتی در زمان 12.4 هستید باید نمونه ای رو بخونید که در زمان 12.4 بهش میرسه. با زمان فعلی کار کنید، کاری نداشته باشید که چند تا نمونه از دفعه جلوتر رفتید. ببینید الان چقدر زمان از شروع پخش گذشته و نوبت چه نمونه ای شده.
من الان بعد از play کردن (قبل از رسم) ، 1100 میلی ثانیه نخ مربوط به رسم را متوقف کردم تا هدر فایل خونده بشه . اوایل اش خیلی بهتر شد ولی همونطور که گفتین ، آخراش خراب تر میشد
اما 2 تا سئوال :
1) دقیق چقدر طول میکشه که بعد از play کردن ، فقط هدر فایل خونده بشه؟

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

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

بالا