8

using C or python (python preferred), How would i encode a binary file to audio that is then outputted though the headphone jack, also how would i decode the audio back to binary using input from the microphone jack, so far i have learned how to covert a text file to binary using python, It would be similar to RTTY communication.

This is so that i can record data onto a cassette tape.

import binascii

a = open('/Users/kyle/Desktop/untitled folder/unix commands.txt', 'r')
f = open('/Users/kyle/Desktop/file_test.txt', 'w')
c = a.read()
b = bin(int(binascii.hexlify(c), 16))
f.write(b)
f.close()
kyle k
  • 5,134
  • 10
  • 31
  • 45
  • 1
    First, what is "a text file containing binary". A "text file" is a file that contains text, instead of binary data; a binary file is a file that contains binary data, instead of text. – abarnert Jun 05 '13 at 01:51
  • Second, what kind of encoding do you want? Do you want to read each byte, convert it to a decimal integer from 0-255, and synthesize a voice speaking that number? Or use each pair of bytes as a 16-bit mono sample to be played at 44.1k? Or treat the bottom 7 bits of each byte as a MIDI note number to be played at 64 notes/sec? Or what? – abarnert Jun 05 '13 at 01:53
  • Thanks for the correction, that was confusing. – kyle k Jun 05 '13 at 01:54
  • I was wanting each bit to be a high or low sound signifying a 1 or a 0 – kyle k Jun 05 '13 at 01:55
  • [Converting Text into a KCS WAV File in Python](http://dabeaz.blogspot.ru/2010/08/using-python-to-encode-cassette.html) – jfs Jun 05 '13 at 04:22
  • On Python 3 you could use [`bin(int.from_bytes(data, 'big', signed=False))[2:].zfill(len(data)*8)` to convert bytes into ascii "01" (binary)-string](http://stackoverflow.com/a/12162190/4279) without hexlify. – jfs Jun 05 '13 at 04:28
  • I think you should start by reading up on howsudio i stored and processed. This post might help: http://blog.bjornroche.com/2013/05/the-abcs-of-pcm-uncompressed-digital.html – Bjorn Roche Jun 05 '13 at 14:15

4 Answers4

7

So you want to transmit digital information using audio? Basically you want to implement a MODEM in software (no matter if it is pure software, it's still called modem).

A modem (MOdulator-DEModulator) is a device that modulates an analog carrier signal to encode digital information, and also demodulates such a carrier signal to decode the transmitted information. The goal is to produce a signal that can be transmitted easily and decoded to reproduce the original digital data. Modems can be used over any means of transmitting analog signals, from light emitting diodes to radio. [wikipedia]

There are modems everywhere you need to transmit data over an analog media, be it sound, light or radio waves. Your TV remote probably is an infrared modem.

Modems implemented in pure software are called soft-modems. Most soft-modems I see in the wild are using some form of FSK modulation:

Frequency-shift keying (FSK) is a frequency modulation scheme in which digital information is transmitted through discrete frequency changes of a carrier wave.1 The simplest FSK is binary FSK (BFSK). BFSK uses a pair of discrete frequencies to transmit binary (0s and 1s) information.2 With this scheme, the "1" is called the mark frequency and the "0" is called the space frequency. The time domain of an FSK modulated carrier is illustrated in the figures to the right. [wikipedia]

There are very interesting applications for data transmission through atmosphere via sound waves - I guess it is what shopkick uses to verify user presence.

For Python check the GnuRadio project.

For a C library, look at the work of Steve Underwood (but please don't contact him with silly questions). I used his soft-modem to bootstrap a FAX to email gateway for Asterisk (a fax transmission is not much more than a B/W TIFF file encoded in audio for transmission over a phone line).

Paulo Scardine
  • 73,447
  • 11
  • 124
  • 153
  • i was wanting something a bit more simple and cheaper that does not require new hardware other than a cassette recorder. – kyle k Jun 05 '13 at 02:12
  • 1
    @kylek: you can do this with pure software, for example, using your notebook or smartphone to encode/decode the signal. That said, signal processing is not among the easiest topics in CS. – Paulo Scardine Jun 05 '13 at 02:29
  • 2
    @kylek: I'm pretty sure what Paulo Scardine is suggesting is that you can build a modem entirely in software. For example, the first popular home computer modems were just BFSK at 300 changes/second. Back then, you needed special hardware to do that fast enough to keep up—but nowadays, just using code pretty close to the sample in my answer, you can do it in a high-level language like Python with only 1% CPU. – abarnert Jun 05 '13 at 02:31
  • @kylek: Trust me, you don't want to reinvent the wheel, just use BFSK. You may borrow some Python code from gnuradio. – Paulo Scardine Jun 05 '13 at 02:39
  • @kylek: check out http://gnuradio.org/redmine/projects/gnuradio/wiki - all the bits you want are there, including FSK modulation and reading/writing WAV files. – Paulo Scardine Jun 05 '13 at 02:47
7

From your comments, you want to process the binary data bit by bit, turning each bit into a high or low sound.

You still need to decide exactly what those high and low sounds are, and how long each one sounds for (and whether there's a gap in between, and so on). If you make it slow, like 1/4 of a second per sound, then you're treating them as notes. If you make it very fast, like 1/44100 of a second, you're treating them as samples. The human ear can't hear 44100 different sounds in a second; instead, it hears a single sound at up to 22050Hz.

Once you've made those decisions, there are two parts to your problem.

First, you have to generate a stream of samples—for example, a stream of 44100 16-bit integers for every second. For really simple things, like playing a chunk of a raw PCM file in 44k 16-bit mono format, or generating a square wave, this is trivial. For more complex cases, like playing a chunk of an MP3 file or synthesizing a sound out of sine waves and filters, you'll need some help. The audioop module, and a few others in the stdlib, can give you the basics; beyond that, you'll need to search PyPI for appropriate modules.

Second, you have to send that sample stream to the headphone jack. There's no built-in support for this in Python. On some platforms, you can do this just by opening a special file and writing to it. But, more generally, you will need to find a third-party library on PyPI.

The simpler modules work for one particular type of audio system. Mac and Windows each have their own standards, and Linux has a half dozen different ones. There are also some Python modules that talk to higher-level wrappers; you may have to install and set up the wrapper, but once you do that, your code will work on any system.


So, let's work through one really simple example. Let's say you've got PortAudio set up on your system, and you've installed PyAudio to talk to it. This code will play square waves of 441Hz and 220.5Hz (just above middle C and low C) for just under 1/4th of a second (just because that's really easy).

import binascii

a = open('/Users/kyle/Desktop/untitled folder/unix commands.txt', 'r')
c = a.read()
b = bin(int(binascii.hexlify(c), 16))

sample_stream = []
high_note = (b'\xFF'*100 + b'\0'*100) * 50
low_note = (b'\xFF'*50 + b'\0'*50) * 100
for bit in b[2:]:
    if bit == '1':
        sample_stream.extend(high_note)
    else:
        sample_stream.extend(low_note)

sample_buffer = b''.join(sample_stream)

p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(8),
                channels=1,
                rate=44100,
                output=True)
stream.write(sample_buffer)
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • that is some helpful advice i investigate that `audioop` module thoroughly. – kyle k Jun 05 '13 at 02:20
  • Hi, I think I'm having a very similar task at the moment. In the first instance I also have a data pattern as above, means, a quite large data streams looks as "b'x\xdam\xdd]\xc4\xeemZ\xc7q)2\xcc\xd6' (...)" and is given as a binary object in python. All I know is that it shall represent a flac audio format. Can you tell me what exactly I see here? Is it binary code which I have to convert to FLAC? – Ben Mar 24 '20 at 08:28
1

So, here is Abarnert's code, updated to python3.

import binascii
import pyaudio

a = open('/home/ian/Python-programs/modem/testy_mcTest.txt', 'rb')
c = a.read()
b = bin(int(binascii.hexlify(c), 16))

sample_stream = []
high_note = (b'\xFF'*100 + b'\0'*100) * 50
low_note = (b'\xFF'*50 + b'\0'*50) * 100
for bit in b[2:]:
    if bit == '1':
        sample_stream.extend(high_note)
    else:
        sample_stream.extend(low_note)


sample_buffer = ''.join(map(str, sample_stream))

p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(1),
                channels=1,
                rate=44100,
                output=True)
stream.write(sample_buffer)

# stop stream (4)
stream.stop_stream()
stream.close()

# close PyAudio (5)
p.terminate()


Ian Walsh
  • 11
  • 2
0

If you're looking for a library that does this, I'd recommend libquiet. It uses an existing SDR library to perform its modulation, and it provides binaries that will offer you a pipe at one end and will feed the sound right to your soundcard using PortAudio at the other. It has GMSK for "over the air" low bitrate transmissions and QAM for cable-based higher bitrate.

Brian Armstrong
  • 326
  • 2
  • 14