Bir dizi göze çarpmayan olayın RIFF dosyalarının ikili kodlamasının ve bu veri kurtarma aracının derinliklerine doğru bir yolculuğa nasıl yol açtığı
Aceleniz varsa doğrudan GitHub deposuna gidin.
Son teknoloji şirketler için yazılım geliştirecek kadar şanslı olsam da, her zaman gururla taşıdığım bir rozet olan "matbaacı adam" oldum.
Ve belki de bu yüzden, çeyrek asırdan uzun süredir insanlar kurtarmak için depolama ortamlarıyla ortaya çıktılar. Bunu hiç profesyonel olarak yapmadım, sadece keyif aldığım bir şey ve çoğu zaman yardım edebiliyorum.
Benim temel yaklaşımım iki yönlüdür:
Ölmekte olan ortamdan yakalayabildiğinizi yakalayın
verileri yeniden yaratmayı deneyin
Bazen, sadece okuma toleransını ayarlayarak, Windows veya Mac'in reddettiği bir diskten her şeyi yakalayabilirsiniz, çünkü işletim sistemi, ölmekte olan ortamın yanıt verebilmesinden daha hızlı zaman aşımına uğrar. 7 ay boyunca bir kutuya bağlı bir diskim vardı; %100 kurtarma başarısı!
Bazen, veri parçalarınız eksik olabilir, ancak Dosya Ayırma Tablosu/Ana Dosya Tablosu/Konteyner süperblok/kök B-ağacından biri hala oradadır, bu nedenle çoğu veri hem dosya adlarıyla hem de ağaç konumlarıyla kurtarılabilir.
En uç noktada, ham verilerden başka hiçbir şeyiniz kalmaz. Yapabileceğiniz tek şey onu çıkarmaktır - esasen ortamdan her baytı okumak, JPG ( FF D8
) veya MKV ( 1A 45 DF A3
) gibi bilinen başlıkları belirlemek ve dosyanın sonuna kadar tüm ardışık verileri yakalamaya devam etmek. Herhangi bir nedenle dosya parçalanırsa, çıkarma işlemi açıkça başarısız olacaktır.
Frankie, bu daha önce hiç olmadı, genelde temkinliyimdir... Ne düşündüğümü bilmiyorum - yanlışlıkla bir oturum boyunca ses içeren bir SD kartı biçimlendirdim. Daha da kötüsü, üzerine bazı dosyalar kaydettim!
Pierre inanılmaz yetenekli bir komedyen ve sıra dışı bir aktör. Çalışmaları çok yönlü olsa da, bazıları kesinlikle evrensel olan sokak çizimleriyle yaygın olarak tanındı. Sadece aşağıda "Affedersiniz" dediği yere bakın.
Bu skeçteki sadelik ve komik çekicilik, neşeli ama aynı zamanda evrensel olarak çekici bir sanat eseri yaratıyor.
Bu basit hareketle Pierre kulübe katılmıştı. Herkes hata yapar. Pixar bile . Endişelenmeyin, dedim, kartı alırken, üzerine yazılan içerikler gitti, ancak mikrofonla biçimlendirilmiş bir kart olduğu için, FAT tabloları olmadan bile, kaydettiğiniz her şeyin çoğunu çıkarabilmeliyiz çünkü veriler muhtemelen sıralı olacaktır.
Bilmiyordum ki, bu bir süredir üzerinde çalıştığım en ilginç oyuncak projelerinden biri olacak. En son bu kadar eğlendiğimde, ' Os Azeitonas'ın bir albümünün master'larını içeren bir donanım RAID-0'ı yeniden inşa ediyordum.
Beklendiği gibi, verileri geri almanın tek yolu onu görüntü dökümünden çıkarmaktı. Seçilebilecek çok sayıda araç var, Photorec (açık kaynak), Recuva (paket yazılıma dikkat edin), ReclaiMe (ücretli), vb... ancak ben R-Studio'yu (ücretli) tercih ediyorum; sonuçları sürekli olarak rakiplerinden daha iyi.
Bu durumda, yine de, işler o kadar basit olmayacaktı. Denenen her yazılım wav
dosyalarını çıkarabildi, ancak verilerde bir sorun vardı çünkü hepsinde bu tekrar, bir tür yankı vardı.
Biraz duymam köreldi, bu yüzden ne olduğunu kontrol etmek için Audacity'de açtım. Burada bir örüntüyü açıkça görebilirsiniz:
Parçalar oldukça benzer bir dalga biçimine sahip olsa da - herhangi bir ikili korelasyon yok. Ayrıca, belirsiz bir şey daha vardı, her wav
dosyasında 2 ardışık başlık varmış gibi görünüyordu.
Dikkat edin, bu noktada, wav
dosyaları hakkındaki bilgim başlığın 52 49 46 46
olduğu yönündeydi. Bir mikrofon kullanmanın dışında, Pierre'e verileri nasıl kaydettiğini sormadım. Ancak, başlıkta "ZOOM M3" etiketini gördüğümde, sesle ilgili her şeyin yetkilisini aradım.
Ed, bu ömrün büyük bir bölümünde hızlı aramadaydı. Ben bu konuda şanslıyım. İnanılmaz bir besteci olmasının ötesinde - sadece nefes kesici Best Youth'u dinleyin - aynı zamanda kusursuz, yaşayan ve nefes alan bir ses ansiklopedisi.
Yakınlaştırma? Evet, evet. Bir tane var. Hem wav hem de raw kaydediyorlar. Veriler bozuldu mu? Ah. Elbette. Kurtarmak mı? Dosyalar büküldü mü? Bu imkansız bir görev olacak ve öyle olmasa bile, yeniden kaydetmek daha kolay olacak.
Ve işte oradaydım. Tekrar kaydetmek kesinlikle daha kolay olurdu, hatta Pierre bir noktada seslendirme yapmayı önerdi, ama bunun neresi eğlenceli olurdu ki?
Ed açıklayana kadar raw
dalga kavramını bile bilmiyordum, ama şimdi mikrofonun aynı anda iki dosyayı kaydettiğini öğrendiğimde her şey yerine oturdu.
Dijital kameraların her iki formatı da depolaması yaygındır, ancak bir mikrofon farklı bir canavardır. Kullanıcının ne kadar süre kayıt yapacağını önceden belirlemenin bir yolu yoktur, bu tek bir akış olsaydı sorun olmazdı. Her iki parçayı da depoladığı için, çok daha fazla oynatma söz konusudur.
Görüyorsunuz, kayıt tuşuna bastığınız anda mikrofon iki dosya oluşturuyor ve yakalanan verileri sürekli olarak her ikisinden de karta aktarıyor. Bu, veri parçaları halinde yapılıyor. Biri RAW için, diğeri WAV için, tekrar.
Bu veri dilimlerini çözmek için onları izole etmemiz gerektiğinden, tam boyutlarını bilmeliyiz . Ve işte sihirli sayımız !
İlk düşüncem, parçaların exFAT
tahsis birimi boyutuyla hizalanmış olabileceğiydi. Bu durumda, 128 KBytes
. Hadi test edelim.
Başlık, bunun bir stereo dosya (2 kanal) olduğunu, kanal başına 32 bit olarak kaydedildiğini ve saniyede 48k kez örneklendiğini açıkça belirtir. Yukarıdaki görüntüden hatırlayacağınız üzere, parçalar yaklaşık 0,7 saniyede tekrar eder.
Kabaca bir tahminde bulunabilmek için, parça baytları hakkında bir tahminde bulunalım.
1 second of data = 2 channels * 32 bits * 48000 samples 1 second of data = 384000 bytes 0.7 seconds ~ 268800 bytes
Yaklaşık 268 KB'lık parçalara bakıyoruz.
Ve böylece, verilerin 128 KB'lık exFAT AUS'a bölünebileceği fikri anında çürütülüyor.
Bir sonraki bariz adım 2 tabanında yukarıya doğru ilerlemek olacaktır. 4096'nın tamponlar için iyi bir denge olduğu göz önüne alındığında, oradan değerlendirelim:
4096 * 32 = 131072 (falls short by about 1/2) 4096 * 64 = 262144 (is in the ballpark of what we're expecting) 262144/384000 ~ 0.682 seconds of data
0,682 saniye bizim 0,7 saniyelik tahminimizle o kadar uyumluydu ki aradığımız sabit değerin 262144 olduğunu hemen anladım.
Kavramsal olarak sorun çözüldü. Şimdi geriye sadece aracı inşa etmek kalmıştı. Bunun için şunlar gerekliydi:
Ve eminim orada kendinizi daha rahat hissedeceksiniz.
Ancak Google indekslemesi uğruna, hem RIFF hem de BEXT başlıklarını oluşturan yöntemleri burada bırakıyorum; ancak bunları bulamadım ve bu da ne yazık ki sürecin kabul etmek istediğimden daha uzun sürmesine neden oldu.
public class RiffFile { /** * Creates a RIFF header with BEXT and fmt chunks * * @param sampleRate the sample rate of the audio (8000Hz, 44100Hz, 48000Hz, etc) times per second the audio is sampled * @param bitsPerSample the bits per sample (8bits, 16bits, 32bits, etc) * @param channels the number of channels (1 mono, 2 stereo, etc) * @param audioDataSize the size of the audio data in bytes * @return the RIFF header * @throws IOException if an I/O error occurs */ public static byte[] createRiffHeader(int sampleRate, short bitsPerSample, short channels, int audioDataSize) throws IOException { // calculate the byte rate, block align and file size int byteRate = sampleRate * channels * bitsPerSample / 8; short blockAlign = (short) (bitsPerSample * channels / 8); // stream that will carry the new RIFF file ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(byteArrayOutputStream); // riff header out.writeBytes("RIFF"); out.writeInt(Integer.reverseBytes(0)); out.writeBytes("WAVE"); // 9-12 Format always WAVE // bext chunk writeBextChunk(out); // fmt chunk out.writeBytes("fmt "); // 13-16 chunkID is "fmt " with trailing whitespace out.writeInt(Integer.reverseBytes(16)); // 17-20 size of this chunk, is 16 byts out.writeShort(Short.reverseBytes((short) 3)); // 21-22 (2 bytes) audioFormat (1 PCM integer, 3 IEEE 754 float) out.writeShort(Short.reverseBytes(channels)); // 23-24 (2 bytes) numChannels (1 mono, 2 stereo, 4, etc) out.writeInt(Integer.reverseBytes(sampleRate)); // 25-28 (4 bytes) sampleRate (8000, 44100, 48000, etc) out.writeInt(Integer.reverseBytes(byteRate)); // 29-32 (4 bytes) byteRate (sampleRate * numChannels * bitsPerSample/8) out.writeShort(Short.reverseBytes(blockAlign)); // 33-34 (2 bytes) blockAlign (numChannels * bitsPerSample/8) out.writeShort(Short.reverseBytes(bitsPerSample)); // 35-36 (2 bytes) bitsPerSample (8bits, 16bits, 32bits, etc) // data chunk out.writeBytes("data"); // 37-40 chunkID ID is "data" out.writeInt(Integer.reverseBytes(audioDataSize)); // 41-44 size of this chunk varies out.close(); // write the full size of the file on the 4-8 bytes byte[] outArr = byteArrayOutputStream.toByteArray(); int size = outArr.length - 8; ByteBuffer.wrap(outArr, 4, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(size); return outArr; } private static void writeBextChunk(DataOutputStream out) throws IOException { // bext chunk out.writeBytes("bext"); out.writeInt(Integer.reverseBytes(256 + 32 + 32 + 10 + 8 + 8 + 8 + 2 + 180 + 4 + 4 + 4 + 4 + 4 + 180)); // bext chunk size (fixed size for BWF) // description 256 bytes writeToArray(out, 256, ""); // 256 bytes description writeToArray(out, 32, "ZOOM M3"); // 32 bytes originator writeToArray(out, 32, ""); // 32 bytes originator reference writeToArray(out, 10, "2023-10-01"); // 10 bytes origination date writeToArray(out, 8, "12:00:00"); // 8 bytes origination time writeToArray(out, 8, "12:00:00"); // 8 bytes time reference out.writeLong(Long.reverseBytes(0L)); // 8 bytes time reference out.writeShort(Short.reverseBytes((short) 0)); // 2 bytes version out.write(new byte[180]); // 180 bytes UMID out.writeFloat(0.0f); // 4 bytes loudness value out.writeFloat(0.0f); // 4 bytes loudness range out.writeFloat(0.0f); // 4 bytes max true peak level out.writeFloat(0.0f); // 4 bytes max momentary loudness out.writeFloat(0.0f); // 4 bytes max short term loudness // zoom m3 needs this bit to allow file to be read from "zoom m3 edit & play" writeToArray(out, 180, "A=PCM,F=48000,W=32,M=stereo,T=M3;VERSION=1.00;MSRAW=ON ;"); } }
Gördüğünüz gibi, BEXT parçasına çok fazla emek harcanmadı; ben bunu sadece "Zoom M3 Edit & Play" ile uyumlu olmasını sağlamak için oluşturdum.
Umarım ilgi çekici bir okuma olmuştur. Bunu ilgi çekici tutarken düşünce sürecinin perdesini kaldırmaya çalıştım. Gerçek kod umarım kendini açıklar ve burada bulabilirsiniz:
https://github.com/wasteofserver/zoom_m3_mic_wav_data_recover/
Zorluk yalnızca kaybolan kayıtları kurtarmak değildi; geleneksel araçların neden başarısız olduğunu anlamak ve işe yarayan bir yöntem geliştirmekti.
Yeniden kaydetmek daha kolay olabilirdi ancak bulmacayı çözmenin heyecanı çabaya değdi. Sonunda, Zoom M3 MicTrak kayıtlarını başarıyla geri yükleyen özel yapım bir çözüm elde ettik.
Eğer kendinizi benzer bir durumda bulursanız, umarım bu döküm size yardımcı olur. Ve eğer bulamazsanız, en azından veri kurtarma dünyasında küçük bir maceranın tadını çıkarmış olursunuz.
Bu hikaye ilk olarak https://wasteofserver.com/zoom-m3-mictrak-file-recovery/ adresinde yayınlandı. En son güncellemeler ve yorumlar için oradan kontrol etmek isteyebilirsiniz.