Skip to content

Commit dd0316e

Browse files
authored
This PR adds an M1-focused Pulse-Packet implementation for more stable transmission, and introduces a WAV-input variant in addition to .tune input. (#70)
* basic impl for M1 Mac * Add c-apple-silicon-wav implementation * update readme
1 parent a02d542 commit dd0316e

10 files changed

Lines changed: 1005 additions & 79 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CPPFLAGS=-Wall -O2
2+
3+
main: main.c
4+
5+
.PHONY: clean
6+
7+
clean:
8+
rm -f main
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# c-apple-silicon-wav
2+
3+
This is a **delta implementation** based on the Apple Silicon version in
4+
`implementations/c-apple-silicon`, extended to play arbitrary WAV files.
5+
6+
For hardware assumptions and receiver setup (such as AM radio placement),
7+
see `implementations/c-apple-silicon/README.md`.
8+
This README summarizes **only the differences**.
9+
10+
## Changes from c-apple-silicon
11+
12+
1. Input format
13+
- Changed input from `.tune` to WAV
14+
- Run format: `./main input.wav`
15+
16+
2. WAV loader
17+
- Added `RIFF/WAVE` validation
18+
- Scans and reads `fmt ` / `data` chunks
19+
- Handles chunk padding (even-byte alignment)
20+
- Downmixes multi-channel audio to mono
21+
- Applies input sample rate to playback timing
22+
23+
3. Audio preprocessing
24+
- 32-bit-safe peak normalization
25+
- Voice-oriented pre-EQ (HP/LP + presence)
26+
- Compression and loudness boost via AGC + limiter
27+
28+
4. Modulation method
29+
- Replaced random-sampling-based density generation with a Sigma-Delta
30+
(error-accumulation) method
31+
- Improves intelligibility by reducing fine-grained random on/off artifacts
32+
33+
5. Packet handling
34+
- Keeps sample time continuity across packets
35+
- Sets default `PACKET_MS` to `100ms`
36+
- Adjustable at runtime via `SBR_PACKET_MS`
37+
38+
39+
## Supported WAV
40+
41+
- `RIFF/WAVE`
42+
- PCM 16-bit (`audio_format=1`, `bits_per_sample=16`)
43+
- 1 channel or more (internally downmixed to mono)
44+
- Any sample rate (tracked by internal timing)
45+
46+
Not supported:
47+
- float PCM
48+
- 24/32-bit PCM
49+
- WAV with compressed codecs
50+
51+
## Build
52+
53+
```bash
54+
cd /Users/cho45/tmp/system-bus-radio/implementations/c-apple-silicon-wav
55+
make
56+
```
57+
58+
## Run
59+
60+
```bash
61+
./main input.wav
62+
```
63+
64+
Examples:
65+
66+
```bash
67+
./main hello.wav
68+
./main sweep.wav
69+
```
70+
71+
## Main runtime parameters
72+
73+
- `SBR_DENSITY_EXP`: Exponent of the modulation curve
74+
- `SBR_DENSITY_DEPTH`: Modulation depth
75+
- `SBR_AGC_TARGET`: Target envelope level for AGC
76+
- `SBR_AGC_MAKEUP`: Makeup gain after AGC
77+
- `SBR_AGC_MAX_GAIN`: Maximum AGC gain
78+
- `SBR_PACKET_MS`: Packet length (ms)
79+
80+
## Tuning guidelines
81+
82+
- Still too quiet: increase `SBR_AGC_TARGET`, `SBR_AGC_MAKEUP`,
83+
and `SBR_AGC_MAX_GAIN`
84+
- Choppy output: increase `SBR_PACKET_MS` (for example `200` to `500`)
85+
- Distortion: decrease `SBR_AGC_MAKEUP` or `SBR_DENSITY_DEPTH`
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <stdint.h>
4+
#include <math.h>
5+
6+
#define SAMPLE_RATE 24000
7+
#define DURATION_PER_TONE 2
8+
#define NUM_TONES 5
9+
10+
int frequencies[] = {500, 1000, 2000, 4000, 8000};
11+
12+
int main() {
13+
FILE *fp = fopen("sweep.wav", "wb");
14+
if (!fp) return 1;
15+
16+
uint32_t total_samples = SAMPLE_RATE * DURATION_PER_TONE * NUM_TONES;
17+
uint32_t data_len = total_samples * 2;
18+
uint32_t riff_len = data_len + 36;
19+
20+
fwrite("RIFF", 1, 4, fp);
21+
fwrite(&riff_len, 4, 1, fp);
22+
fwrite("WAVE", 1, 4, fp);
23+
24+
fwrite("fmt ", 1, 4, fp);
25+
uint32_t fmt_len = 16;
26+
uint16_t audio_fmt = 1;
27+
uint16_t num_channels = 1;
28+
uint32_t sample_rate = SAMPLE_RATE;
29+
uint32_t byte_rate = SAMPLE_RATE * 2;
30+
uint16_t block_align = 2;
31+
uint16_t bits_per_sample = 16;
32+
33+
fwrite(&fmt_len, 4, 1, fp);
34+
fwrite(&audio_fmt, 2, 1, fp);
35+
fwrite(&num_channels, 2, 1, fp);
36+
fwrite(&sample_rate, 4, 1, fp);
37+
fwrite(&byte_rate, 4, 1, fp);
38+
fwrite(&block_align, 2, 1, fp);
39+
fwrite(&bits_per_sample, 2, 1, fp);
40+
41+
fwrite("data", 1, 4, fp);
42+
fwrite(&data_len, 4, 1, fp);
43+
44+
for (int t = 0; t < NUM_TONES; t++) {
45+
int freq = frequencies[t];
46+
printf("Generating %d Hz...\n", freq);
47+
for (int i = 0; i < SAMPLE_RATE * DURATION_PER_TONE; i++) {
48+
double time = (double)i / SAMPLE_RATE;
49+
double v = sin(2.0 * M_PI * freq * time);
50+
int16_t sample = (int16_t)(v * 32000.0);
51+
fwrite(&sample, 2, 1, fp);
52+
}
53+
}
54+
55+
fclose(fp);
56+
printf("Generated sweep.wav (500, 1000, 2000, 4000, 8000 Hz)\n");
57+
return 0;
58+
}
218 KB
Binary file not shown.

0 commit comments

Comments
 (0)