Como recuperei dados em um formato desconhecido de uma fita magnética

fundo



Como amante de ferro retrô, uma vez comprei um ZX Spectrum + de um vendedor do Reino Unido. Completo com o próprio computador, recebi várias fitas cassetes com jogos (na embalagem original com instruções), além de programas gravados em fitas sem designações especiais. Surpreendentemente, os dados dos cassetes de 40 anos eram legíveis e eu pude baixar quase todos os jogos e programas deles.







No entanto, em algumas fitas encontrei gravações que claramente não foram feitas pelo computador ZX Spectrum. Eles pareciam completamente diferentes e, diferentemente das gravações do computador mencionado acima, não iniciavam com um pequeno carregador de inicialização BASIC, que geralmente está presente nas gravações de todos os programas e jogos.



Por algum tempo, fui assombrado por isso - eu realmente queria saber o que está escondido neles. Se você pudesse ler o sinal de áudio como uma sequência de bytes, poderia procurar neles caracteres ou algo que indique a origem do sinal. Uma espécie de arqueologia retrô.



Agora que cheguei até o fim e olhei para os rótulos das fitas, sorrio porque

a resposta estava bem na minha frente todo esse tempo
— TRS-80, : «Manufactured by Radio Shack in USA»


(Se você quiser manter a intriga até o fim, não entre no spoiler)



Comparação de sinais de áudio



O primeiro passo é digitalizar as gravações de áudio. Você pode ouvir como isso soa:





E, como sempre, a gravação do computador ZX Spectrum soa:





Nos dois casos, no início da gravação, existe o chamado tom piloto - um som de uma frequência (na primeira gravação, é muito curto <1 segundo, mas distinguível). O tom do piloto sinaliza para o computador se preparar para receber dados. Como regra, cada computador reconhece apenas "seu" tom piloto pela forma de onda e sua frequência.



Devo dizer sobre a forma do sinal em si. Por exemplo, no ZX Spectrum, seu formato é retangular:







quando um tom piloto é detectado, o ZX Spectrum exibe faixas vermelhas e azuis alternadas na borda da tela, indicando que o sinal é reconhecido. O tom piloto termina com um pulso sincronizado, que indica ao computador para começar a receber dados. É caracterizada por uma duração mais curta (comparada ao tom piloto e aos dados subsequentes) (consulte a figura).



Após o recebimento do pulso de sincronização, o computador registra cada aumento / queda do sinal, medindo sua duração. Se a duração for menor que um determinado limite, o bit 1 é gravado na memória, caso contrário, 0. Os bits são coletados em bytes e o processo é repetido até que N bytes sejam recebidos. O número N geralmente é obtido no cabeçalho do arquivo baixado. A sequência de inicialização é a seguinte:



  1. tom piloto
  2. cabeçalho (comprimento fixo), contém o tamanho dos dados carregados (N), nome e tipo de arquivo
  3. tom piloto
  4. os dados em si


Para garantir que os dados sejam carregados corretamente, o ZX Spectrum lê o último byte da chamada paridade de bytes (paridade de bytes), calculada quando você salva a operação de arquivo XOR em todos os bytes dos dados gravados. Ao ler o arquivo, o computador calcula o byte de paridade dos dados recebidos e, se o resultado for diferente do salvo, exibe a mensagem de erro "R Erro no carregamento da fita". Estritamente falando, o computador pode emitir essa mensagem mais cedo se, ao ler, não reconhecer o impulso (está faltando ou sua duração não corresponde a certos limites)



. Agora, vamos ver como é o sinal desconhecido:







Este é um tom piloto. A forma de onda é significativamente diferente, mas você pode ver que o sinal consiste em pulsos curtos e repetitivos de uma determinada frequência. A uma taxa de amostragem de 44100 Hz, a distância entre os "picos" é de aproximadamente 48 amostras (o que corresponde a uma frequência de ~ 918 Hz). Vamos lembrar desta figura.



Agora, vejamos o fragmento com os dados:







se medirmos a distância entre pulsos individuais, verifica-se que a distância entre pulsos "longos" ainda é de ~ 48 amostras e entre curtos - ~ 24 amostras. Seguindo um pouco à frente, direi que, no final, descobriu-se que pulsos de "referência" com uma frequência de 918 Hz seguem continuamente, do início ao fim do arquivo. Pode-se supor que durante a transmissão de dados, se um pulso adicional ocorrer entre os pulsos de referência, o consideraremos como bit 1, caso contrário, 0.



O que há com o pulso sincronizado? Vejamos o início dos dados:







o tom do piloto termina e os dados começam imediatamente. Um pouco mais tarde, depois de analisar várias gravações de áudio diferentes, descobrimos que o primeiro byte de dados é sempre o mesmo (10100101b, A5h). O computador pode começar a ler dados depois de recebê-los.



Você também pode prestar atenção ao deslocamento do primeiro pulso de referência imediatamente após o último 1 no sincronizador. Foi descoberto muito mais tarde no processo de desenvolvimento de um programa para reconhecimento de dados, quando os dados no início do arquivo não podiam ser lidos de forma estável.



Agora vamos tentar descrever um algoritmo que processará um arquivo de áudio e carregará dados.



Carregando dados



