see changes in readme.md (09.04.26)

This commit is contained in:
2026-04-09 14:30:20 +02:00
parent f050cad853
commit aa67aa0e07
12 changed files with 96267 additions and 43 deletions

7
.gitignore vendored
View File

@@ -70,3 +70,10 @@ e36
./build
.vscode
## clangd
compile_commands.json
## APTEST
AP_TEST

View File

@@ -0,0 +1,4 @@
Copyright 2026 , rattatwinko
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,7 +1,7 @@
# Makefile
CC = gcc
CFLAGS = -Wall -O2 -Iinclude -Ithird_party
LDFLAGS = -lm
CFLAGS = -Wall -O2 -Iinclude -Ithird_party -std=c11
LDFLAGS = -lm -pthread
SRCDIR = src
BUILDDIR = build
TARGET = e36
@@ -15,14 +15,21 @@ SRCS = \
$(SRCDIR)/encoder/modes/scottie.c \
$(SRCDIR)/sound/wav.c
OBJS = $(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%.o,$(SRCS))
# For APTEST
SRCS_TEST = \
$(SRCDIR)/sound/wav.c \
$(SRCDIR)/decoder/provider/audio_in_provider.c \
$(SRCDIR)/decoder/test/audio_in_provider_test.c
.PHONY: all clean dirs
OBJS = $(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%.o,$(SRCS))
OBJS_TEST = $(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%.o,$(SRCS_TEST))
.PHONY: all clean dirs AP_TEST test
all: dirs $(TARGET)
dirs:
mkdir -p $(BUILDDIR)/encoder/modes $(BUILDDIR)/sound
mkdir -p $(BUILDDIR)/encoder/modes $(BUILDDIR)/sound $(BUILDDIR)/decoder/provider $(BUILDDIR)/decoder/test
$(TARGET): $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)
@@ -31,5 +38,9 @@ $(BUILDDIR)/%.o: $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf $(BUILDDIR) $(TARGET)
rm -rf $(BUILDDIR) $(TARGET) AP_TEST mic_capture.wav
# build audio_in_provider_test
AP_TEST: dirs $(OBJS_TEST)
$(CC) $(OBJS_TEST) -o AP_TEST $(LDFLAGS)

View File

@@ -0,0 +1,33 @@
#ifndef AUDIO_IN_PROVIDER_H
#define AUDIO_IN_PROVIDER_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct audio_in_provider_t audio_in_provider_t;
/**
* device_name: NULL -> default device
* sample_rate: 0 -> default
* channels: 0 -> default (1)
* frames_per_buffer: 0 -> default
*/
audio_in_provider_t* audio_in_open(const char *device_name, uint32_t sample_rate, uint32_t channels, uint32_t frames_per_buffer);
size_t audio_in_read(audio_in_provider_t *p, float *out_frames, size_t max_frames);
size_t audio_in_read_blocking(audio_in_provider_t *p, float *out_frames, size_t max_frames, uint32_t timeout_ms);
void audio_in_close(audio_in_provider_t *p);
#ifdef __cplusplus
}
#endif
#endif // !AUDIO_IN_PROVIDER_H

View File

