كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

قبل التاريخ

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

كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

ومع ذلك، وجدت في بعض أشرطة الكاسيت تسجيلات من الواضح أنها لم يتم إجراؤها بواسطة كمبيوتر ZX Spectrum. لقد بدت مختلفة تمامًا، وعلى عكس التسجيلات من الكمبيوتر المذكور، لم تبدأ بمحمل تشغيل BASIC قصير، والذي عادة ما يكون موجودًا في تسجيلات جميع البرامج والألعاب.

لقد طاردني هذا لبعض الوقت - أردت حقًا معرفة ما كان مخفيًا فيها. إذا كان بإمكانك قراءة الإشارة الصوتية كسلسلة من البايتات، فيمكنك البحث عن الأحرف أو أي شيء يشير إلى أصل الإشارة. نوع من علم الآثار الرجعية.

الآن بعد أن قطعت كل الطريق وألقيت نظرة على الملصقات الموجودة على أشرطة الكاسيت نفسها، ابتسمت لأنني

وكان الجواب أمام عيني طوال الوقت
يوجد على ملصق الكاسيت الأيسر اسم كمبيوتر TRS-80، وأسفل اسم الشركة المصنعة مباشرةً: "تم تصنيعه بواسطة راديو شاك في الولايات المتحدة الأمريكية"

(إذا كنت تريد الاحتفاظ بالمكائد حتى النهاية، فلا تدخل تحت المفسد)

مقارنة الإشارات الصوتية

أولاً، دعونا نقوم برقمنة التسجيلات الصوتية. يمكنك الاستماع إلى ما يبدو مثل:


وكالعادة التسجيل من كمبيوتر ZX Spectrum يبدو:


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

ومن الضروري أن نقول شيئا عن شكل الإشارة نفسها. على سبيل المثال، في ZX Spectrum يكون شكله مستطيلًا:

كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

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

بعد استقبال نبضة المزامنة، يسجل الكمبيوتر كل ارتفاع/انخفاض للإشارة، وقياس مدتها. إذا كانت المدة أقل من حد معين، فسيتم كتابة البت 1 في الذاكرة، وإلا 0. يتم جمع البتات في بايتات وتكرر العملية حتى يتم استلام N بايت. عادةً ما يتم أخذ الرقم N من رأس الملف الذي تم تنزيله. تسلسل التحميل كما يلي:

  1. نغمة الطيار
  2. الرأس (طول ثابت)، يحتوي على حجم البيانات التي تم تنزيلها (N)، واسم الملف ونوعه
  3. نغمة الطيار
  4. البيانات نفسها

للتأكد من تحميل البيانات بشكل صحيح، يقرأ ZX Spectrum ما يسمى بايت التكافؤ (بايت التكافؤ)، والذي يتم حسابه عند حفظ ملف عن طريق XORing كافة بايتات البيانات المكتوبة. عند قراءة ملف، يقوم الكمبيوتر بحساب بايت التكافؤ من البيانات المستلمة، وإذا كانت النتيجة تختلف عن تلك المحفوظة، يعرض رسالة الخطأ "خطأ في تحميل شريط R". بالمعنى الدقيق للكلمة، يمكن للكمبيوتر إصدار هذه الرسالة في وقت مبكر إذا لم يتمكن، عند القراءة، من التعرف على النبض (ضائع أو أن مدته لا تتوافق مع حدود معينة)

لذا، دعونا نرى الآن كيف تبدو الإشارة غير المعروفة:

كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

هذه هي النغمة التجريبية. ويختلف شكل الإشارة بشكل كبير، ولكن من الواضح أن الإشارة تتكون من تكرار نبضات قصيرة بتردد معين. عند تردد أخذ العينات 44100 هرتز، تبلغ المسافة بين "القمم" حوالي 48 عينة (وهو ما يتوافق مع تردد ~ 918 هرتز). دعونا نتذكر هذا الرقم.

لنلق نظرة الآن على جزء البيانات:

كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

إذا قمنا بقياس المسافة بين النبضات الفردية، يتبين أن المسافة بين النبضات "الطويلة" لا تزال ~48 عينة، وبين القصيرة - ~24. بالنظر إلى الأمام قليلاً، سأقول أنه في النهاية اتضح أن النبضات "المرجعية" بتردد 918 هرتز تتبع بشكل مستمر، من بداية الملف إلى نهايته. يمكن الافتراض أنه عند إرسال البيانات، إذا تمت مواجهة نبضة إضافية بين النبضات المرجعية، فإننا نعتبرها البتة 1، وإلا 0.

