本文主要是介绍File transfer over sound card,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
转载墙外的文章,慢慢翻译,慢慢看
Before I even start, a word of warning: Never try these programs with your headphones on . THEY MAKE LOUD NOISES! It is possible to configure these programs to make noises way louder than you ever imagined your headphones could make . You can damage your hearing when playing with audio programming . Tinnitus isn't fun.This will be you if you don't take my warning seriously:
Background and problem
I have an old laptop laying about . A while back, I was in a bit of trouble getting it to work . It's so old that several parts of it has shut down . The USB system is fried, and it can't read modern burned DVD:s . I needed to move software to it to get the network up and running again . The only peripheral that was working (besides the keyboard and the screen) was the sound card . It was running an old version of Slackware .
Ah, I thought, and wrote a program that encoded data in sound . When I did it back then I used a bad algorithm. It was very noise sensitive and tried to do too much at the same time . As of then, I've improved (and simplified) the concept to using a sort of pulse width modulation (an idea I got when I read about the ZX Spectrum Tape Loader . )
The basic protocol is trivial:
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 signal means that errors don't taint their neighbors .
The crux isn't the signal generation (which is laughably trivial), it is the analysis on the receiving end; or rather dealing with the noise in the signal . The naive implementation would be to sum the square of the signal amplitude over time periods--the presence of a sine wave would converge towards some value and a silent signal would converge towards 0 . In a noisy signal, it almost always converges towards something non-zero, so no such luck .
So, the second approach would be to use a Fourier transform, to select the part of the spectrum where our signal resides (400 Hz is what I chose) .
A simple implementation of such a function 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 series of numbers between -1 and 1, and n is the modified frequency (which is to say: length * frequency / rate) . This function would give you a number corresponding to how much of a given frequency is in a sample . But you can do one better: Harmonics . Almost every loudspeaker will produce some level of harmonics even though the signal broadcasted is a plain sine wave with no harmonics .
So, to check if our signal is in a given segment, the following 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 signal is present in a given signal, you must compare this against some form of threshold . What's a good threshold varies with noise. A bad threshold value may either cause the program to interpret random noise as meaningful data, or reject good data as random noise .
if(sum > threshold) { /* Signal is present in data block */ }
else { /* Signal isn't present */ }
The protocol described above can be realized with the following 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. Following is all the code you need for transferring files from two computers using their soundcards .
Garbled transfers like this may soon arrive through a soundcard near you .
Utility programs
Before I get deeper into to the main program, I'm going to contribute some utility programs. record and playback . They are both wrappers for OSS, and reads and digests data from the soundcard; or writes digested data to the soundcard at given sample rates . They deal in signed char arrays only, and may convert them for the soundcard . Exactly what they do and how they work is a bit off topic, so I'll just post the code listings .
playback.c
record.c
The broadcasting end
As previously discussed, the broadcasting part of the program is pretty simple . The only real gotcha is the sample rate factor in the frequency . Since we're generating a signal with N bytes per second, we must decrease our frequencies by a factor 1/N . Beyond that, it's really quite trivial.
generate.c
The math parts
Almost there now . We just need some fourier transforms and things of such nature . The analysis end of the program can also make a XPM file of the frequency spectrum of the input, which is why you see a bunch of XPM code .
fourier.c
fourier.h
Finally.. . the receiving end
Most of what this one does has already been discussed . The threshold is hard-coded . You may want to change it or whatever.
analyze.c
... one file to compile them all, and into objects link them
Makefile
To compile, you just run
> make
Using the programs
Before I get to actually using the programs, I repeat my warning: Never try these programs with your headphones on . THEY MAKE LOUD NOISES! It is possible to configure these programs to make noises way louder than you ever imagined your headphones could make . You can damage your hearing when playing with audio programming . Tinnitus isn't fun.
Not there yet. It's quite an elaborate matter to use all these programs. First you'll want to generate your raw sound data . Let's transfer /etc/fstab (don't do this as root! Something might go horribly wrong ! )
First, attach the microphone on the receiving end to the speakers on the transmitting end . Use duct tape or whatever. I had an old hands free headset that I wrapped so that the microphone was held in place by the earpiece .
On the transmitting computer, run the following command:
> ./generate -b 25 -r 48000 -o out.data /etc/fstab
Enter, but do not start the following on the transmitting computer:
> ./playback -r 48000 < out.data # don't press enter yet!
Now, on the receiving computer, run the following command:
> ./record -r 48000 -o out.recdata
Note that out . recdata will grow very fast. In this case, 48000 bytes/second .
Run the command pre-typed in the transmitting computer's terminal . Be very quitet, and listen to the noise coming from of the speaker . This may take quite some time. Practice your Zen. Find enlightenment. When the noise stops, press Ctrl+C on the receiving computer .
Run the following command on the receiving computer:
> ./analyze -b 25 out.recdata
Watch a semi-garbled /etc/fstab be printed across your screen . The -b switch is to be taken with a grain of salt. It is proportional to how fast the transfer is . It must (obviously) be the same on the receiving and the transmitting end . I've gotten it to work at -b 50 -r 48000. Sample rate (-r) increases the processing time, but it also allows faster transfers . There are a few fixed possible sample rates, 8000 always works, others that are supported by most soundcards are 11025,16000,22050,24000,32000,44100 and 48000 .
So, in summary: -b determines how fast the transfer is, and the maximum possible transfer speed is limited by the sampling rate .
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 .
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.
这篇关于File transfer over sound card的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!