@@ -1,6 +1,6 @@
# sstv e36 encoder
This is a SSTV "encoder", currently it is in work, but it has some modes already:
This is a SSTV "encoder", currently it is in work, but it has some modes already: (update of 09.04.26 - We now have a component with miniaudio which is able to stream in live microphone data)
Future plans for a decoder have been made. I do not plan to do any decoding
soon. Wayy to much of a workload, high cortisol!
@@ -19,9 +19,14 @@ soon. Wayy to much of a workload, high cortisol!
Written in _pure_ **C** with some _Makefiles_ to pull it together
## License:
## Changes:
This project is distributed under the MiT License!
- 09.04.26
- Added Audio stream provider ([.c](/src/decoder/provider/audio_in_provider.c), [.h](/include/decoder/provider/audio_in_provider.h), [test](/src/decoder/test/audio_in_provider_test.c))
- Added Licenses to [third party](/third_party/license/)
- Added a few things to the [gitignore](.gitignore)
- Added new [AP_TEST](/include/decoder/provider/audio_in_provider.h) to [Makefile](Makefile)
- Added [miniaudio.h](https://miniaud.io/)
### For developing or adding to the source code:
@@ -69,8 +74,6 @@ In you C File:
#include "decoder/modes/martin.h" // for example
```
If you add a new module, you may add to the Makefile. as a -I CFLAG!
#### C Files:
For a real implementation this stub below would make 0 sense,
@@ -104,33 +107,13 @@ References:
If you have the balls to define a new Mode, then refer to the Dayton Papers!
And when your done make this [Table](#support-table) complete!
### Our License:
#### MIT :
```
Copyright 2026 , rattatwinko
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
```
#### Defining Stuff in the Makefile:
#### For stb_image.h:
```
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
If you were to add new Modules then add them to the makefile.
As a Example are our CFLAGS. which define which include directories to use! Currently it is just include and third_party (for stbi)
### Licensing:
All Third-Party Licenses are available under *[./third_party/license/](./third_party/license/)*
Our Licenses is a MIT License is available under [*./LICENSE*](./LICENSE)

View File

@@ -0,0 +1,201 @@
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <wchar.h>
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
#include "decoder/provider/audio_in_provider.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>
struct audio_in_provider_t {
ma_context ctx;
ma_device device;
float *ring_buf; // interleaved
size_t ring_capacity; // frames
atomic_size_t write_pos; // frames
atomic_size_t read_pos; // frames
uint32_t channels;
mtx_t mutex;
cnd_t cond;
atomic_int running;
};
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
(void)pOutput;
audio_in_provider_t *p = (audio_in_provider_t*)pDevice->pUserData;
if (!p || !pInput) return;
const float *in = (const float*)pInput;
size_t write = atomic_load(&p->write_pos);
size_t capacity = p->ring_capacity;
size_t channels = p->channels;
size_t to_write = frameCount;
size_t first = capacity - write;
if (first >= to_write) {
memcpy(p->ring_buf + write * channels,
in,
to_write * channels * sizeof(float));
write += to_write;
if (write == capacity) write = 0;
} else {
memcpy(p->ring_buf + write * channels,
in,
first * channels * sizeof(float));
memcpy(p->ring_buf,
in + first * channels,
(to_write - first) * channels * sizeof(float));
write = to_write - first;
}
atomic_store(&p->write_pos, write);
mtx_lock(&p->mutex);
cnd_signal(&p->cond);
mtx_unlock(&p->mutex);
}
audio_in_provider_t* audio_in_open(const char *device_name, uint32_t sample_rate,
uint32_t channels, uint32_t frames_per_buffer) {
audio_in_provider_t *p = (audio_in_provider_t*)malloc(sizeof(audio_in_provider_t));
if (!p) return NULL;
if (ma_context_init(NULL, 0, NULL, &p->ctx) != MA_SUCCESS) {
free(p);
return NULL;
}
p->channels = channels ? channels : 1;
ma_device_config config = ma_device_config_init(ma_device_type_capture);
config.capture.format = ma_format_f32;
config.capture.channels = p->channels;
config.sampleRate = sample_rate ? sample_rate : 44100;
if (frames_per_buffer) config.periodSizeInFrames = frames_per_buffer;
config.dataCallback = data_callback;
config.pUserData = p;
if (device_name) {
ma_device_info *pPlaybackInfos, *pCaptureInfos;
ma_uint32 playbackCount, captureCount;
if (ma_context_get_devices(&p->ctx,
&pPlaybackInfos, &playbackCount,
&pCaptureInfos, &captureCount) == MA_SUCCESS) {
for (ma_uint32 i = 0; i < captureCount; ++i) {
if (strcmp(pCaptureInfos[i].name, device_name) == 0) {
config.capture.pDeviceID = &pCaptureInfos[i].id;
break;
}
}
// no match pId stays NULL, miniaudio will default to system device
}
}
if (ma_device_init(&p->ctx, &config, &p->device) != MA_SUCCESS) {
ma_context_uninit(&p->ctx);
free(p);
return NULL;
}
uint32_t sr = config.sampleRate;
p->ring_capacity = sr * 2;
p->ring_buf = (float*)malloc(p->ring_capacity * p->channels * sizeof(float));
if (!p->ring_buf) {
ma_device_uninit(&p->device);
ma_context_uninit(&p->ctx);
free(p);
return NULL;
}
atomic_store(&p->write_pos, 0);
atomic_store(&p->read_pos, 0);
p->running = 1;
mtx_init(&p->mutex, mtx_plain);
cnd_init(&p->cond);
if (ma_device_start(&p->device) != MA_SUCCESS) {
cnd_destroy(&p->cond);
mtx_destroy(&p->mutex);
free(p->ring_buf);
ma_device_uninit(&p->device);
ma_context_uninit(&p->ctx);
free(p);
return NULL;
}
return p;
}
size_t audio_in_read(audio_in_provider_t *p, float *out_frames, size_t max_frames) {
if (!p || !out_frames || max_frames == 0) return 0;
size_t write = atomic_load(&p->write_pos);
size_t read = atomic_load(&p->read_pos);
size_t available = (write >= read) ? (write - read) : (p->ring_capacity - (read - write));
size_t to_read = max_frames < available ? max_frames : available;
if (to_read == 0) return 0;
size_t first = p->ring_capacity - read;
if (first >= to_read) {
memcpy(out_frames,
p->ring_buf + read * p->channels,
to_read * p->channels * sizeof(float));
read += to_read;
if (read == p->ring_capacity) read = 0;
} else {
memcpy(out_frames,
p->ring_buf + read * p->channels,
first * p->channels * sizeof(float));
memcpy(out_frames + first * p->channels,
p->ring_buf,
(to_read - first) * p->channels * sizeof(float));
read = to_read - first;
}
atomic_store(&p->read_pos, read);
return to_read;
}
size_t audio_in_read_blocking(audio_in_provider_t *p, float *out_frames, size_t max_frames, uint32_t timeout_ms) {
if (!p || !out_frames || max_frames == 0) return 0;
size_t n = audio_in_read(p, out_frames, max_frames);
if (n > 0) return n;
mtx_lock(&p->mutex);
if (timeout_ms == 0) {
while ((n = audio_in_read(p, out_frames, max_frames)) == 0 && p->running)
cnd_wait(&p->cond, &p->mutex);
} else {
struct timespec ts;
timespec_get(&ts, TIME_UTC);
ts.tv_sec += timeout_ms / 1000;
ts.tv_nsec += (timeout_ms % 1000) * 1000000;
if (ts.tv_nsec >= 1000000000) { ts.tv_sec += 1; ts.tv_nsec -= 1000000000; }
while ((n = audio_in_read(p, out_frames, max_frames)) == 0 && p->running) {
if (cnd_timedwait(&p->cond, &p->mutex, &ts) != thrd_success)
break;
}
}
mtx_unlock(&p->mutex);
return n;
}
void audio_in_close(audio_in_provider_t *p) {
if (!p) return;
p->running = 0;
mtx_lock(&p->mutex);
cnd_broadcast(&p->cond);
mtx_unlock(&p->mutex);
ma_device_stop(&p->device);
ma_device_uninit(&p->device);
ma_context_uninit(&p->ctx);
cnd_destroy(&p->cond);
mtx_destroy(&p->mutex);
free(p->ring_buf);
free(p);
}

