نمایه‌سازی صوتی

تغییرات پروژه از تاریخ 1396/11/11 تا حالا
پیدا کردن یک قطعه آهنگ با شنیدن بخشی از آن، نیاز به نمایه‌سازی مجموعه آهنگ‌ها دارد، درست مثل جستجوی واژه‌ها.

# مقدمه:
گاهی در بین راه  یا  در رستوران , در تاکسی آهنگی را  می شنویم که جذبمان می کند . اما نه می توانیم خواننده ی آن  و نه  متن آن را تشخیص بدهیم.
برای رفع این مشکل application  هایی مانند shazam , google sound search وجود دارد که با پخش موزیک برای آن , مشخصات موزیک مربوطه را پیدا
می کند.

 Shazam Entertainment Ltd: 
 یک شرکت توسعه نرم افزار بریتانیا است که
برنامه ای را ایجاد می کند که می تواند موسیقی، فیلم، تبلیغات و برنامه های
تلویزیونی را براساس نمونه ای کوتاه و با استفاده از میکروفون در دستگاه شناسایی
کند. این نرم افزار برای ویندوز، macOS و گوشی های هوشمند در دسترس است

Google sound search :
 برنامه ای برای دستگاهای اندرویدی است که به صورت widget   قابل استفاده است که پخش موزیک
برای آن , نام و  خواننده ی موزیک مربوطه
را  به کاربر  اعلام می کند.

این application ها علاوه بر تطبیق دادن صدا با آهنگ مربوطه , می بایست  noise را از صدای پخش شده نیز بگیرد .
در این نوع  application ها کار اصلی تبدیل سیگنال پیوسته به گسسته است  که امروزه کارت صدای کامپیوتر ها این کار را انجام می دهند.
# کارهای مرتبط:

در این قسمت الگوریتمی که تشخیص موزیک را انجام می شود  را به اختصار توضیح می دهیم.
الگوریتم مربوطه audio  fingerprinting   نام دارد . به این دلیل این الگوریتم به این نام خوانده می شود که از هر موزیک در دیتابیس ابتدا  fingerprint  خواهد شد. یعنی به صورت برگشت پذیر کدگذاری خواهد شد.
![fft](https://boute.s3.amazonaws.com/286-fft.jpg)

در چنین برنامه هایی همواره دیتابیس هایی از آهنگ ها وجود دارد  که آهنگ وارد شده با یکی  از این آهنگ های دیتابیس تطبیق داده شود.
وقتی  کاربر یا ادمین برنامه آهنگی به دیتابیس اضافه کند دیتابیس  ۲ عمل باید روی  آهنگ ها انجام دهد:
۱- ساختن constellation map  از سیگنال ها.
۲- عمل hashing

**ساختن constellation map:**

 سیگنال صوتی که توسط سیستم دریافت می شود باید توسط نمودار  فرکانس-زمان نمایش داده شو برای تبدیل دامنه به فرکانس از تبدیل فوریه استفاده  می شود که  سیگنال را  با دامنه ی فرکانسی نمایش  خواهد داد. برای بالا بردن سرعت عملیات از fft  که  همان تبدیل فوریه سریع است استفاده  می شود.
 حال سیگنالی  که این تغییرات را  یافت می بایست نقاط peak  نمودار آن(spectrogram) ذخیره شود.
 نقاط peak می تواند نقاطی باشد که انرژی سیگنال در ان نقاط بیشتر است.
 همچنین می توان نقاطی  که دامنه ی فرکانس در آنها بیشتر است نیز می تواند  نقاط peak باشد.
 نقاط peak  به صورت گسسته ذخیره  می شوند بدین معنا کمحور زمان نیز گسسته خواهد بود.
این عمل باعث  آسان تر شدن  ذخیره و جست و جو خواهد بود. همچنین ذخیره کردن نقاط  peak  و  حذف کردن بقیه تقاط باعث  کاهش مقدار قابل توجهی از noise  خواهد شد.
![spectogram+constllation map](https://boute.s3.amazonaws.com/286-spctrum.jpg)
**عمل  hashing**
 یکی از شرایط این الگوریتم وجود بی نظمی زیاد است. بدین معنا که دیتاها باید اختلاف زیادی باهم داشته باشند. اگر ما نقاط در نمودارقبل را ذخیره کنیم اختلاف بین نقاط کم خواهد بود درنتیجه تشابه  فایل ها بیشتر و تشخیص سخت تر خواهد بود.
 بدین منظور نقاط موجود در  constellation map را hash  می کنیم. 
 برای hash کردن هر ۲ نقطه ی متوالی  از    constellation map  را درنظر میگیریم و به نقطه ی اول Anchor point و به نقطه ی دوم target zone می گوییم . پس برای عمل hash  ۲ مولفه ی  ذکر شده  به علاوه ی اختلاف زمانی  بین ۲ نقطه را داریم  که این ۳ مولفه را دردیتابیس ذخیره می کنیم.
 اگر هر مولفه بفرض ۱۰ بیت فضا بگیرد که در جمع ۳۰ بیت خواهد شد در مقایسه با ذخیرهی صرفا نقاط ۲۰ بیت بیشتر به ازای هر نقطه خواهد گرفت .
 اما سرعت سرچ کردن چندین هزار برابر خواهد شد.

 ![hashing  paramemters + time](https://boute.s3.amazonaws.com/286-Screenshot_1.jpg)

آیدی موزیکی که در دیتابیس ذخیره می شود یک عدد ۶۴ بیتی است که  ۳۲ بیت آن برای hash و ۳۲ بیت دیگر آن برای خود id  و time offset است.
**عملیات سرچ کردن:**
پس از این که عمل hashing نیز صورت گرفت سرچ کردن موزیک آغاز می شود.
هنگامی که موزیک سمپل یا همان موزیک ناشناخته به ورودی برنامه داده می شود  مانند سایر موزیک های دیتابیس عمل hashing صورت میگیرد .
سپس باید موزیک با موزیک های داخل دیتابیس مقایسه شود. برای این کار در هردنقطه ای که ۲ مولفه اول  hash ها باهم برابر بودند به bin هایی دسته بندی خواهند شد که این دسته بندی براساس trackID خواهد بود.
در هر دسته این hash  ها با تایم ها مطابقت داده خواهند شد که  در صورت مطابقت ب عنوان matching نهایی درنظر گرفته خواهد شد. 
هر کدام از این bin ها که  تعداد matching بیشتری داشته باشد به عنوان موزیک تشخیص داده شاده انتخاب خواهد شد.

**سرعت search**
سرعت search در برنامه هایی که دیتابیس انها حدود ۲۰ هزار اهنگ  داشته باشد بین ۵ تا ۵۰۰ میلی ثانیه خواهد بود.که این مقدار به پارامترهای مختلفی از جمله کیفیت موزیک بستگی دارد.
# آزمایش‌ها:
![توضیح تصویر](https://boute.s3.amazonaws.com/286-ddddd.jpg)
***اجرای کد تست:***
الگوریتم fingerprinting را با استفاده  از پایتون و دیتابیس mysql پیاده یازی کرده ایم. 

در این برنامه تعدادی  آهنگ به عنوان دیتا ست در فولدر mp3 دارد و با پخش موزیک برای برنامه از طریق میکروفون لپتاپ درصورت تطبیق اهنگ با هر یک از آهنگ های دیتاست برنامه نام آهنگ را به عنوان خروجی چاپ می کند.
From mic with 2 seconds we recognized: {'song_id': 1, 'song_name': 'Brad-Sucks--Total-Breakdown', 'file_sha1': '02A83F248EFDA76A46C8B2AC97798D2CE9BC1FBE', 'confidence': 1, 'offset_seconds': 92.69406, 'offset': 1996}
درصورت پخش نشدن موزیک خروجی زیر را خواهد داد:
Nothing recognized -- did you play the song out loud so your mic could hear it? :)
همچنین این برنامه قابلیت این را دارد که موزیک از روی فایل لود شود که نام موزیک مورد نظر را در تابع زیر وارد می کنیم:
<pre>
song = djv.recognize(FileRecognizer, "Josh-Woodward--I-Want-To-Destroy-Something-Beautiful.mp3")
</pre>
که موزیک تشخیص داده به صورت زیر اعلام می شود:
From file we recognized: {'song_id': 2, 'song_name': 'Josh-Woodward--I-Want-To-Destroy-Something-Beautiful', 'file_sha1': 'C6364099D8E0DC297956EC9D8B2AC1B83403D407', 'confidence': 127098, 'offset_seconds': 0.0, 'match_time': 25.191730976104736, 'offset': 0}

این برنامه را با ران کردن  فایل example.py  اجرا می کنیم.
در این فایل ۲ تابع اصلی برای هر بار تشخیص آهنگ فراخوانی می شود:
<pre>
djv.fingerprint_directory("mp3", [".mp3",".wma"])
</pre>
که دایرکتوری قرار گرفتن موزیک هارا به آن معرفی می کنیم. همچنین فرمت هایی که در این دایرکتوری به عنوان موزیک شناخته می شوند را نیز وارد می کنیم.
 دیتابیس ما fingerprint های هر یک از این موزیک هارا ذخیره می کند و درصورت وجود fingerprint هر موزیک  دوباره آنرا fingerprint نخواهد کرد.


<pre>
if decoder.unique_hash(filename) in self.songhashes_set:    print "%s already fingerprinted, continuing..." % filename    continue
</pre>
<pre>
secs = 2
song = djv.recognize(MicrophoneRecognizer, seconds=secs)
</pre>
این تابع موزیک را از روی میکروفون می به عنوان ورودی دریافت می کند و اهنگ را تشخیص می دهد  و مشخصات آنرا به عنوان خروجی می دهد.
<pre>
def recognize(self, recognizer, *options, **kwoptions):   
	 r = recognizer(self)  
	   return r.recognize(*options, **kwoptions)
</pre>
ورودی این تابع را MicrophoneRecognizer است به این معنی که از میکروفون ورودی را دریافت میکند نه از دیسک.
<pre>
def recognize(self, seconds=10):  
  self.start_recording()  
    for i in range(0, int(self.samplerate / self.chunksize    * seconds)):     
       self.process_recording()     
         self.stop_recording()    
     return self.recognize_recording()
</pre>

در این تابع به اندازه یself.samplerate / self.chunksize    * seconds  صدا را از ورودی می خواند.
 در تابع recognize_recording تابع find_matches فراخوانی شده است که عمل fingerprint را روی موزیک ها انجام می دهد.و تابع align matches بررسی میکند که  fingerprint با موزیک داده شده برابر است  یا ن.
 در تابع fingerprint از توابع ماژول numpy برای تبدیل فوریه سریع(FFT) استفاده شده است .
پس از تبدیل فوریه الگوریتم باید local maximum  هارا بیابد و انهارا ذخیره کند و با استفاده از تابع زیر  این کارا می کند.

<pre>
local_max = maximum_filter(arr2D, footprint=neighborhood)
</pre>
سپس hash می کند و در دیتابیس ذخیره می کند.
+---------+-----------------------+------+-----+---------+-------+
| Field   | Type                  | Null | Key | Default | Extra |
+---------+-----------------------+------+-----+---------+-------+
| hash    | binary(10)            | NO   | PRI | NULL    |       |
| song_id | mediumint(8) unsigned | NO   | PRI | NULL    |       |
| offset  | int(10) unsigned      | NO   | PRI | NULL    |       |
+---------+-----------------------+------+-----+---------+-------+
***تست برنامه:***
برای تست این برنامه معیار های تغییر ما ثانیه ی پخش شدن آهنگ و افزایش نویز و تغییر تعداد دیتا ست هاست.
برای این کار ابتدا ۵ موزیک را در فولدر دیتاست اضافه کردیم و به مرور موزیک های بیشتری اضافه کردیم و تست را  شروع کردیم.
تغییر ثانیه ی پخش:
by microphone:
| Number Correct | Number of Seconds  |
| ----------------- | -------------- 
| 1                 | 40 / 50        
| 2                 | 42 / 50        
| 3                 | 44 / 50        
| 4                 | 47 / 50        
| 5                 | 47 / 50        
| 6                 | 50 / 50        
by file :
موزیکی که لود می شود شامل  چند ثانیه از هر موزیک خواهد بود.

| Number Correct | Number of Seconds  |
| ----------------- | -------------- 
| 1                 | 48 / 50        
| 2                 | 49 / 50        
| 3                 | 50 / 50        
| 4                 | 50 / 50        
| 5                 | 50 / 50        
| 6                 | 50 / 50        

درنتیجه بدیل نویز داشتن صدای میکروفون  نسبت به صدای اصلی نتایج درست کمتری خواهد داد.
تغییر نویز:
نویز شامل صداهایی است که از شدت صدای موزیک کمتر باشند.
نویز حتی می تواند موزیک دیگری باشد که در  بک گراند موزیک اصلی پخش می شود.
| Number Correct |         noise   |
| ----------------- | -------------- 
| 1                 | 20 / 20        
| 2                 | 17 / 20        
| 3                 | 16 / 20        
تغییر تعداد اهنگ های دیتا ست با ۵ ثانیه  :

| Number Correct | Number of Songs   |
| ----------------- | --------------  
| 5                 |   5 / 5         
| 7                 | 7 / 7           
| 10                 | 10 / 10        
| 15                 | 15 / 15        
| 20                 | 19 / 20        

پیوست کد:
https://github.com/mehraveh/audio-finger-printing

# کارهای آینده:
در این برنامه موزیک هایی که در دیتابیس نیستند را به احبار به یمی از موزیک های دیتابیس مپ می کند که درآینده این مشکل حل خواهد شد.
پیوست کد:

# مراجع
http://www.ee.columbia.edu/%7Edpwe/papers/Wang03-shazam.pdf
http://www.cs.cmu.edu/%7Eyke/musicretrieval/
      

# پیوندهای مفید:
https://www.bbc.co.uk/education/guides/zpfdwmn/revision/3
https://www.toptal.com/algorithms/shazam-it-music-processing-fingerprinting-and-recognition
https://en.wikipedia.org/wiki/Time_domain
https://en.wikipedia.org/wiki/Sampling_%28signal_processing%29
![توضیح تصویر]()
1.  [مفهوم نمایه سازی](http://fa.wikipedia.org/wiki/%D9%86%D9%85%D8%A7%DB%8C%D9%87)

2.  [Audio Fingerprinting with Python and Numpy](http://willdrevo.com/fingerprinting-and-audio-recognition-with-python.html)

3.  [Echoprint](http://echoprint.me/how)

4.  [Pydub(python library)](http://pydub.com/)

5.  [MySQL on Ubuntu](http://www.cs.wcupa.edu/rkline/index/mysql-lin.html)

6.  [Duplicate songs detector via audio fingerprinting](http://www.codeproject.com/Articles/206507/Duplicates-detector-via-audio-fingerprinting)