ماذا عن نبض المزامنة؟ دعونا نلقي نظرة على بداية البيانات:

كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

تنتهي النغمة التجريبية وتبدأ البيانات على الفور. وبعد قليل، وبعد تحليل عدة تسجيلات صوتية مختلفة، تمكنا من اكتشاف أن البايت الأول من البيانات هو نفسه دائمًا (10100101b، A5h). قد يبدأ الكمبيوتر في قراءة البيانات بعد استلامها.

يمكنك أيضًا الانتباه إلى إزاحة النبضة المرجعية الأولى مباشرةً بعد آخر نبضة في بايت المزامنة. تم اكتشافه لاحقًا أثناء عملية تطوير برنامج التعرف على البيانات، عندما لم يكن من الممكن قراءة البيانات الموجودة في بداية الملف بشكل ثابت.

الآن دعونا نحاول وصف الخوارزمية التي ستقوم بمعالجة ملف صوتي وتحميل البيانات.

تحميل البيانات

أولاً، دعونا نلقي نظرة على بعض الافتراضات لإبقاء الخوارزمية بسيطة:

  1. سننظر فقط في الملفات بتنسيق WAV؛
  2. يجب أن يبدأ الملف الصوتي بنغمة إرشادية ويجب ألا يحتوي على الصمت في البداية
  3. يجب أن يحتوي الملف المصدر على معدل أخذ عينات يبلغ 44100 هرتز. في هذه الحالة، تم تحديد المسافة بين النبضات المرجعية لـ 48 عينة بالفعل ولا نحتاج إلى حسابها برمجيًا؛
  4. يمكن أن يكون تنسيق العينة أي (8/16 بت/نقطة عائمة) - لأنه عند القراءة يمكننا تحويله إلى التنسيق المطلوب؛
  5. نحن نفترض أن الملف المصدر تمت تسويته من خلال السعة، مما يؤدي إلى استقرار النتيجة؛

ستكون خوارزمية القراءة كما يلي:

  1. نقرأ الملف في الذاكرة، وفي نفس الوقت نقوم بتحويل تنسيق العينة إلى 8 بتات؛
  2. تحديد موضع النبضة الأولى في البيانات الصوتية. للقيام بذلك، تحتاج إلى حساب عدد العينة بأقصى سعة. للتبسيط، سوف نقوم بحسابها مرة واحدة يدويًا. لنحفظه في المتغير prev_pos;
  3. أضف 48 إلى موضع النبضة الأخيرة (pos := prev_pos + 48)
  4. نظرًا لأن زيادة الموضع بمقدار 48 لا يضمن أننا سنصل إلى موضع النبض المرجعي التالي (عيوب الشريط، والتشغيل غير المستقر لآلية محرك الشريط، وما إلى ذلك)، فإننا نحتاج إلى ضبط موضع نبض نقطة البيع. للقيام بذلك، خذ قطعة صغيرة من البيانات (pos-8;pos+8) وابحث عن قيمة السعة القصوى عليها. سيتم تخزين الموضع المقابل للحد الأقصى في نقاط البيع. هنا 8 = 48/6 هو ثابت تم الحصول عليه تجريبيًا، مما يضمن أننا سنحدد الحد الأقصى الصحيح ولن يؤثر على النبضات الأخرى التي قد تكون قريبة. في الحالات السيئة جدًا، عندما تكون المسافة بين النبضات أقل بكثير أو أكبر من 48، يمكنك تنفيذ بحث قسري عن النبضة، لكن في نطاق المقالة لن أصف ذلك في الخوارزمية؛
  5. في الخطوة السابقة، سيكون من الضروري أيضًا التحقق من العثور على النبض المرجعي على الإطلاق. أي أنك إذا بحثت ببساطة عن الحد الأقصى، فهذا لا يضمن وجود الدافع في هذا الجزء. في آخر تطبيق لي لبرنامج القراءة، قمت بالتحقق من الفرق بين قيم السعة القصوى والدنيا على مقطع ما، وإذا تجاوز حدًا معينًا، أحسب وجود دفعة. والسؤال هو أيضًا ما يجب فعله إذا لم يتم العثور على النبض المرجعي. هناك خياران: إما أن البيانات قد انتهت ويتبعها الصمت، أو أن هذا يعتبر خطأ في القراءة. ومع ذلك، فإننا سوف نحذف هذا لتبسيط الخوارزمية؛
  6. في الخطوة التالية، نحتاج إلى تحديد وجود نبضة بيانات (بت 0 أو 1)، ولهذا نأخذ منتصف المقطع (prev_pos;pos) middle_pos يساوي middle_pos := (prev_pos+pos)/2 و في بعض أحياء middle_pos على المقطع (middle_pos-8;middle_pos +8) لنحسب السعة القصوى والدنيا. إذا كان الفرق بينهما أكثر من 10، نكتب البتة 1 في النتيجة، وإلا فإن 0. 10 هو ثابت تم الحصول عليه تجريبيًا؛
  7. احفظ الموضع الحالي في prev_pos (prev_pos := pos)
  8. كرر بدءاً من الخطوة 3 حتى نقرأ الملف بأكمله؛
  9. يجب حفظ مصفوفة البت الناتجة كمجموعة من البايتات. نظرًا لأننا لم نأخذ في الاعتبار بايت المزامنة عند القراءة، فقد لا يكون عدد البتات مضاعفًا لـ 8، كما أن إزاحة البت المطلوبة غير معروفة أيضًا. في التنفيذ الأول للخوارزمية، لم أكن أعلم بوجود بايت المزامنة، وبالتالي قمت ببساطة بحفظ 8 ملفات بأعداد مختلفة من بتات الإزاحة. واحد منهم يحتوي على البيانات الصحيحة. في الخوارزمية النهائية، أقوم ببساطة بإزالة جميع البتات حتى A5h، مما يسمح لي بالحصول على ملف الإخراج الصحيح على الفور

