File transfer over sound card

转载墙外的文章,慢慢翻译,慢慢看

Be­fore I even start, a word of warn­ing: Never try these pro­grams with your head­phones on .  THEY MAKE LOUD NOISES! It is pos­si­ble to con­fig­ure these pro­grams to make noises way louder than you ever imag­ined your head­phones could make .  You can dam­age your hear­ing when play­ing with audio pro­gram­ming .   Tin­ni­tus  isn't fun. 

This will be you if you don't take my warn­ing se­ri­ously: 



Back­ground and prob­lem 

I have an old lap­top lay­ing about .  A while back, I was in a bit of trou­ble get­ting it to work .  It's so old that sev­eral parts of it has shut down .  The USB sys­tem is fried, and it can't read mod­ern burned DVD:s .  I needed to move soft­ware to it to get the net­work up and run­ning again .  The only pe­riph­eral that was work­ing (be­sides the key­board and the screen) was the sound card .  It was run­ning an old ver­sion of  Slack­ware  .  

Ah, I thought, and wrote a pro­gram that en­coded data in sound .  When I did it back then I used a bad al­go­rithm. It was very noise sen­si­tive and tried to do too much at the same time .  As of then, I've im­proved (and sim­pli­fied) the con­cept to using a sort of pulse width mod­u­la­tion (an idea I got when I read about the  ZX Spec­trum Tape Loader .

The basic pro­to­col is triv­ial:
For every character:

  For every bit:

    Send a short pulse if the bit is 1. 

    Send a long pulse if the bit is 0.

    Send a silence.

  Send a very long pulse (4 times as long as the shortest pulse).

  Send a silence.


This is nice and not very error prone .  The end-of-byte sig­nal means that er­rors don't taint their neigh­bors .  

The crux isn't the sig­nal gen­er­a­tion (which is laugh­ably triv­ial), it is the analy­sis on the re­ceiv­ing end; or rather deal­ing with the noise in the sig­nal .  The naive im­ple­men­ta­tion would be to sum the square of the sig­nal am­pli­tude over time pe­ri­ods--the pres­ence of a sine wave would con­verge to­wards some value and a silent sig­nal would con­verge to­wards 0 .  In a noisy sig­nal, it al­most al­ways con­verges to­wards some­thing non-zero, so no such luck .  

So, the sec­ond ap­proach would be to use a Fourier trans­form, to se­lect the part of the spec­trum where our sig­nal re­sides (400 Hz is what I chose) .  

A sim­ple im­ple­men­ta­tion of such a func­tion looks like this: 

