Skip to content

Instantly share code, notes, and snippets.

@jeremyblow
Created July 17, 2018 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremyblow/8c900d1f68aa83ec10e40e0eeba2ed71 to your computer and use it in GitHub Desktop.
Save jeremyblow/8c900d1f68aa83ec10e40e0eeba2ed71 to your computer and use it in GitHub Desktop.
Fun things for Dabeaz's superbad superboard
"""Fun things for Dabeaz's superbad superboard.
Default Audio Format:
Frame rate: 48kHz
Channels: 1
Bytes per sample: 1
Superboard Encoding:
Baud rate: 300
Start bit: 0b0
Stop bits: 0b11
0: 4 square wave cycles at 1200 Hz
40 samples (1 cycle) @ 48k Hz
160 samples (4 cycles) @ 48 kHz (bit)
1760 samples (44 cycles) @ 48 kHz (byte payload)
1: 8 square wave cycles at 2400 Hz
20 samples (1 cycle) @ 48 kHz
160 samples (8 cycles) @ 48 kHz (bit)
1760 samples (88 cycles) @ 48 kHz (byte payload)
Thoughts:
* Why not use a slower sample rate (i.e. 2400 Hz)?
"""
import wave
def encode_bit(value, frame_rate=48000):
cycles, frequency = ((4, 1200), (8, 2400))[value]
data = bytearray()
n_samples = frame_rate // frequency
for i in range(n_samples // 2):
data.append(0)
for i in range(n_samples // 2):
data.append(255)
return cycles * data
def encode_byte(byte):
data = bytearray(encode_bit(0)) # Start bit
for bit in range(0, 8):
if byte & 0x1:
data.extend(encode_bit(1))
else:
data.extend(encode_bit(0))
byte = byte >> 1
data.extend(encode_bit(1) * 2) # Stop bits
return data
def encode_data(in_data):
data = bytearray(encode_bit(1) * 1000) # Padding
for byte in in_data:
data.extend(encode_byte(byte))
data.extend(encode_bit(1) * 1000) # Padding
return data
def decode_samples(samples, frame_rate=48000):
ref_samples = [encode_bit(n, frame_rate=frame_rate) for n in (0, 1)]
bit_len = len(ref_samples[0])
# Convert samples into bits
bits = []
for idx in range(0, len(samples), bit_len):
bit = ref_samples.index(samples[idx:idx + bit_len])
bits.append(bit)
# Starting at first start bit, extract bytes from 11-bit chunks, skip
# chunks with invalid start/stop bits
data = bytearray()
for idx in range(bits.index(0), len(bits), 11):
bit_set = bits[idx:idx+11]
if bit_set[0] != 0 or bit_set[-2:] != [1, 1]:
continue
value = 0
for bit in bit_set[-3:0:-1]:
value = (value << 1) | bit
data.append(value)
# data = data.replace(b'\n', b'\r\n')
return data
def ascii_to_wav(in_file, out_file, frame_rate=48000, sample_width=1, channels=1):
with open(in_file, "rb") as fh:
in_data = fh.read()
in_data = in_data.replace(b'\n', b'\r\n')
data = encode_data(in_data)
with wave.open(out_file, "wb") as w:
w.setnchannels(channels)
w.setsampwidth(sample_width)
w.setframerate(frame_rate)
w.writeframes(data)
return data
def wav_to_ascii(in_file, out_file):
with wave.open(in_file, "rb") as w:
samples = w.readframes(w.getnframes())
data = decode_samples(samples, w.getframerate())
with open(out_file, "wb") as fh:
fh.write(data)
return data
assert decode_samples(encode_data(b'A')) == b'A'
assert decode_samples(encode_data(b'A')) == b'A'
ascii_to_wav("haiku_1_in.bas", "haiku_1_out.wav")
wav_to_ascii("haiku_1_out.wav", "haiku_1_out.bas")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment