طرق ضغط / تخزين الوسائط في WAVE و JPEG ، الجزء 1

أهلا وسهلا بك! تهدف سلسلة مقالاتي الأولى إلى دراسة طرق ضغط وتخزين الصور / الصوت ، مثل JPEG (صورة) و WAVE (صوت) ، وسوف تتضمن أيضًا أمثلة لبرامج تستخدم هذه التنسيقات (.jpg ، .wav) في الممارسة. في هذا الجزء سوف ننظر في الموجة.


القصة


WAVE (تنسيق ملف صوتي Waveform) هو تنسيق ملف حاوية لتخزين تسجيلات دفق الصوت. عادة ما تستخدم هذه الحاوية لتخزين الصوت غير المضغوط في تعديل شفرة النبض. (مقتبس من ويكيبيديا)

تم اختراعه ونشره في عام 1991 مع RIFF بواسطة Microsoft و IBM (شركات تكنولوجيا المعلومات الرائدة في ذلك الوقت).


هيكل الملف


يحتوي الملف على جزء رأس ، البيانات نفسها ، لكن لا يوجد تذييل. يزن الرأس إجمالي 44 بايت.
يحتوي الرأس على إعدادات لعدد البتات في العينة ، وتكرار إزالة التعرية ، وعمق الصوت ، إلخ. المعلومات اللازمة للحصول على بطاقة الصوت. (يجب كتابة جميع قيم الجدول الرقمي بترتيب Little-Endian)


