sb-duplex 1.2.0b0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. sb_duplex-1.2.0b0/.gitignore +15 -0
  2. sb_duplex-1.2.0b0/LICENSE +21 -0
  3. sb_duplex-1.2.0b0/PKG-INFO +374 -0
  4. sb_duplex-1.2.0b0/public/LICENSE +21 -0
  5. sb_duplex-1.2.0b0/public/README.md +347 -0
  6. sb_duplex-1.2.0b0/pyproject.toml +42 -0
  7. sb_duplex-1.2.0b0/soundbridge/__init__.py +0 -0
  8. sb_duplex-1.2.0b0/soundbridge/__main__.py +7 -0
  9. sb_duplex-1.2.0b0/soundbridge/app.py +370 -0
  10. sb_duplex-1.2.0b0/soundbridge/audio.py +146 -0
  11. sb_duplex-1.2.0b0/soundbridge/cli.py +705 -0
  12. sb_duplex-1.2.0b0/soundbridge/config.py +105 -0
  13. sb_duplex-1.2.0b0/soundbridge/devices.py +120 -0
  14. sb_duplex-1.2.0b0/soundbridge/link/__init__.py +1 -0
  15. sb_duplex-1.2.0b0/soundbridge/link/calibration.py +22 -0
  16. sb_duplex-1.2.0b0/soundbridge/link/calibrator.py +404 -0
  17. sb_duplex-1.2.0b0/soundbridge/link/detector.py +239 -0
  18. sb_duplex-1.2.0b0/soundbridge/link/session.py +365 -0
  19. sb_duplex-1.2.0b0/soundbridge/link/sounding.py +519 -0
  20. sb_duplex-1.2.0b0/soundbridge/link/stream.py +150 -0
  21. sb_duplex-1.2.0b0/soundbridge/phy/__init__.py +0 -0
  22. sb_duplex-1.2.0b0/soundbridge/phy/base.py +44 -0
  23. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/__init__.py +0 -0
  24. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/block_format.py +159 -0
  25. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/channel.py +75 -0
  26. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/decode_wav.py +170 -0
  27. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/fec.py +176 -0
  28. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/fec_rx.py +190 -0
  29. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/mcs.py +43 -0
  30. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/modem.py +311 -0
  31. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/ofdm_params.py +139 -0
  32. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/phy.py +55 -0
  33. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/rx.py +517 -0
  34. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/tx.py +115 -0
  35. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/tx_stereo.py +93 -0
  36. sb_duplex-1.2.0b0/soundbridge/phy/ofdm/wav_io.py +51 -0
  37. sb_duplex-1.2.0b0/soundbridge/power.py +58 -0
  38. sb_duplex-1.2.0b0/soundbridge/progress.py +238 -0
  39. sb_duplex-1.2.0b0/soundbridge/transfer/__init__.py +1 -0
  40. sb_duplex-1.2.0b0/soundbridge/transfer/ack.py +120 -0
  41. sb_duplex-1.2.0b0/soundbridge/transfer/assembler.py +85 -0
  42. sb_duplex-1.2.0b0/soundbridge/transfer/config.py +83 -0
  43. sb_duplex-1.2.0b0/soundbridge/transfer/gf256.py +75 -0
  44. sb_duplex-1.2.0b0/soundbridge/transfer/manifest.py +79 -0
  45. sb_duplex-1.2.0b0/soundbridge/transfer/packing.py +41 -0
  46. sb_duplex-1.2.0b0/soundbridge/transfer/parity.py +122 -0
  47. sb_duplex-1.2.0b0/soundbridge/transfer/rate.py +108 -0
  48. sb_duplex-1.2.0b0/soundbridge/transfer/sender.py +92 -0
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ .venv/
7
+ venv/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .idea/
12
+ .vscode/
13
+ *.wav
14
+ *.log
15
+ out/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Makoto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,374 @@
1
+ Metadata-Version: 2.5
2
+ Name: sb-duplex
3
+ Version: 1.2.0b0
4
+ Summary: Transferência de arquivos por áudio entre dois PCs (OFDM + FEC + ARQ), bidirecional, com calibração automática.
5
+ Project-URL: Homepage, https://github.com/Cafecanudo/sb-duplex
6
+ Project-URL: Documentation, https://github.com/Cafecanudo/sb-duplex#readme
7
+ Project-URL: Issues, https://github.com/Cafecanudo/sb-duplex/issues
8
+ Author: Makoto
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: arq,audio,file-transfer,modem,ofdm,qam,wasapi
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Communications :: File Sharing
22
+ Classifier: Topic :: Multimedia :: Sound/Audio
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: numpy>=1.24
25
+ Requires-Dist: sounddevice>=0.4
26
+ Description-Content-Type: text/markdown
27
+
28
+ # sb-duplex
29
+
30
+ Transferência de arquivos **por áudio** entre dois PCs, por cabo: codifica o arquivo em som (**OFDM** com
31
+ correção de erros), envia pela saída de áudio de um PC e reconstrói na entrada do outro. Com dois cabos é
32
+ **bidirecional**: o receptor confirma e o transmissor reenvia só o que faltou. Os dois lados usam o mesmo
33
+ programa, por linha de comando. Inclui **calibração automática** do enlace nos dois sentidos.
34
+
35
+ > **Versão beta, só Windows.** O áudio usa WASAPI (modo exclusivo). Linux e macOS ficam para versões
36
+ > futuras.
37
+
38
+ ## Requisitos
39
+
40
+ - Windows 10 ou 11 (WASAPI)
41
+ - Python 3.10 ou mais novo
42
+ - Dois PCs e cabos de áudio P2 (3,5 mm); para notebooks com entrada combo, um cabo P3 e um adaptador fone +
43
+ microfone (veja as ligações abaixo)
44
+
45
+ ## Instalação
46
+
47
+ ```bash
48
+ python -m pip install sb-duplex
49
+ ```
50
+
51
+ O pacote não cria um executável: tudo roda com `python -m soundbridge`.
52
+
53
+ ```bash
54
+ python -m soundbridge --help
55
+ python -m soundbridge --list-devices
56
+ ```
57
+
58
+ ## Como usar
59
+
60
+ Cada PC usa uma **saída** (`--out`) e uma **entrada** (`--in`) de áudio, ligadas ao outro PC por cabo:
61
+ a saída de um vai na entrada do outro. Com um cabo, a transferência é **unidirecional** (`uni`); com
62
+ dois cabos cruzados, pode ser **bidirecional** (`--bi`, com confirmação e reenvio).
63
+
64
+ ![Ligação unidirecional: a saída de áudio do PC A vai na entrada (microfone ou linha) do PC B](https://raw.githubusercontent.com/Cafecanudo/sb-duplex/main/docs/img/ligacao-unidirecional.svg)
65
+
66
+ ![Ligação bidirecional: dois cabos cruzados, dados de A para B e ACK de B para A](https://raw.githubusercontent.com/Cafecanudo/sb-duplex/main/docs/img/ligacao-bidirecional.svg)
67
+
68
+ Notebook com uma só entrada **combo** (P3, fone e microfone no mesmo conector): um cabo P3 de 4 polos leva
69
+ os dois sentidos e, no outro PC, um adaptador P3 → fone + microfone é ligado **cruzado**.
70
+
71
+ ![Ligação bidirecional com cabo P3 combo e adaptador fone + microfone cruzado no PC B](https://raw.githubusercontent.com/Cafecanudo/sb-duplex/main/docs/img/ligacao-combo-p3.svg)
72
+
73
+ Nos exemplos, os IDs são fictícios: troque pelos do seu `--list-devices`.
74
+
75
+ | PC | Saída (`--out`) | Entrada (`--in`) |
76
+ |---|---|---|
77
+ | PC A | `k7p2` | `m3xa` |
78
+ | PC B | `d9fr` | `t4wq` |
79
+
80
+ ### Listar dispositivos
81
+
82
+ ```bash
83
+ # saídas e entradas de áudio com ID curto, mais os padrões e apelidos cadastrados
84
+ python -m soundbridge --list-devices
85
+
86
+ # o mesmo em JSON (um documento: outputs, inputs, aliases, defaults, config)
87
+ python -m soundbridge --list-devices --json
88
+
89
+ # só os IDs das entradas, para scripts (com jq)
90
+ python -m soundbridge --list-devices --json | jq -r '.inputs[].id'
91
+
92
+
93
+ # apelido para um device (use depois em --out/--in); "dados=" remove
94
+ python -m soundbridge --alias dados=k7p2
95
+ python -m soundbridge --alias retorno=m3xa
96
+ python -m soundbridge --alias dados=
97
+
98
+ # padrões: dispensam --out/--in (e a pasta do --rx) nos próximos comandos
99
+ python -m soundbridge --save-defaults --out k7p2 --in m3xa
100
+ python -m soundbridge --save-defaults --dir D:\recebidos
101
+ python -m soundbridge --save-defaults --out dados --in retorno --dir D:\recebidos
102
+ python -m soundbridge --clear-defaults
103
+ ```
104
+
105
+ Os devices aceitam ID curto (`k7p2`), apelido (`dados`), nome ou trecho do nome
106
+ (`"Alto Falante"`) e índice (que muda ao replugar). O ID curto vem do nome do device e não muda.
107
+
108
+ ### Calibrar o enlace
109
+
110
+ Cada par de placas e cabos se comporta de um jeito: uma saída de linha aguenta estéreo em banda cheia e
111
+ modulação alta; uma entrada de microfone de notebook pode somar os canais (só mono), cortar acima de ~8 kHz,
112
+ saturar com sinal fraco e ter ganho automático (AGC). Achar à mão o `--mono`, o `--band-high`, o `--peak` e
113
+ o `--mcs` de cada sentido exige medir com tons e tentativas. A calibração faz isso sozinha, nos **dois
114
+ sentidos**, em poucos minutos.
115
+
116
+ **Como funciona.** Os dois cabos precisam estar ligados e o outro PC escutando com `--rx` e `--out`.
117
+
118
+ 1. O PC que roda `--calibrate` envia uma **sondagem** (~5 s): uma escada de níveis de sinais conhecidos,
119
+ diferentes no canal esquerdo e no direito.
120
+ 2. O outro PC mede o que chegou e devolve o resultado pelo 2º cabo:
121
+ - qual nível chega limpo, sem saturar;
122
+ - se a entrada soma os canais (então mono);
123
+ - até que frequência o sinal passa (banda);
124
+ - o SNR, que define o MCS.
125
+
126
+ Em seguida, ele sonda o sentido de volta, e o primeiro PC mede.
127
+ 3. Com **`--calibrate-test`**, a escolha de cada sentido é **validada com transferências reais** (descartadas
128
+ no RX). Se menos de 80% passar, a configuração desce um degrau (MCS menor, depois banda menor, depois
129
+ mono) e é testada de novo. Os tamanhos de teste vêm de uma lista: arquivos pequenos validam rápido;
130
+ arquivos grandes pegam problemas que só aparecem em quadros longos (AGC, rajadas da placa).
131
+ 4. Com **`--calibrate-save`**, o resultado vira o **perfil padrão** dos dois PCs (por par de devices). Daí
132
+ em diante, `--tx` usa o pico, o mono, a banda e o MCS do perfil, e `--rx` usa o nível do ACK, quando você
133
+ não os informa. O que for passado na linha de comando sempre vence.
134
+
135
+ Sem `--calibrate-save`, nada é gravado: a calibração só mostra o resultado e os comandos prontos.
136
+
137
+ ```bash
138
+ # 1. Só medir e ver a recomendação (nada é testado nem salvo)
139
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr --keep
140
+ PC A: python -m soundbridge --calibrate --out k7p2 --in m3xa
141
+
142
+ # 2. Medir, validar com 10 transferências de 5 KB por sentido e salvar nos dois PCs
143
+ PC A: python -m soundbridge --calibrate --out k7p2 --in m3xa --calibrate-test --calibrate-save
144
+
145
+ # 3. Validar em vários tamanhos (do menor ao maior; a escolha final passa em todos)
146
+ PC A: python -m soundbridge --calibrate --out k7p2 --in m3xa --calibrate-test 5k,200k,1mb --calibrate-save
147
+
148
+ # 4. Depois de salvo, enviar e receber sem informar pico, mono, banda nem MCS
149
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr --keep
150
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --in m3xa --bi
151
+ ```
152
+
153
+ Exemplo de resultado (PC A com saída de linha; PC B com entrada de microfone de notebook):
154
+
155
+ ```
156
+ este PC → outro: mono · 5 kHz · MCS 1 (QPSK r34) · pico 0.0055 · SNR 14 dB · testes 5k 10/10 OK
157
+ aviso: ganho automático (AGC) ou compressão na entrada: desligue o AGC/melhorias de áudio
158
+ outro → este PC: estéreo · 22 kHz · MCS 9 (1024-QAM r34) · pico 0.2 · SNR 41 dB · testes 5k 10/10 OK
159
+ comandos:
160
+ enviar daqui: python -m python -m soundbridge --tx ARQUIVO --out k7p2 --in m3xa --bi --mono --band-high 5000 --peak 0.0055 --mcs 1
161
+ receber no outro PC: python -m python -m soundbridge --rx PASTA --out <saída do outro PC> --in <entrada do outro PC> --keep --ack-peak 0.2
162
+ enviar do outro PC: python -m python -m soundbridge --tx ARQUIVO --out <saída do outro PC> --in <entrada do outro PC> --bi --band-high 22000 --peak 0.2 --mcs 9
163
+ receber aqui: python -m python -m soundbridge --rx PASTA --out k7p2 --in m3xa --keep --ack-peak 0.0055
164
+ perfil salvo nos dois PCs: --tx e --rx usam esses valores quando não forem informados
165
+ ```
166
+
167
+ **Tamanhos de teste** (`--calibrate-test`): `2k`, `5k`, `10k`, `20k`, `50k`, `100k`, `200k`, `500k`, `1mb`,
168
+ `5mb`, `10mb`; sem lista, `5k`. São 10 repetições até `100k`, 3 até `1mb` e 1 em `5mb` e `10mb`. Os grandes
169
+ levam minutos por tentativa (um `10mb` leva ~15 min no melhor caso), então use-os quando o objetivo for
170
+ enviar arquivos grandes.
171
+
172
+ **Avisos.** "O menor nível já chega saturado" pede para reduzir o volume de gravação ou desligar o
173
+ reforço (boost) da entrada. "AGC" indica ganho automático na entrada: a calibração ainda funciona, mas
174
+ limita o MCS e quadros longos podem falhar; o melhor é desligar o AGC/melhorias de áudio da entrada, ou
175
+ usar uma entrada de linha. Recalibre sempre que trocar de placa, porta, cabo ou volume.
176
+
177
+ ### Enviar dados
178
+
179
+ O RX sobe primeiro (fica esperando); depois o TX envia. **PC A envia → PC B recebe.**
180
+
181
+ ```bash
182
+ # 1. Um arquivo, um cabo (unidirecional)
183
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq
184
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2
185
+
186
+ # 2. Um arquivo, dois cabos (bidirecional: o RX confirma e o TX reenvia o que faltou)
187
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr
188
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --in m3xa --bi
189
+
190
+ # 3. Vários arquivos (lista entre aspas, separada por ";"; aceita curingas)
191
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr
192
+ PC A: python -m soundbridge --tx "C:\relatorio.pdf;C:\notas.txt;C:\fotos\*.jpg" --out k7p2 --in m3xa --bi
193
+
194
+ # 4. Uma pasta inteira, recursiva, dentro de uma subpasta do RX
195
+ # C:\docs\a.txt → D:\recebidos\backup\a.txt ; C:\docs\sub\b.txt → D:\recebidos\backup\sub\b.txt
196
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr
197
+ PC A: python -m soundbridge --tx C:\docs --dest backup --out k7p2 --in m3xa --bi
198
+
199
+ # 5. Arquivo numa subpasta do RX
200
+ PC A: python -m soundbridge --tx C:\foto.jpg --dest fotos/2026 --out k7p2 --in m3xa --bi
201
+
202
+ # 6. Vários envios em sequência sem --keep no RX (--more avisa que vem outro)
203
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr
204
+ PC A: python -m soundbridge --tx C:\a.pdf --out k7p2 --in m3xa --bi --more
205
+ PC A: python -m soundbridge --tx C:\b.pdf --out k7p2 --in m3xa --bi
206
+
207
+ # 7. MCS fixo (padrão: --auto)
208
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --in m3xa --bi --mcs 8
209
+
210
+ # 8. Sem compressão, ou compressão mais leve (padrão: comprime no nível 9)
211
+ PC A: python -m soundbridge --tx C:\video.mp4 --out k7p2 --no-zip
212
+ PC A: python -m soundbridge --tx C:\logs --out k7p2 --zip-level 6
213
+
214
+ # 9. Para uma entrada de microfone (mono, banda estreita, ganho alto) do outro lado
215
+ # --mono, --band-high e --peak só no TX: o RX lê o modo e a banda no header
216
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq
217
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --mono --band-high 10000 --peak 0.05 --mcs 8
218
+
219
+ # 10. Com padrões salvos nos dois PCs (sem --out/--in nem pasta)
220
+ PC B: python -m soundbridge --rx --keep
221
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --bi
222
+
223
+ # 11. Calibrar os dois sentidos, testar e salvar como padrão (ver "Calibrar o enlace")
224
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr --keep
225
+ PC A: python -m soundbridge --calibrate --out k7p2 --in m3xa --calibrate-test 5k,200k --calibrate-save
226
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --in m3xa --bi # usa o perfil salvo
227
+
228
+ # 12. Saída para scripts e diagnóstico
229
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --json # uma linha JSON por evento
230
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --verbose # barra + uma linha por round
231
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --no-progress # sem barra
232
+ ```
233
+
234
+ ### Receber dados
235
+
236
+ Do ponto de vista de quem recebe. **PC B recebe ← PC A envia.**
237
+
238
+ ```bash
239
+ # 1. Receber um arquivo e sair (um cabo: só unidirecional)
240
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq
241
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2
242
+
243
+ # 2. Receber com confirmação (dois cabos: aceita uni e bi; o modo é detectado sozinho)
244
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr
245
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --in m3xa --bi
246
+
247
+ # 3. Ficar recebendo vários arquivos até Ctrl+C
248
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr --keep
249
+ PC A: python -m soundbridge --tx C:\a.pdf --out k7p2 --in m3xa --bi
250
+ PC A: python -m soundbridge --tx "C:\b.pdf;C:\c.zip" --out k7p2 --in m3xa --bi
251
+
252
+ # 4. Receber na pasta padrão (ou na pasta atual, se não houver padrão)
253
+ PC B: python -m soundbridge --save-defaults --dir D:\recebidos
254
+ PC B: python -m soundbridge --rx --in t4wq --out d9fr
255
+
256
+ # 5. Receber de quem envia para entrada de microfone (o RX descobre mono e banda pelo header)
257
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq
258
+ PC A: python -m soundbridge --tx C:\relatorio.pdf --out k7p2 --mono --band-high 10000 --peak 0.05
259
+
260
+ # 6. Receber vários envios encadeados sem --keep (o TX usa --more; o RX sai no último)
261
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr
262
+ PC A: python -m soundbridge --tx "C:\a.pdf;C:\b.pdf;C:\c.pdf" --out k7p2 --in m3xa --bi
263
+
264
+ # 7. Responder a uma calibração do outro lado (o RX só precisa estar escutando, com --out)
265
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr
266
+ PC A: python -m soundbridge --calibrate --out k7p2 --in m3xa
267
+
268
+ # 8. Registrar a recepção em JSON (log para scripts)
269
+ PC B: python -m soundbridge --rx D:\recebidos --in t4wq --out d9fr --keep --json > recepcao.jsonl
270
+
271
+ # 9. Com padrões salvos (devices e pasta)
272
+ PC B: python -m soundbridge --save-defaults --out d9fr --in t4wq --dir D:\recebidos
273
+ PC B: python -m soundbridge --rx --keep
274
+ ```
275
+
276
+ O arquivo é gravado com o mesmo nome (mais a subpasta do `--dest` do TX) e nunca sobrescreve:
277
+ `relatorio (1).pdf`. Ctrl+C encerra o RX (código de saída 130).
278
+
279
+ ---
280
+
281
+ ## Parâmetros da linha de comando
282
+
283
+ Uma ação por vez (`--tx`, `--rx`, `--calibrate`, `--list-devices`, `--alias`, `--save-defaults`,
284
+ `--clear-defaults`). As tabelas abaixo agrupam os parâmetros por quem os usa.
285
+
286
+ ### TX (envio): `python -m soundbridge --tx ...`
287
+
288
+ | Parâmetro | Descrição |
289
+ |---|---|
290
+ | `--tx "ARQ1;ARQ2;..."` | Envia um ou mais arquivos e/ou pastas, em sequência: um item, ou uma lista entre aspas separada por `;` (ex.: `--tx "C:\a.jpg;C:\b.pdf;C:\fotos\*.jpg;C:\docs"`). Aceita curingas, expandidos pelo próprio SoundBridge. **Pasta** envia todos os arquivos dentro dela, recursivamente, e o RX recria a estrutura de subpastas **a partir do conteúdo** (sem o nome da própria pasta): com `--tx C:\docs --dest backup`, `C:\docs\a.txt` vai para `<pasta do RX>\backup\a.txt` e `C:\docs\sub\b.txt` para `<pasta do RX>\backup\sub\b.txt`. Pastas vazias são ignoradas. Todos menos o último levam `--more`, então o RX recebe a lista inteira mesmo sem `--keep`. Tudo é conferido antes de começar; no fim, um resumo (`3/3 arquivos enviados`). Exige `--out`; com `--bi`, exige também `--in` (informados ou do padrão, `--save-defaults`). |
291
+ | `--bi` | Bidirecional com ARQ: o RX confirma cada round e o TX reenvia só o que faltou. Exige os dois cabos (e o RX com `--out`). Padrão: unidirecional (um cabo, sem retransmissão, protegido por paridade Reed-Solomon). O RX detecta o modo sozinho. |
292
+ | `--auto` | Escolha automática do MCS (padrão). Uni: o maior MCS até 6 cujo áudio estimado cabe em 3 s, senão MCS 3 (na prática, MCS 6 até ~50 KB). Bi: MCS adaptativo começando em 7, que sobe e desce conforme as perdas de cada round. |
293
+ | `--mcs 0-9` | Fixa o MCS (desliga a adaptação no bi). Não combina com `--auto`. Tabela abaixo. |
294
+ | `--dest SUBPASTA` | Subpasta, relativa à pasta do RX, onde os arquivos serão gravados: `--tx C:\foto.jpg --dest ado/oash` com o RX em `--rx D:\recebidos` grava `D:\recebidos\ado\oash\foto.jpg`. Aceita `/` ou `\`; recusa `..` e drive. |
295
+ | `--more` | Avisa o RX que outro arquivo vem em seguida (o RX continua escutando mesmo sem `--keep` e encerra no primeiro arquivo sem `--more`, ou se o próximo não chegar em 2 min). Automático numa lista do `--tx`; manual para encadear vários comandos. |
296
+ | `--no-zip` | Envia sem compressão. Padrão: todo arquivo é comprimido (deflate) antes de enviar e o RX grava o original, com o mesmo nome e hash. Texto, código e logs ficam 2–3× menores; JPG, ZIP, DOCX e vídeo quase não mudam. |
297
+ | `--zip-level 0-9` | Nível de compressão. Padrão 9 (máximo: o canal é lento e a CPU gasta é desprezível); 0 só embala, sem comprimir. |
298
+ | `--mono` | Dados em mono (o mesmo sinal nos dois canais), para entrada ou cabo mono. Metade da velocidade. O RX detecta pelo header, sem opção. |
299
+ | `--peak 0-1` | Pico do sinal de dados. Padrão: 0,9 no uni, 0,5 no bi (no bi a placa opera em full-duplex e distorce em nível alto). Use o valor recomendado por `--calibrate`. |
300
+
301
+ No TX, `--out` leva os dados e `--in` recebe o ACK (só no `--bi`).
302
+
303
+ ### RX (recepção): `python -m soundbridge --rx ...`
304
+
305
+ | Parâmetro | Descrição |
306
+ |---|---|
307
+ | `--rx [PASTA]` | Recebe arquivos na pasta (criada se não existir) e espera até Ctrl+C. Sem pasta: a padrão (`--save-defaults --dir`) ou, sem padrão, a pasta atual. O modo (uni/bi), o mono e a compressão são detectados sozinhos. O arquivo é gravado na pasta (mais a subpasta do `--dest` do TX) e não sobrescreve: `nome (1).ext`. Exige `--in`. |
308
+ | `--keep` | Continua escutando depois de cada arquivo. Uma transmissão nova encerra a anterior se ela ficou incompleta. |
309
+
310
+ No RX, `--in` recebe os dados e `--out` envia o ACK. Sem `--out`, o RX só recebe transferências unidirecionais.
311
+
312
+ ### Comuns (TX e RX)
313
+
314
+ | Parâmetro | Descrição |
315
+ |---|---|
316
+ | `--out DEVICE` | Saída de áudio (TX: dados; RX: ACK). Aceita ID curto, apelido, nome (exato ou trecho único) ou índice. Sem ela, usa o padrão do `--save-defaults`. |
317
+ | `--in DEVICE` | Entrada de áudio (TX: ACK; RX: dados). Mesmos formatos de `--out`. Sem ela, usa o padrão do `--save-defaults`. |
318
+ | `--shared` | Usa o WASAPI em modo compartilhado. Padrão: exclusivo (evita o processamento de áudio do Windows, que degrada o sinal). |
319
+ | `--band-high HZ` | Limite superior da banda dos dados. Padrão: 22000. Valores da tabela: 5000, 7000, 8000, 10000, 14000, 18000, 22000. No TX define a banda; o RX procura todas as da tabela e lê a do header, sem precisar do parâmetro. Valor fora da tabela: o RX só acha o quadro se usar o mesmo `--band-high`. |
320
+ | `--ack-band HZ` | Limite superior da banda do ACK. Padrão: 7000 (entradas de microfone cortam em ~8 kHz). **Igual nos dois lados.** |
321
+ | `--ack-peak 0-1` | Pico do ACK. Padrão: o do perfil salvo pela calibração; sem perfil, 0,02 (baixo porque entradas de microfone têm ganho alto). |
322
+ | (padrão) | Barra de progresso numa linha atualizada no lugar: percentual, blocos, KB/s, tempo restante (pela taxa recente) e round/MCS. Avisos (clip) aparecem acima dela. Só em terminal (inclui o Git Bash); com a saída redirecionada, volta às linhas por round. |
323
+ | `--verbose` | Mostra também uma linha por round (TX) e por quadro (RX). |
324
+ | `--no-progress` | Sem barra: uma linha por round/quadro (o formato anterior). |
325
+ | `--json` | Saída em JSON para scripts e testes: uma linha por evento (progresso e resultado); no `--list-devices`, um único documento com `outputs`, `inputs` (cada device com `id`, `name`, `channels`, `samplerate`, `index`), `aliases`, `defaults` e `config`. |
326
+ | `-h`, `--help` | Mostra a ajuda. |
327
+
328
+ ### Configuração e diagnóstico
329
+
330
+ | Parâmetro | Descrição |
331
+ |---|---|
332
+ | `--list-devices` | Lista saídas e entradas de áudio com ID curto e nome, os padrões e os apelidos. |
333
+ | `--alias NOME=DEVICE` | Cadastra um apelido (ex.: `--alias dados=k7p2`) para usar em `--out`/`--in`. `NOME=` remove. Nome: letras minúsculas, dígitos, `_` ou `-`, começando por letra. Fica no arquivo de configuração do usuário (`%APPDATA%\soundbridge\config.json` no Windows; `SOUNDBRIDGE_CONFIG` troca o caminho). |
334
+ | `--save-defaults` | Grava o `--out`, o `--in` e/ou a pasta do `--rx` (`--dir PASTA`) informados como padrão (devices validados antes de gravar). O informado na linha de comando sempre vence. Um par basta para os dois papéis: em cada PC a saída e a entrada do enlace são as mesmas, seja ele TX ou RX. |
335
+ | `--dir PASTA` | Com `--save-defaults`: pasta padrão onde o `--rx` grava os arquivos. |
336
+ | `--clear-defaults` | Remove os padrões (devices e pasta). |
337
+ | `--calibrate` | Calibra o enlace nos **dois sentidos** contra um RX em escuta (`--rx` com `--out`): uma sondagem de ~5 s em cada sentido mede nível, mono/estéreo, banda e SNR e recomenda `--peak`, `--mono`, `--band-high` e `--mcs` para cada um, com os comandos de TX e RX. Avisa entrada saturada e AGC. Exige `--out` e `--in`. |
338
+ | `--calibrate-test [TAMANHOS]` | Com `--calibrate`: valida a escolha de cada sentido com transferências reais em bi (descartadas no RX), nos tamanhos da lista separada por vírgula: `2k`, `5k`, `10k`, `20k`, `50k`, `100k`, `200k`, `500k`, `1mb`, `5mb`, `10mb` (ex.: `--calibrate-test 5k,10k,10mb`; sem lista: `5k`). Repetições: 10 até 100k, 3 até 1mb, 1 em 5mb e 10mb. Testa do menor ao maior; aceita acima de 80% em cada tamanho; na 1ª reprovação desce um degrau (MCS, depois banda, depois mono) e recomeça, até 4 tentativas. Tamanhos grandes levam minutos (10mb ≈ 15 min por tentativa no melhor caso). |
339
+ | `--calibrate-save` | Com `--calibrate`: grava o resultado como perfil padrão nos **dois PCs**, por par de devices. Depois, `--tx` usa pico, mono, banda e MCS do perfil e `--rx` usa o pico do ACK, quando não forem informados (o informado sempre vence). Sem ele, a calibração só mostra o resultado. |
340
+
341
+ ### MCS (`--mcs`)
342
+
343
+ | MCS | Modulação | Código | MCS | Modulação | Código |
344
+ |---|---|---|---|---|---|
345
+ | 0 | QPSK | r1/2 | 5 | 64-QAM | r3/4 |
346
+ | 1 | QPSK | r3/4 | 6 | 256-QAM | r2/3 |
347
+ | 2 | 16-QAM | r1/2 | 7 | 256-QAM | r3/4 |
348
+ | 3 | 16-QAM | r3/4 | 8 | 1024-QAM | r2/3 |
349
+ | 4 | 64-QAM | r2/3 | 9 | 1024-QAM | r3/4 |
350
+
351
+ ### Comportamento
352
+
353
+ - O arquivo recebido é gravado na pasta do RX (mais a subpasta do `--dest`, se houver) e não
354
+ sobrescreve: `nome (1).ext`. O caminho recebido é saneado: drive, raiz, `.` e `..` são descartados e o
355
+ resultado sempre fica dentro da pasta do RX.
356
+ - Com compressão (padrão), o `--auto` do uni escolhe o MCS pelo tamanho comprimido, e a velocidade
357
+ mostrada é a efetiva (tamanho original ÷ tempo).
358
+ - O PC não suspende durante a transferência. O RX avisa quando a entrada satura (clip).
359
+ - Códigos de saída: 0 ok, 1 transferência falhou, 2 uso incorreto, 3 erro de device, 130 Ctrl+C.
360
+
361
+ ---
362
+
363
+ ## Limitações conhecidas (beta)
364
+
365
+ - Só Windows (WASAPI).
366
+ - Entradas de **microfone** (sobretudo em notebooks) costumam somar os canais, cortar acima de ~8 kHz e ter
367
+ ganho automático (AGC): funcionam, mas bem mais devagar (mono, banda estreita, MCS baixo). Prefira entrada
368
+ de linha e rode a calibração.
369
+ - A calibração com tamanhos grandes (`--calibrate-test 50k` ou mais) num sentido lento pode levar dezenas de
370
+ minutos.
371
+
372
+ ## Licença
373
+
374
+ MIT.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Makoto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.