View File

@@ -0,0 +1,56 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "decoder/provider/audio_in_provider.h"
#include "sound/wav.h"
static int16_t float_to_int16(float s) {
if (s > 1.0f) s = 1.0f;
if (s < -1.0f) s = -1.0f;
return (int16_t)(s * 32767.0f);
}
int main(void) {
const char *outname = "mic_capture.wav";
const uint32_t sample_rate = 44100;
const size_t total_frames = sample_rate * 2; /* 2 seconds */
const size_t chunk = 512;
wav_t wav;
if (!wave_open(&wav, outname, sample_rate)) {
fprintf(stderr, "wave_open failed\n");
return 1;
}
audio_in_provider_t *p = audio_in_open(NULL, sample_rate, 1, chunk);
if (!p) {
fprintf(stderr, "audio_in_open failed\n");
wave_close(&wav);
return 2;
}
float *buf = (float*)malloc(chunk * sizeof(float));
if (!buf) {
audio_in_close(p);
wave_close(&wav);
return 3;
}
size_t captured = 0;
while (captured < total_frames) {
size_t n = audio_in_read_blocking(p, buf, chunk, 2000);
if (n == 0) {
fprintf(stderr, "timeout or no data\n");
break;
}
for (size_t i = 0; i < n; i++)
wave_write_sample(&wav, float_to_int16(buf[i]));
captured += n;
}
free(buf);
audio_in_close(p);
wave_close(&wav);
printf("Captured %zu frames to %s\n", captured, outname);
return 0;
}

View File

@@ -1,6 +1,6 @@
#define STB_IMAGE_IMPLEMENTATION
#include "../../third_party/stb_image.h"
#include "../../include/encoder/image.h"
#include "stb_image.h"
#include "encoder/image.h"
#include <stdlib.h>
int image_load(image_t *img, const char *filename) {

View File

@@ -3,6 +3,7 @@
#include <stdint.h>
// From Dayton Paper Appendix B - ITU BT.601
// Or refer to doc/Dayton Paper.pdf page 5
// http://www.barberdsp.com/downloads/Dayton%20Paper.pdf
static void rgb_to_ycbcr(uint8_t r, uint8_t g, uint8_t b,
double *Y, double *RY, double *BY) {

47
third_party/license/miniaudio vendored Normal file
View File

@@ -0,0 +1,47 @@
This software is available as a choice of the following licenses. Choose
whichever you prefer.
===============================================================================
ALTERNATIVE 1 - Public Domain (www.unlicense.org)
===============================================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
===============================================================================
ALTERNATIVE 2 - MIT No Attribution
===============================================================================
Copyright 2025 David Reid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

17
third_party/license/stb_image vendored Normal file
View File

@@ -0,0 +1,17 @@
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

95864
third_party/miniaudio.h vendored Normal file

File diff suppressed because it is too large Load Diff