double fourier1(double x_in[], double n, int length) { 
double x_complex[2] = { 0, 0 }; 
int i; 

for(i = 0; i < length; i++) { 
x_complex[0] += x_in[i] * cos(M_PI * 2 * i * n / (double) length); 
x_complex[1] += x_in[i] * sin(M_PI * 2 * i * n / (double) length); 

return sqrt(x_complex[0]*x_complex[0] + x_complex[1]*x_complex[1]) / (double) length; 



Where x_in is a se­ries of num­bers be­tween -1 and 1, and n is the mod­i­fied fre­quency (which is to say: length * fre­quency / rate) .  This func­tion would give you a num­ber cor­re­spond­ing to how much of a given fre­quency is in a sam­ple .  But you can do one bet­ter:  Har­mon­ics  .  Al­most every loud­speaker will pro­duce some level of har­mon­ics even though the sig­nal broad­casted is a plain sine wave with no har­mon­ics .  

So, to check if our sig­nal is in a given seg­ment, the fol­low­ing code can be used: 
double sum = 0; 
for(harmonic = 1; 2*harmonic < length / frq; harmonic++) { 
sum += fourier1(data, frq * harmonic, length); 



To check if the sig­nal is pre­sent in a given sig­nal, you must com­pare this against some form of thresh­old .  What's a good thresh­old varies with noise. A bad thresh­old value may ei­ther cause the pro­gram to in­ter­pret ran­dom noise as mean­ing­ful data, or re­ject good data as ran­dom noise .  

if(sum > threshold) { /* Signal is present in data block */ } 
else { /* Signal isn't present */ } 


The pro­to­col de­scribed above can be re­al­ized with the fol­low­ing code: 

if(sum < threshold) { 
if(signal_length) { 
if(signal_length > 10) { 
if(bit != 0) printf("(?)"); 
bit = 0; 
signal_length = 0; 
} else { 
bit_data = 2 * bit_data + (signal_length < 6); 
if(++bit == 8) { 
printf("%c", bit_data); 
fflush(NULL); 
bit = 0; 


signal_length = 0; 

} else { 
signal_length++; 



This does work .  It's not just some crazy pipe dream. Fol­low­ing is all the code you need for trans­fer­ring files from two com­put­ers using their sound­cards .  



Gar­bled trans­fers like this may soon ar­rive through a sound­card near you .  


Util­ity pro­grams 

Be­fore I get deeper into to the main pro­gram, I'm going to con­tribute some util­ity pro­grams. record and play­back .  They are both wrap­pers for OSS, and reads and di­gests data from the sound­card; or writes di­gested data to the sound­card at given sam­ple rates .  They deal in signed char ar­rays only, and may con­vert them for the sound­card .  Ex­actly what they do and how they work is a bit off topic, so I'll just post the code list­ings .  

play­back.c 
record.c 

The broad­cast­ing end 
As pre­vi­ously dis­cussed, the broad­cast­ing part of the pro­gram is pretty sim­ple . The only real gotcha is the sam­ple rate fac­tor in the fre­quency .  Since we're gen­er­at­ing a sig­nal with N bytes per sec­ond, we must de­crease our fre­quen­cies by a fac­tor 1/N .  Be­yond that, it's re­ally quite triv­ial. 

gen­er­ate.

The math parts 
Al­most there now .  We just need some fourier trans­forms and things of such na­ture .  The analy­sis end of the pro­gram can also make a XPM file of the fre­quency spec­trum of the input, which is why you see a bunch of XPM code .  

fourier.c 
fourier.h 

Fi­nally.. .  the re­ceiv­ing end 

Most of what this one does has al­ready been dis­cussed .  The thresh­old is hard-coded .  You may want to change it or what­ever. 

an­a­lyze.

... one file to com­pile them all, and into ob­jects link them 

Make­file 

To com­pile, you just run 
> make  

Using the pro­grams 

Be­fore I get to ac­tu­ally using the pro­grams, I re­peat my warn­ing: Never try these pro­grams with your head­phones on .  THEY MAKE LOUD NOISES! It is pos­si­ble to con­fig­ure these pro­grams to make noises way louder than you ever imag­ined your head­phones could make .  You can dam­age your hear­ing when play­ing with audio pro­gram­ming .   Tin­ni­tus  isn't fun. 

Not there yet. It's quite an elab­o­rate mat­ter to use all these pro­grams. First you'll want to gen­er­ate your raw sound data .  Let's trans­fer /etc/fstab (don't do this as root! Some­thing might go hor­ri­bly wrong !

First, at­tach the mi­cro­phone on the re­ceiv­ing end to the speak­ers on the trans­mit­ting end .  Use duct tape or what­ever. I had an old hands free head­set that I wrapped so that the mi­cro­phone was held in place by the ear­piece .  





On the trans­mit­ting com­puter, run the fol­low­ing com­mand: 
./generate -b 25 -r 48000 -o out.data /etc/fstab 


Enter, but do not start the fol­low­ing on the trans­mit­ting com­puter: 
./playback -r 48000 < out.data # don't press enter yet! 


Now, on the re­ceiv­ing com­puter, run the fol­low­ing com­mand: 
./record -r 48000 -o out.recdata 

Note that out . ​recdata will grow very fast. In this case, 48000 bytes/sec­ond .  

Run the com­mand pre-typed in the trans­mit­ting com­puter's ter­mi­nal .  Be very quitet, and lis­ten to the noise com­ing from of the speaker .  This may take quite some time. Prac­tice your Zen. Find en­light­en­ment. When the noise stops, press Ctrl+C on the re­ceiv­ing com­puter .  

Run the fol­low­ing com­mand on the re­ceiv­ing com­puter: 
./analyze -b 25 out.recdata 


Watch a semi-gar­bled /etc/fstab be printed across your screen .  The -b switch is to be taken with a grain of salt. It is pro­por­tional to how fast the trans­fer is .  It must (ob­vi­ously) be the same on the re­ceiv­ing and the trans­mit­ting end .  I've got­ten it to work at -b 50 -r 48000. Sam­ple rate (-r) in­creases the pro­cess­ing time, but it also al­lows faster trans­fers .  There are a few fixed pos­si­ble sam­ple rates, 8000 al­ways works, oth­ers that are sup­ported by most sound­cards are 11025,16000,22050,24000,32000,44100 and 48000 .  

So, in sum­mary: -b de­ter­mines how fast the trans­fer is, and the max­i­mum pos­si­ble trans­fer speed is lim­ited by the sam­pling rate .  

If it doesn't work, try play­ing what you recorded with play­back .  If you can hear and dis­tin­guish the beeps, then so should the com­puter be able to .  If record or play­back fails, chances are you don't have per­mis­sions to ac­cess /dev/dsp .  If all you get is char­ac­ter salad, fid­dle with thresh­old in an­a­lyze . c. 

An even more elab­o­rate ver­sion of this pro­gram is de­scribed in  File Trans­fer Over Sound Card II - Phase Shift Key­ing  .  

2011 up­date: Moved the sources to a  github repo  .    


If it doesn't work, try playing what you recorded with playback. If you can hear and distinguish the beeps, then so should the computer be able to. If record or playback fails, chances are you don't have permissions to access /dev/dsp. If all you get is character salad, fiddle with threshold in analyze.c



An even more elaborate version of this program is described in File Transfer Over Sound Card II - Phase Shift Keying. 

2011 update: Moved the sources to a github repo.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值