Advertisement
Marrin

Dragon 32 tape reader

Aug 19th, 2013
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.83 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # coding: utf8
  3. import wave as wave_lib
  4. from array import array
  5. from functools import partial
  6.  
  7. READ_FRAMES_PER_BLOCK = 64 * 1024
  8. OSCILLATOR_RATE = 14318180
  9. SAM_CPU_SLOW_DIVISOR = 16
  10. BIT0_LENGTH = 813 * SAM_CPU_SLOW_DIVISOR
  11. BIT1_LENGTH = 435 * SAM_CPU_SLOW_DIVISOR
  12. AVERAGE_BIT_LENGTH = (BIT0_LENGTH + BIT1_LENGTH) / 2
  13.  
  14.  
  15. class TapeError(Exception):
  16.     pass
  17.  
  18.  
  19. def iter_samples(wave):
  20.     samplewidth = wave.getsampwidth()
  21.     try:
  22.         typecode = {1: 'b', 2: 'h', 4: 'i'}[samplewidth]
  23.     except KeyError:
  24.         raise ValueError('Unsupported samplewidth: {0}'.format(samplewidth))
  25.     for frames in iter(partial(wave.readframes, READ_FRAMES_PER_BLOCK), ''):
  26.         for value in array(typecode, frames):
  27.             yield value
  28.  
  29.  
  30.  
  31. class PushbackIterator(object):
  32.    
  33.     NOTHING = object()
  34.    
  35.     def __init__(self, iterable):
  36.         self.iterator = iter(iterable)
  37.         self.pushed_value = self.NOTHING
  38.  
  39.     def __iter__(self):
  40.         return self
  41.  
  42.     def next(self):
  43.         result = self.pushed_value
  44.         if result is self.NOTHING:
  45.             return next(self.iterator)
  46.         else:
  47.             self.pushed_value = self.NOTHING
  48.             return result
  49.  
  50.     def push_value(self, value):
  51.         self.pushed_value = value
  52.  
  53.  
  54. class Tape(object):
  55.     def __init__(self, filename):
  56.         self.wave = wave_lib.open(filename)
  57.         if self.wave.getnchannels() != 1:
  58.             raise TapeError(
  59.                 'unsupported number of channels: {0}'.format(
  60.                     self.wave.getnchannels()
  61.                 )
  62.             )
  63.         self.cycles_per_frame = OSCILLATOR_RATE / self.wave.getframerate()
  64.         self.samples = PushbackIterator(iter_samples(self.wave))
  65.  
  66.     def __enter__(self):
  67.         return self
  68.  
  69.     def __exit__(self, *_args):
  70.         self.close()
  71.  
  72.     def close(self):
  73.         self.wave.close()
  74.  
  75.     def pulse_in(self):
  76.         length = self.cycles_per_frame
  77.         sign = next(self.samples) < 0
  78.         for sample in self.samples:
  79.             if (sample < 0) != sign:
  80.                 self.samples.push_value(sample)
  81.                 break
  82.             length += self.cycles_per_frame
  83.             if length > (OSCILLATOR_RATE / 2):
  84.                 break
  85.         return sign, length
  86.  
  87.     def bit_in(self):
  88.         _, pulse1_width = self.pulse_in()
  89.         while True:
  90.             pulse0_width = pulse1_width
  91.             phase, pulse1_width = self.pulse_in()
  92.             cycle_width = pulse0_width + pulse1_width
  93.             if phase and (BIT1_LENGTH / 2) <= cycle_width <= (BIT0_LENGTH * 2):
  94.                 break
  95.         return int(cycle_width < AVERAGE_BIT_LENGTH)
  96.  
  97.     def byte_in(self):
  98.         result = 0
  99.         for _ in xrange(8):
  100.             result = (result >> 1) | (0x80 if self.bit_in() else 0)
  101.         return result
  102.  
  103.     def block_sync(self):
  104.         byte = 0
  105.         while True:
  106.             byte = (byte >> 1) | (0x80 if self.bit_in() else 0)
  107.             # print '{0:08b}'.format(byte)
  108.             if byte == 0x3c:
  109.                 break
  110.  
  111.     def block_in(self):
  112.         self.block_sync()
  113.         block = [self.byte_in(), self.byte_in()]
  114.         block.extend(self.byte_in() for _ in xrange(block[1]))
  115.         expected_sum = self.byte_in()
  116.         block_sum = sum(block) & 0xff
  117.         if expected_sum != block_sum:
  118.             print block
  119.             raise TapeError(
  120.                 'Wrong block checksum: expected {0}, got {1}'.format(
  121.                     expected_sum, block_sum
  122.                 )
  123.             )
  124.         block.append(expected_sum)
  125.         return block
  126.  
  127.  
  128. def main():
  129.     #filename = 'HelloWorld1 xroar.wav'
  130.     filename = 'HelloWorld1 origin.wav'
  131.     tape = Tape(filename)
  132.     print tape.block_in()
  133.     print tape.block_in()
  134.     print tape.block_in()
  135.  
  136.  
  137. if __name__ == '__main__':
  138.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement