Multitrack recording file corruption restore tip

Forums Forums Qu Forums Qu troubleshooting Multitrack recording file corruption restore tip

Viewing 4 posts - 1 through 4 (of 4 total)
  • Author
    Posts
  • #50008
    Profile photo of HawkHawk
    Participant

    We had our 3 hour long concert recorded as 18 multi track files into a SanDisk Extreme USB3. When I try to copy the files to the computer, track#2 refuse to copy, the finder is saying it cannot read this file. It must be corrupted, all the other tracks are fine. So I tried to use windows disk scan as suggested before to restore this file, but the result is it become a very small file (16k or something). Since the normal restore method does not work, as an all software engineer band, we start to work on a lower level.

    The disk format is FAT32, from this article (https://www.pjrc.com/tech/8051/ide/fat32.html) we learnt how it index the file into sectors and cluster. The cluster index must be messed up on track2, that’s why normal tools cannot recover the correct content. So we wrote the following C++ program to print out the cluster chain of track 1 which is OK to find out the sequence. The result shows that only the first two clusters are not in the right order for track2. We recovered it successfully! And the advice for everyone is to format the disk before multi-track recording every time.

    #include <iostream>
    #include <fstream>
    #include <cassert>
    #include <cstdint>
    #include <algorithm>
    
    using namespace std;
    
    class Fat32 {
    private:
      static const size_t header_size = 0x74fc * 512;
      ifstream fin;
      vector<char> buf;
      size_t BPB_BytsPerSec;
      size_t BPB_SecPerClus;
      size_t BPB_RsvdSecCnt;
      size_t BPB_NumFATs;
      size_t BPB_FATSz32;
      size_t bytes_per_cluster;
      uint32_t *fat;
    public:
      Fat32() {
        fin.open("/home/wcgbg/recovery/sdc1", ios::in | ios::binary);
        assert(fin);
        buf.resize(header_size);
        fin.read(&buf[0], header_size);
        assert(fin.gcount() == header_size);
        BPB_BytsPerSec = (uint16_t &) buf[0x0b];
        assert(BPB_BytsPerSec == 512);
        BPB_SecPerClus = (uint8_t &) buf[0x0d];
        bytes_per_cluster = BPB_BytsPerSec * BPB_SecPerClus;
        BPB_RsvdSecCnt = (uint16_t &) buf[0x0e];
        BPB_NumFATs = (uint8_t &) buf[0x10];
        assert(BPB_NumFATs == 2);
        BPB_FATSz32 = (uint32_t &) buf[0x24];
        uint16_t signature = (uint16_t &) buf[0x1fe];
        assert(signature == 0xaa55);
        assert(
            (BPB_RsvdSecCnt + (BPB_NumFATs * BPB_FATSz32)) * BPB_BytsPerSec
                == header_size);
        fat = (uint32_t *) &buf[BPB_RsvdSecCnt * BPB_BytsPerSec];
      }
      void read_file(const char *short_filename, uint32_t offset) {
        cout << short_filename << endl;
        fin.seekg(offset);
        char dir_buf[32];
        fin.read(dir_buf, 32);
        assert(fin.gcount() == 32);
        assert(equal(dir_buf, dir_buf + 11, short_filename));
        uint32_t first_cluster_high = (uint16_t &) dir_buf[0x14];
        uint32_t first_cluster_low = (uint16_t &) dir_buf[0x1a];
        uint32_t first_cluster = (first_cluster_high << 16) | first_cluster_low;
        uint32_t file_size = (uint32_t &) dir_buf[0x1c];
        uint32_t n_clusters = (file_size + bytes_per_cluster - 1)
            / bytes_per_cluster;
        cout << "file_size=" << file_size << endl;
        cout << "n_clusters=" << n_clusters << endl;
        ofstream fout("/tmp/TRK02.WAV", ios::out | ios::binary);
        vector<char> cluster_buf(bytes_per_cluster);
        for (uint32_t i = first_cluster, j = 0; j < n_clusters; i = fat[i], j++) {
          cout << j << '/' << n_clusters << '\t' << i << endl;
          assert(i != 0 && i != 0xffffffffU);
          if (j < 2) {
            // write first 2 clusters of TRK01.WAV
            fin.seekg(header_size + (i - 2) * bytes_per_cluster);
          } else {
            // TRK02.WAV is 2 clusters after TRK01.WAV
            fin.seekg(header_size + (i + 2 - 2) * bytes_per_cluster);
          }
          fin.read(&cluster_buf[0], bytes_per_cluster);
          assert(fin.gcount() == bytes_per_cluster);
          fout.write(&cluster_buf[0], bytes_per_cluster);
        }
        cout << endl;
      }
    };
    
    int main() {
      Fat32 fat32;
      fat32.read_file("TRK01   WAV", 0x14c9f840);
    //  fat32.read_file("TRK03   WAV", 0x14c9f880);
    //  fat32.read_file("TRK04   WAV", 0x14c9f8a0);
    //  fat32.read_file("TRK05   WAV", 0x14c9f8c0);
    }
    #50009
    Profile photo of Dick ReesDick Rees
    Participant

    the advice for everyone is to format the disk before multi-track recording every time.

    Congratulations on the recovery. Did you not know beforehand that you have to re-format recording media rather than just deleting files before starting a new project?

    #109990
    Profile photo of BadgerBadger
    Participant

    Can anyone shed light on how to use that code on a mac? I have the same situation and need to fix a file that was corrupted.

    IMO having to reformat the drive after every record pass is inconvenient when on tour.

    #109993
    Profile photo of GigaGiga
    Participant

    I have no idea what he’s talking about. However, I have never reformatted my USB-stick and made and deleted a lot of tracks over the years.

    Giga

Viewing 4 posts - 1 through 4 (of 4 total)
  • You must be logged in to reply to this topic.