mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-02-06 16:47:59 +08:00
r2t2 - Transmit data through the PC speaker (#32)
* inital implementation * remove file * ggwave-cli : txProtocol -> txProtocolId * ggwave : add custom protocol enum values * r2t2 : use cutom protocols * r2t2 : build only on Unix systems * r2t2 : remove thread * r2t2-rx : wip * r2t2 : wasm build ready + various fixes * r2t2 : error message * Update README.md * Update README.md * Update README.md * Update README.md * r2t2 : length 16 * r2t2 : use slow protocol by default * r2t2 : add timestamp * r2t2 : update html * r2t2 : update github link * r2t2 : more robust tx * r2t2 : add option to use beep command * emscripten : cannot use requestAnimationFrame when capturing audio This causes the queued audio buffer to grow indefinitely when the page is not focused, causing the process to run out of memory. * r2t2 : disable beep option * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * r2t2 : add example to README
This commit is contained in:
136
examples/r2t2/main.cpp
Normal file
136
examples/r2t2/main.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#include "ggwave/ggwave.h"
|
||||
|
||||
#include "ggwave-common.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
#define CONSOLE "/dev/tty0"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
void processTone(int fd, double freq_hz, long duration_ms, bool useBeep, bool printTones) {
|
||||
if (printTones) {
|
||||
printf("TONE %8.2f Hz %5ld ms\n", freq_hz, duration_ms);
|
||||
return;
|
||||
}
|
||||
|
||||
if (useBeep) {
|
||||
static char cmd[128];
|
||||
snprintf(cmd, 128, "beep -f %g -l %ld", freq_hz, duration_ms);
|
||||
system(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
long pitch = std::round(1193180.0/freq_hz);
|
||||
long ms = std::round(duration_ms);
|
||||
ioctl(fd, KDMKTONE, (ms<<16)|pitch);
|
||||
usleep(ms*1000);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
printf("Usage: %s [-tN] [-lN]\n", argv[0]);
|
||||
printf(" -p - print tones, no playback\n");
|
||||
//printf(" -b - use 'beep' command\n");
|
||||
printf(" -tN - transmission protocol\n");
|
||||
printf(" -lN - fixed payload length of size N, N in [1, %d]\n", GGWave::kMaxLengthFixed);
|
||||
printf("\n");
|
||||
|
||||
const GGWave::TxProtocols protocols = {
|
||||
{ GGWAVE_TX_PROTOCOL_CUSTOM_0, { "[R2T2] Normal", 64, 9, 1, } },
|
||||
{ GGWAVE_TX_PROTOCOL_CUSTOM_1, { "[R2T2] Fast", 64, 6, 1, } },
|
||||
{ GGWAVE_TX_PROTOCOL_CUSTOM_2, { "[R2T2] Fastest", 64, 3, 1, } },
|
||||
};
|
||||
|
||||
auto argm = parseCmdArguments(argc, argv);
|
||||
bool printTones = argm.find("p") != argm.end();
|
||||
bool useBeep = false; //argm.find("b") != argm.end();
|
||||
int txProtocolId = argm["t"].empty() ? GGWAVE_TX_PROTOCOL_CUSTOM_0 : std::stoi(argm["t"]);
|
||||
int payloadLength = argm["l"].empty() ? 16 : std::stoi(argm["l"]);
|
||||
|
||||
GGWave ggWave({
|
||||
payloadLength,
|
||||
GGWave::kBaseSampleRate,
|
||||
GGWave::kBaseSampleRate,
|
||||
GGWave::kDefaultSamplesPerFrame,
|
||||
GGWave::kDefaultSoundMarkerThreshold,
|
||||
GGWAVE_SAMPLE_FORMAT_F32,
|
||||
GGWAVE_SAMPLE_FORMAT_F32});
|
||||
|
||||
printf("Available Tx protocols:\n");
|
||||
for (const auto & protocol : protocols) {
|
||||
printf(" -t%d : %s\n", protocol.first, protocol.second.name);
|
||||
}
|
||||
|
||||
if (protocols.find(GGWave::TxProtocolId(txProtocolId)) == protocols.end()) {
|
||||
fprintf(stderr, "Unknown Tx protocol %d\n", txProtocolId);
|
||||
return -3;
|
||||
}
|
||||
|
||||
printf("Selecting Tx protocol %d\n", txProtocolId);
|
||||
|
||||
int fd = 1;
|
||||
if (useBeep == false && printTones == false) {
|
||||
if (ioctl(fd, KDMKTONE, 0)) {
|
||||
fd = open(CONSOLE, O_RDONLY);
|
||||
}
|
||||
if (fd < 0) {
|
||||
perror(CONSOLE);
|
||||
fprintf(stderr, "This program must be run as root\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Enter a text message:\n");
|
||||
|
||||
std::string message;
|
||||
std::getline(std::cin, message);
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (message.size() == 0) {
|
||||
fprintf(stderr, "Invalid message: size = 0\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ((int) message.size() > payloadLength) {
|
||||
fprintf(stderr, "Invalid message: size > %d\n", payloadLength);
|
||||
return -3;
|
||||
}
|
||||
|
||||
ggWave.init(message.size(), message.data(), protocols.at(GGWave::TxProtocolId(txProtocolId)), 10);
|
||||
|
||||
GGWave::CBWaveformOut tmp = [](const void * , uint32_t ){};
|
||||
ggWave.encode(tmp);
|
||||
|
||||
int nFrames = 0;
|
||||
double lastF = -1.0f;
|
||||
|
||||
auto tones = ggWave.getWaveformTones();
|
||||
for (auto & tonesCur : tones) {
|
||||
if (tonesCur.size() == 0) continue;
|
||||
const auto & tone = tonesCur.front();
|
||||
if (tone.freq_hz != lastF) {
|
||||
if (nFrames > 0) {
|
||||
processTone(fd, lastF, nFrames*tone.duration_ms, useBeep, printTones);
|
||||
}
|
||||
nFrames = 0;
|
||||
lastF = tone.freq_hz;
|
||||
}
|
||||
++nFrames;
|
||||
}
|
||||
|
||||
if (nFrames > 0) {
|
||||
const auto & tone = tones.front().front();
|
||||
processTone(fd, lastF, nFrames*tone.duration_ms, useBeep, printTones);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user