Primeiro, vejamos algumas suposições para não complicar o algoritmo:



  1. Consideraremos os arquivos apenas no formato WAV;
  2. O arquivo de áudio deve começar com um tom piloto e não deve conter silêncio no início
  3. O arquivo de origem deve ter uma taxa de amostragem de 44100 Hz. Nesse caso, a distância entre os pulsos de referência de 48 amostras já foi determinada e não precisamos calculá-lo programaticamente;
  4. O formato da amostra pode ser qualquer (8/16 bits / ponto flutuante) - pois ao ler, podemos convertê-lo para o desejado;
  5. Assumimos que o arquivo original seja normalizado em amplitude, o que deve estabilizar o resultado;


O algoritmo de leitura será o seguinte:



  1. Lemos o arquivo na memória e, ao mesmo tempo, convertemos o formato de amostra em 8 bits;
  2. Determine a posição do primeiro pulso nos dados de áudio. Para fazer isso, você precisa calcular o número da amostra com a amplitude máxima. Para simplificar, vamos contar manualmente uma vez. Vamos salvá-lo na variável prev_pos;
  3. Adicione 48 à posição do último impulso (pos: = prev_pos + 48)
  4. 48 , ( , ), pos. (pos-8;pos+8) . , , pos. 8 = 48/6 — , , . , 48, , ;
  5. , . , , . , , . , . 2 : , . ;
  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,


Ruby,
Ruby, .. . , .



#  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*")






Tendo tentado várias variantes do algoritmo e constantes, tive a sorte de obter algo extremamente interessante:







Portanto, a julgar pelas cadeias de caracteres, temos um programa para plotar gráficos. No entanto, não há palavras-chave no texto do programa. Todas as palavras-chave são codificadas como bytes (cada valor> 80h). Agora precisamos descobrir qual computador dos anos 80 poderia salvar programas nesse formato.



Na verdade, isso é muito semelhante a um programa BASIC. Aproximadamente no mesmo formato, o computador ZX Spectrum armazena na memória e salva os programas em fita. Por precaução, verifiquei as palavras-chave na mesa . No entanto, o resultado foi obviamente negativo.



Também verifiquei as palavras-chave BASIC dos computadores Atari populares, o Commodore 64 e vários outros, para os quais consegui encontrar documentação, mas sem sucesso - meu conhecimento dos tipos de computadores retrô não era tão amplo.



Decidi examinar a lista e, em seguida, meus olhos se voltaram para o nome do fabricante da Radio Shack e do computador TRS-80. Esses nomes foram escritos nos rótulos das fitas que estavam na minha mesa! Afinal, eu não conhecia esses nomes antes e não estava familiarizado com o computador TRS-80, então pareceu-me que a Radio Shack era um fabricante de cassetes de áudio, como BASF, Sony ou TDK, e TRS-80 era a duração da reprodução. Por que não?



Computador Tandy / Radio Shack TRS-80



É muito provável que a gravação de áudio em questão, que citei como exemplo no início do artigo, tenha sido feita em um computador:







Descobriu-se que esse computador e suas variantes (Modelo I / Modelo III / Modelo IV, etc.) eram muito populares em seus computadores. tempo (é claro, não na Rússia). Vale ressaltar que o processador usado neles também é Z80. Muitas informações podem ser encontradas neste computador na Internet . Na década de 1980, informações sobre o computador foram divulgadas em revistas . No momento, existem vários emuladores de computador para diferentes plataformas.



Eu baixei o emulador trs80gpe pela primeira vez pude ver como esse computador funcionava. Obviamente, o computador não suportava saída colorida, a resolução da tela era de apenas 128x48 pixels, mas havia muitas extensões e modificações que podiam aumentar a resolução da tela. Havia também muitas opções de sistemas operacionais para este computador e opções de implementação da linguagem BASIC (que, diferentemente do ZX Spectrum, em alguns modelos nem sequer eram "flashadas" para a ROM e qualquer opção podia inicializar a partir de um disquete, bem como do próprio sistema operacional)



. Encontrei um utilitário para converter gravações de áudio no formato CAS, suportado por emuladores, mas, por algum motivo, não consegui ler as gravações dos meus cassetes com a ajuda deles.



Depois de descobrir o formato do arquivo CAS (que acabou sendo apenas uma cópia bit a bit dos dados da fita, que eu já tinha em minhas mãos, com exceção do cabeçalho com a presença de um byte de sincronização), fiz várias alterações no meu programa e consegui obter um arquivo CAS ativo na saída, o que funcionou no emulador (TRS-80 Modelo III):







A última versão do utilitário para conversão com detecção automática do primeiro pulso e a distância entre os pulsos de referência que eu projetei como um pacote GEM, o código fonte está disponível no Github .



Conclusão



O caminho percorrido acabou por ser uma emocionante jornada para o passado, e estou feliz que, no final, encontrei uma solução. Entre outras coisas, eu:



  • Eu descobri o formato para salvar dados no ZX Spectrum e estudei as rotinas ROM incorporadas para salvar / ler dados de fitas de áudio
  • Eu me familiarizei com o computador TRS-80 e suas variedades, estudei o sistema operacional, observei exemplos de programas e até tive a oportunidade de depurar códigos de máquina (afinal, todos os mnemônicos Z80 me são familiares)
  • Eu escrevi um utilitário completo para converter gravações de áudio para o formato CAS, que pode ler dados que não são reconhecidos pelo utilitário "oficial"



All Articles