Discussion:
[d2t] Data to Tones
Add Reply
Onion Courier
2024-12-27 21:45:42 UTC
Reply
Permalink
https://jmp.sh/ELTus4hj
(download and decode with Python3 code below)

import argparse
import math
import numpy as np
import struct
import sys
from scipy.fftpack import fft

SAMPLE_RATE = 44100
DURATION = 0.2
FFT_SIZE = 8820
AMPLITUDE_8BIT = 127
AMPLITUDE_16BIT = 32760
BASE_FREQ = 440.0
FREQ_STEP = 25.0 # Larger step size since we only need 16 values

def generate_tone_buffer(freq, use_16bit):
num_samples = int(SAMPLE_RATE * DURATION)
amplitude = AMPLITUDE_16BIT if use_16bit else AMPLITUDE_8BIT
bytes_per_sample = 2 if use_16bit else 1
buf = bytearray(num_samples * bytes_per_sample)

for i in range(num_samples):
t = i / SAMPLE_RATE
window = 0.5 * (1 - math.cos(2 * math.pi * i / (num_samples - 1)))
sample = int(amplitude * math.sin(2 * math.pi * freq * t) * window)

if use_16bit:
struct.pack_into('>h', buf, i * 2, sample)
else:
buf[i] = sample + AMPLITUDE_8BIT

return buf

def write_au_header(use_16bit):
encoding = 0x03 if use_16bit else 0x02
header = bytearray([
0x2e, 0x73, 0x6e, 0x64,
0x00, 0x00, 0x00, 0x20,
0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, encoding,
0x00, 0x00, 0xac, 0x44,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
])
sys.stdout.buffer.write(header)

def encode_tones(data, use_16bit, tone_buffers):
write_au_header(use_16bit)
hex_str = data.hex()

for c in hex_str:
index = int(c, 16)
sys.stdout.buffer.write(tone_buffers[index])

def detect_frequency(samples):
windowed_samples = samples * np.hanning(len(samples))
spectrum = fft(windowed_samples)
magnitude = np.abs(spectrum[:len(spectrum) // 2])
peak_index = np.argmax(magnitude)
freq = peak_index * SAMPLE_RATE / FFT_SIZE

if peak_index > 0 and peak_index < FFT_SIZE // 2 - 1:
alpha = magnitude[peak_index - 1]
beta = magnitude[peak_index]
gamma = magnitude[peak_index + 1]
correction = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma)
freq += correction * SAMPLE_RATE / FFT_SIZE

return freq

def freq_to_hex(freq):
index = round((freq - BASE_FREQ) / FREQ_STEP)
if 0 <= index < 16:
return format(index, 'x')
return None

def decode_tones(input_data, use_16bit):
bytes_per_sample = 2 if use_16bit else 1
input_data = input_data[24:]
num_samples = len(input_data) // bytes_per_sample

if use_16bit:
samples = np.frombuffer(input_data, dtype='>i2').astype(np.float64) / AMPLITUDE_16BIT
else:
samples = (np.frombuffer(input_data, dtype=np.uint8).astype(np.float64) - AMPLITUDE_8BIT) / AMPLITUDE_8BIT

hex_output = []
for i in range(0, num_samples, FFT_SIZE):
if i + FFT_SIZE > num_samples:
break
window = samples[i:i + FFT_SIZE]
freq = detect_frequency(window)
digit = freq_to_hex(freq)
if digit is not None:
hex_output.append(digit)

decoded_data = bytes.fromhex(''.join(hex_output))
sys.stdout.buffer.write(decoded_data)

def main():
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--decode', action='store_true', help='Decode mode')
parser.add_argument('-16', '--use16bit', action='store_true', help='Use 16-bit audio (default: 8-bit)')
args = parser.parse_args()

tone_buffers = [
generate_tone_buffer(BASE_FREQ + i * FREQ_STEP, args.use16bit)
for i in range(16)
]

input_data = sys.stdin.buffer.read()

if args.decode:
decode_tones(input_data, args.use16bit)
else:
encode_tones(input_data, args.use16bit, tone_buffers)

if __name__ == '__main__':
main()
Chris M. Thomasson
2024-12-27 22:16:50 UTC
Reply
Permalink
Post by Onion Courier
https://jmp.sh/ELTus4hj
(download and decode with Python3 code below)
[snip code]

Interesting to me. Well, fwiw, here is one of my tries. Cantor Pairing
notes via MIDI:



A drum kit:



;^)
Onion Courier
2024-12-27 22:25:26 UTC
Reply
Permalink
Post by Chris M. Thomasson
Post by Onion Courier
https://jmp.sh/ELTus4hj
(download and decode with Python3 code below)
[snip code]
Interesting to me. Well, fwiw, here is one of my tries. Cantor Pairing
http://youtu.be/XkwgJt5bxKI
http://youtu.be/712wWf7Q9sE
Really nice!
--
Regards
Stefan
Chris M. Thomasson
2024-12-31 21:47:50 UTC
Reply
Permalink
Post by Onion Courier
Post by Chris M. Thomasson
Post by Onion Courier
https://jmp.sh/ELTus4hj
(download and decode with Python3 code below)
[snip code]
Interesting to me. Well, fwiw, here is one of my tries. Cantor Pairing
http://youtu.be/XkwgJt5bxKI
http://youtu.be/712wWf7Q9sE
Really nice!
Thank you! :^)

Happy New Year!

Btw, I actually made it into the AMS webpage. A screenshot:

Loading Image...

I am humbled.
Stefan Claas
2024-12-31 21:56:39 UTC
Reply
Permalink
Post by Chris M. Thomasson
Post by Onion Courier
Post by Chris M. Thomasson
Post by Onion Courier
https://jmp.sh/ELTus4hj
(download and decode with Python3 code below)
[snip code]
Interesting to me. Well, fwiw, here is one of my tries. Cantor Pairing
http://youtu.be/XkwgJt5bxKI
http://youtu.be/712wWf7Q9sE
Really nice!
Thank you! :^)
Happy New Year!
https://i.ibb.co/64dSF1d/image.png
I am humbled.
Cool! Happy News Year!
--
Regards
Stefan
Loading...