اسم كتلةحجم الكتلة (ب)الوصف / الغرضالقيمة (بالنسبة للبعض ثابتة
chunkId4تحديد ملف كحاوية وسائط0x52494646 في Big-Endian ("RIFF")
chunkSize4حجم الملف بأكمله دون chunkId و chunkSizeFILE_SIZE - 8
شكل4اكتب التعريف من RIFF0x57415645 في Big-Endian ("WAVE")
subchunk1Id4لشغل المزيد من مساحة الملف شكل مستمر0x666d7420 في Big-Endian ("fmt")
subchunk1Size4الرأس المتبقي (بالبايت)16 افتراضيًا (للحالة بدون ضغط دفق الصوت)
audioFormat2تنسيق الصوت (يعتمد على طريقة الضغط وبنية البيانات الصوتية)1 (بالنسبة لـ PCM ، والتي ندرسها)
numChannels2عدد القنوات1/2 ، نأخذ قناة واحدة (3/4/5/6/7 ... - مسار صوتي محدد ، على سبيل المثال 4 لصوت رباعي ، إلخ)
طريقة sampleRate4تردد أخذ العينات الصوتية (في هيرتز)كلما زاد حجم الصوت كلما كان ذلك أفضل ، ولكن ستكون هناك حاجة لمزيد من الذاكرة لإنشاء مسار صوت بنفس الطول ، والقيمة الموصى بها هي 48000 (جودة الصوت الأكثر قبولًا)
byteRate4عدد البايتات في 1 ثانيةSampleRate numChannels bitsPerSample (فيما يلي)
blockAlign2عدد البايتات لعينة واحدةnumChannels * bitsPerSample: 8
bitsPerSample2عدد البتات لكل 1 عينة (العمق)أي رقم يكون مضاعف 8. كلما كان الصوت أفضل كلما كان أفضل ، من 32 بت لا يوجد اختلاف بالنسبة للشخص
subchunk2Id4العلامة المرجعية لبداية البيانات (نظرًا لأنه قد يكون هناك عناصر رأسية أخرى بناءً على audioFormat)0x64617461 في Big-Endian ("البيانات")
subchunk2Size4حجم مساحة البياناتحجم البيانات في كثافة العمليات
معطياتbyteRate * مدة الصوتالبيانات الصوتية؟

موجة مثال


يمكن ترجمة الجدول السابق بسهولة إلى بنية C ، ولكن لغتنا اليوم هي Python. أسهل ما تفعله باستخدام الموجة هو مولد الضوضاء. لهذه المهمة ، نحن لسنا بحاجة إلى بايت عالية وضغط.
للبدء ، نستورد الوحدات اللازمة:


# WAV.py from struct import pack #  py-     C from os import urandom #    /dev/urandom,  windows: # from random import randint # urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)]) #   windows, .. urandom'    from sys import argv, exit #      if len(argv) != 3: # +1   (-1,   ) print('Usage: python3 WAV.py [num of samples] [output]') exit(1) 

بعد ذلك ، نحتاج إلى إنشاء جميع المتغيرات الضرورية من الجدول وفقًا لأحجامها. تعتمد القيم المتغيرة فيه فقط على numSamples (عدد العينات). كلما زاد عددهم ، كلما طالت مدة الضوضاء.


 numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    ,     .  1000-  ,   bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # numChannels * BPS / 8 subchunk2ID = b'data' subchunk2Size = pack('<L', numSamples * 2 * 4) # * numChannels * BPS / 8 chunkSize = pack('<L', 36 + numSamples * 2 * 4) # 36 + subchunk2Size data = urandom(1000 * 2 * 4 * numSamples) #   

يبقى فقط لكتابتها بالتسلسل اللازم (كما في الجدول):


 with open(output_path, 'wb') as fh: fh.write(chunkId + chunkSize + Format + subchunk1ID + subchunk1Size + audioFormat + numChannels + sampleRate + byteRate + blockAlign + bitsPerSample + subchunk2ID + subchunk2Size + data) #  

وهكذا ، فعلت. لاستخدام البرنامج النصي ، نحتاج إلى إضافة وسيطات سطر الأوامر الضرورية:
python3 WAV.py [num of samples] [output]
عدد العينات - العد عينات
الإخراج - المسار إلى ملف الإخراج


فيما يلي رابط لملف صوتي تم اختباره مع وجود ضوضاء ، ولكن لحفظ الذاكرة ، قمت بخفض BPS إلى 1b / s وانخفض عدد القنوات إلى 1 (مع دفق صوت ستيريو غير مضغوط 32 كيلو بت بسرعة 64 كيلو بايت ، تم إيقاف 80M من ملف .wav نظيف ، و 10 فقط): https: / /instaud.io/3Dcy


الشفرة بأكملها (WAV.py) (تحتوي الشفرة على العديد من القيم المكررة للمتغيرات ، هذا مجرد رسم تخطيطي):


 from struct import pack #  py-     C from os import urandom #    /dev/urandom,  windows: # from random import randint # urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)]) #   windows, .. urandom'    from sys import argv, exit #      if len(argv) != 3: # +1   (-1,   ) print('Usage: python3 WAV.py [num of samples] [output]') exit(1) numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    . bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # numChannels * BPS / 8 subchunk2ID = b'data' subchunk2Size = pack('<L', numSamples * 2 * 4) # * numChannels * BPS / 8 chunkSize = pack('<L', 36 + numSamples * 2 * 4) # 36 + subchunk2Size data = urandom(1000 * 2 * 4 * numSamples) #   with open(output_path, 'wb') as fh: fh.write(chunkId + chunkSize + Format + subchunk1ID + subchunk1Size + audioFormat + numChannels + sampleRate + byteRate + blockAlign + bitsPerSample + subchunk2ID + subchunk2Size + data) #     

يؤدي


لذلك تعلمت أكثر قليلاً عن الصوت الرقمي وكيف يتم تخزينه. في هذا المنشور ، لم نستخدم الضغط (audioFormat) ، ولكن لمراجعة كل مقالة شهيرة ستحتاج إلى مقالات 10. آمل أن تكون قد تعلمت شيئًا جديدًا لنفسك وسيساعدك ذلك في التطورات المستقبلية.
شكرا لك


مصادر

هيكل ملف WAV
WAV - ويكيبيديا

Source: https://habr.com/ru/post/ar450774/


All Articles