الخوارزمية في روبي للمهتمين
لقد اخترت لغة روبي كلغة لكتابة البرنامج، لأن... أنا أبرمج عليه في أغلب الأحيان. الخيار ليس عالي الأداء، لكن مهمة جعل سرعة القراءة في أسرع وقت ممكن لا تستحق العناء.

# Используем gem 'wavefile'
require 'wavefile'

reader = WaveFile::Reader.new('input.wav')
samples = []
format = WaveFile::Format.new(:mono, :pcm_8, 44100)

# Читаем WAV файл, конвертируем в формат Mono, 8 bit 
# Массив samples будет состоять из байт со значениями 0-255
reader.each_buffer(10000) do |buffer|
  samples += buffer.convert(format).samples
end

# Позиция первого импульса (вместо 0)
prev_pos = 0
# Расстояние между импульсами
distance = 48
# Значение расстояния для окрестности поиска локального максимума
delta = (distance / 6).floor
# Биты будем сохранять в виде строки из "0" и "1"
bits = ""

loop do
  # Рассчитываем позицию следующего импульса
  pos = prev_pos + distance
  
  # Выходим из цикла если данные закончились 
  break if pos + delta >= samples.size

  # Корректируем позицию pos обнаружением максимума на отрезке [pos - delta;pos + delta]
  (pos - delta..pos + delta).each { |p| pos = p if samples[p] > samples[pos] }

  # Находим середину отрезка [prev_pos;pos]
  middle_pos = ((prev_pos + pos) / 2).floor

  # Берем окрестность в середине 
  sample = samples[middle_pos - delta..middle_pos + delta]

  # Определяем бит как "1" если разница между максимальным и минимальным значением на отрезке превышает 10
  bit = sample.max - sample.min > 10
  bits += bit ? "1" : "0"
end

# Определяем синхро-байт и заменяем все предшествующие биты на 256 бит нулей (согласно спецификации формата) 
bits.gsub! /^[01]*?10100101/, ("0" * 256) + "10100101"

# Сохраняем выходной файл, упаковывая биты в байты
File.write "output.cas", [bits].pack("B*")

نتيجة

بعد تجربة العديد من الخوارزميات والثوابت، كنت محظوظًا بالحصول على شيء مثير للاهتمام للغاية:

كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

لذلك، إذا حكمنا من خلال سلاسل الأحرف، لدينا برنامج لرسم الرسوم البيانية. ومع ذلك، لا توجد كلمات رئيسية في نص البرنامج. يتم ترميز كافة الكلمات الرئيسية بالبايت (كل قيمة > 80 ساعة). نحتاج الآن إلى معرفة أي جهاز كمبيوتر من الثمانينيات يمكنه حفظ البرامج بهذا التنسيق.

في الواقع، إنه مشابه جدًا لبرنامج BASIC. يقوم كمبيوتر ZX Spectrum بتخزين البرامج بنفس التنسيق تقريبًا في الذاكرة ويحفظ البرامج على الشريط. فقط في حالة، قمت بمراجعة الكلمات الرئيسية مقابلها جدول. ومع ذلك، كانت النتيجة سلبية بشكل واضح.

لقد قمت أيضًا بفحص الكلمات الرئيسية الأساسية لأجهزة Atari و Commodore 64 الشهيرة والعديد من أجهزة الكمبيوتر الأخرى في ذلك الوقت، والتي تمكنت من العثور على وثائق لها، ولكن دون جدوى - تبين أن معرفتي بأنواع أجهزة الكمبيوتر القديمة ليست واسعة جدًا.

ثم قررت أن أذهب القائمةثم وقعت نظري على اسم الشركة المصنعة Radio Shack وجهاز الكمبيوتر TRS-80. هذه هي الأسماء التي كانت مكتوبة على ملصقات الأشرطة التي كانت ملقاة على طاولتي! لم أكن أعرف هذه الأسماء من قبل ولم أكن على دراية بكمبيوتر TRS-80، لذلك بدا لي أن Radio Shack هي شركة مصنعة لأشرطة الكاسيت الصوتية مثل BASF أو Sony أو TDK، وكان TRS-80 هو وقت التشغيل. ولم لا؟

كمبيوتر تاندي/راديو شاك TRS-80

ومن المحتمل جدًا أن يكون التسجيل الصوتي المذكور، والذي ذكرته كمثال في بداية المقال، قد تم على جهاز كمبيوتر مثل هذا:

كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

اتضح أن هذا الكمبيوتر وأنواعه (الطراز I/الطراز III/الطراز IV، وما إلى ذلك) كانت تحظى بشعبية كبيرة في وقت ما (بالطبع، ليس في روسيا). يشار إلى أن المعالج الذي استخدموه كان أيضًا Z80. يمكنك العثور على هذا الكمبيوتر على الإنترنت معلومات كثيرة. في الثمانينات، تم توزيع معلومات الكمبيوتر في المجلات. في الوقت الحالي هناك عدة محاكيات أجهزة كمبيوتر لمنصات مختلفة.

لقد قمت بتنزيل المحاكي trs80gp ولأول مرة تمكنت من رؤية كيفية عمل هذا الكمبيوتر. بالطبع لم يكن الكمبيوتر يدعم إخراج الألوان، وكانت دقة الشاشة 128 × 48 بكسل فقط، ولكن كان هناك العديد من الإضافات والتعديلات التي من الممكن أن تزيد من دقة الشاشة. كان هناك أيضًا العديد من الخيارات لأنظمة التشغيل لهذا الكمبيوتر وخيارات لتنفيذ اللغة الأساسية (والتي، على عكس ZX Spectrum، في بعض الطرز لم يتم "وميضها" في ذاكرة القراءة فقط ويمكن تحميل أي خيار من قرص مرن، تمامًا مثل نظام التشغيل نفسه)

لقد وجدت أيضا جدوى لتحويل التسجيلات الصوتية إلى تنسيق CAS، وهو ما تدعمه المحاكيات، ولكن لسبب ما لم يكن من الممكن قراءة التسجيلات من أشرطة الكاسيت الخاصة بي باستخدامها.

بعد أن اكتشفت تنسيق ملف CAS (والذي تبين أنه مجرد نسخة تدريجية من البيانات من الشريط الذي كان لدي بالفعل، باستثناء الرأس مع وجود بايت متزامن)، قمت بإجراء بعض التغييرات على برنامجي وتمكنت من إخراج ملف CAS عامل يعمل في المحاكي (TRS-80 Model III):

كيف استعيدت البيانات بتنسيق غير معروف من الشريط المغناطيسي

لقد قمت بتصميم أحدث إصدار من أداة التحويل مع التحديد التلقائي للنبضة الأولى والمسافة بين النبضات المرجعية كحزمة GEM، كود المصدر متاح على جيثب.

اختتام

تبين أن المسار الذي سلكناه كان بمثابة رحلة رائعة إلى الماضي، وأنا سعيد لأنني وجدت الإجابة في النهاية. ومن بين أمور أخرى، أنا:

  • لقد اكتشفت تنسيق حفظ البيانات في ZX Spectrum ودرست إجراءات ROM المضمنة لحفظ/قراءة البيانات من أشرطة الصوت
  • تعرفت على جهاز الكمبيوتر TRS-80 وأصنافه، ودرست نظام التشغيل، ونظرت إلى نماذج من البرامج، وحتى أتيحت لي الفرصة لتصحيح الأخطاء في رموز الجهاز (بعد كل شيء، جميع أساليب تقوية Z80 مألوفة بالنسبة لي)
  • كتب أداة مساعدة كاملة لتحويل التسجيلات الصوتية إلى تنسيق CAS، والتي يمكنها قراءة البيانات التي لم تتعرف عليها الأداة المساعدة "الرسمية"

المصدر: www.habr.com

إضافة تعليق