feat: convert sound to image
This commit is contained in:
parent
109c1b74b0
commit
50ee62911a
|
@ -1,11 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "derivative.h"
|
||||
|
||||
#define ADC_M 1024
|
||||
#define ADC_M 2048
|
||||
extern int16_t adc_buf[ADC_M];
|
||||
extern int16_t pADC;
|
||||
extern uint16_t pADC;
|
||||
extern uint8_t fADC;
|
||||
|
||||
void adc0_Init();
|
||||
int16_t adc0_TR_DATA();
|
||||
void adc0_read_buf(int16_t *data, uint16_t len);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#define FS 20000
|
||||
#define RE FS / FFT_N
|
||||
#define BUF_M 256
|
||||
#define BUF_M 1024
|
||||
|
||||
#define FREQ_BIT1 1100
|
||||
#define FREQ_SYNC 1200
|
||||
|
|
|
@ -84,3 +84,9 @@ static inline size_t uart_getline(UART_Type *UART, char *buf) {
|
|||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static inline void string_format(char *buf, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(buf, format, args);
|
||||
}
|
||||
|
|
31
main.c
31
main.c
|
@ -1,5 +1,6 @@
|
|||
#include "adc.h"
|
||||
#include "derivative.h"
|
||||
#include "sstv.h"
|
||||
#include "systick.h"
|
||||
#include "tftlcd.h"
|
||||
#include "uart.h"
|
||||
|
@ -16,36 +17,8 @@ int main(void) {
|
|||
uart_printf(UART_MSG, "System Clock: %lu\r\n", CORCLK);
|
||||
uart_printf(UART_MSG, "Bus Clock: %lu\r\n", BUSCLK);
|
||||
|
||||
LCD_ShowString(LCD_W / 3, 0, "Audio Sample", 16, 0, 1);
|
||||
LCD_DrawLine(0, 16, LCD_W - 1, 16);
|
||||
|
||||
uint16_t x0 = 16, y0 = 32;
|
||||
uint16_t x1 = LCD_W - 8, y1 = LCD_H - 16;
|
||||
uint16_t ym = (y0 + y1) / 2;
|
||||
LCD_DrawLine(x0, y0, x0, y1);
|
||||
LCD_DrawLine(x0, ym, x1, ym);
|
||||
LCD_ShowChar(0, y0, 'A', 16, 0);
|
||||
LCD_ShowChar(x1, ym, 'T', 16, 0);
|
||||
|
||||
LCD_SetColor(BACK_COLOR);
|
||||
|
||||
int16_t res;
|
||||
uint16_t pos[x1 - x0 - 1];
|
||||
uint16_t x = x0 + 1, y;
|
||||
uint32_t timer = 0;
|
||||
fADC = 1;
|
||||
|
||||
for (;;) {
|
||||
if (timer_expired_50us(&timer, 1)) {
|
||||
LCD_DrawPoint(x, pos[x - x0 - 1], BACK_COLOR);
|
||||
|
||||
res = adc_buf[pADC];
|
||||
y = ym + res * (y1 - ym) / 2048;
|
||||
LCD_DrawPoint(x, y, RED);
|
||||
LCD_DrawPoint(x, ym, BLACK);
|
||||
|
||||
pos[x - x0 - 1] = y;
|
||||
x = x + 1 < x1 ? x + 1 : x0 + 1;
|
||||
}
|
||||
decode_sstv();
|
||||
}
|
||||
}
|
||||
|
|
10
src/adc.c
10
src/adc.c
|
@ -2,7 +2,7 @@
|
|||
#include "derivative.h"
|
||||
|
||||
int16_t adc_buf[ADC_M];
|
||||
int16_t pADC = 0;
|
||||
uint16_t pADC = 0;
|
||||
uint8_t fADC = 0;
|
||||
|
||||
void adc0_Init() {
|
||||
|
@ -27,3 +27,11 @@ int16_t adc0_TR_DATA() {
|
|||
ADC0->SC1[0] &= ~ADC_SC1_COCO_MASK;
|
||||
return ADC_Result;
|
||||
}
|
||||
|
||||
static uint16_t lastPos = 0;
|
||||
void adc0_read_buf(int16_t *data, uint16_t len) {
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
data[i] = adc_buf[lastPos];
|
||||
lastPos = (lastPos + 1) % ADC_M;
|
||||
}
|
||||
}
|
||||
|
|
176
src/sstv.c
176
src/sstv.c
|
@ -1,31 +1,20 @@
|
|||
#include "adc.h"
|
||||
#include "derivative.h"
|
||||
#include "fft/fft.h"
|
||||
#include "fft/table.h"
|
||||
#include "math.h"
|
||||
#include "sstv.h"
|
||||
#include "tftlcd.h"
|
||||
#include "uart.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static q15_t data[N];
|
||||
static q15_t buffer[MN];
|
||||
static q15_t* pData = &data[0];
|
||||
static uint8_t colorBuf[960];
|
||||
static q15_t data[FFT_N];
|
||||
static q15_t buffer[BUF_M];
|
||||
static q15_t *pData = &data[0];
|
||||
|
||||
static const float32_t color_re = (float32_t)(FREQ_RANGE) / (COLOR_SCALE - 1);
|
||||
#define fre2lum(fre) (uint8_t)((fre - FREQ_BLACK) / color_re)
|
||||
|
||||
static q15_t img[1843202];
|
||||
static q15_t* pImg = &img[0];
|
||||
void init() {
|
||||
FILE* fp;
|
||||
fp = fopen("temp/data.txt", "r");
|
||||
for (int i = 0; i < 1843202; i++) fscanf(fp, "%" SCNd16, &img[i]);
|
||||
}
|
||||
|
||||
static void read_data(q15_t* pSrc, uint16_t len) {
|
||||
for (int i = 0; i < len; i++) pSrc[i] = *pImg++;
|
||||
}
|
||||
|
||||
static uint16_t find_peak(uint16_t L, uint16_t R) {
|
||||
q15_t peak = 0;
|
||||
uint16_t index = 0;
|
||||
|
@ -37,24 +26,16 @@ static uint16_t find_peak(uint16_t L, uint16_t R) {
|
|||
return index;
|
||||
}
|
||||
|
||||
static void hanning(uint16_t len) {
|
||||
for (uint16_t i = len; i < N; i++) data[i] = 0;
|
||||
if (len == 160)
|
||||
for (uint16_t i = 0; i < len; i++) data[i] = (q15_t)(((q31_t)data[i] * hanning_160[i]) >> 15);
|
||||
else
|
||||
for (uint16_t i = 0; i < len; i++) data[i] = (q15_t)(((q31_t)data[i] * hanning_17[i]) >> 15);
|
||||
}
|
||||
|
||||
static uint32_t cSample = 0;
|
||||
static uint16_t preLen = 0;
|
||||
static void read_samples(uint32_t start, uint16_t len) {
|
||||
int16_t offset = start - cSample;
|
||||
if (offset >= 0) {
|
||||
read_data(pData, offset);
|
||||
read_data(pData, len);
|
||||
adc0_read_buf(pData, offset);
|
||||
adc0_read_buf(pData, len);
|
||||
} else {
|
||||
for (uint16_t i = 0; i < -offset; i++) data[i] = buffer[preLen + offset + i];
|
||||
read_data(pData - offset, len + offset);
|
||||
adc0_read_buf(pData - offset, len + offset);
|
||||
}
|
||||
for (uint16_t i = 0; i < len; i++) buffer[i] = data[i];
|
||||
|
||||
|
@ -62,146 +43,59 @@ static void read_samples(uint32_t start, uint16_t len) {
|
|||
preLen = len;
|
||||
}
|
||||
|
||||
static void read_header() {
|
||||
uint8_t cLeader1, cLeader2, cBreak, cVis;
|
||||
uint16_t len = (uint16_t)(FS * 0.01);
|
||||
uint16_t idx, fre;
|
||||
cLeader1 = cLeader2 = cBreak = cVis = 0;
|
||||
|
||||
for (;;) {
|
||||
read_data(pData, len);
|
||||
hanning(len);
|
||||
|
||||
FFT(pData);
|
||||
idx = find_peak(64, 128); // 1000 - 2000 Hz
|
||||
fre = FFT_BIN(idx, RE);
|
||||
|
||||
if (abs(fre - FREQ_START) < 80) {
|
||||
if (cBreak) cLeader2++;
|
||||
else cLeader1++;
|
||||
} else if (abs(fre - FREQ_SYNC) < 80) {
|
||||
if (cLeader2) cVis++;
|
||||
else cBreak++;
|
||||
} else cLeader1 = cLeader2 = cBreak = cVis = 0;
|
||||
|
||||
if (cLeader1 > 5 // Leader tone
|
||||
&& cBreak < 3 // Break
|
||||
&& abs(cLeader2 - 30) < 5 // Leader tone
|
||||
&& (cVis == 3 || cVis == 4) // VIS start bit
|
||||
) {
|
||||
printf("Header: %d %d %d %d\r\n", cLeader1, cBreak, cLeader2, cVis);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t read_mode() {
|
||||
uint16_t len = (uint16_t)(FS * 0.01);
|
||||
uint16_t idx, fre;
|
||||
uint8_t cBit1 = 0, cParity = 0, mode = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 24; i++) {
|
||||
read_data(pData, len);
|
||||
hanning(len);
|
||||
|
||||
FFT(pData);
|
||||
idx = find_peak(64, 128); // 1000 - 2000 Hz
|
||||
fre = FFT_BIN(idx, RE);
|
||||
|
||||
if (abs(fre - FREQ_BIT1) < 80) cBit1++;
|
||||
else if (abs(fre - FREQ_BIT0) > 80) {
|
||||
printf("Error VIS BIT: %d\r\n", fre);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i % 3 == 2) {
|
||||
mode = mode >> 1;
|
||||
if (cBit1 > 1) {
|
||||
mode |= BIT(7);
|
||||
if (i != 23) cParity++;
|
||||
}
|
||||
cBit1 = 0;
|
||||
}
|
||||
}
|
||||
cParity = (mode & BIT(7) ? 1 : 0) == (cParity % 2);
|
||||
mode = mode & (~BIT(7));
|
||||
|
||||
if (!cParity) {
|
||||
printf("Error Parity Check: %d\r\n", mode);
|
||||
return 0;
|
||||
}
|
||||
read_data(pData, len * 3);
|
||||
return mode;
|
||||
}
|
||||
|
||||
static void decode_martin1() {
|
||||
FILE* fp;
|
||||
fp = fopen("temp/decode.txt", "w");
|
||||
uart_printf(UART_MSG, "Mode: 44 - Martin 1\r\n");
|
||||
|
||||
printf("Mode: 44 - Martin 1\r\n");
|
||||
|
||||
const uint16_t WIDTH = 320;
|
||||
const uint16_t HEIGHT = 256;
|
||||
const uint16_t WIDTH = 240;
|
||||
const uint16_t HEIGHT = 240;
|
||||
|
||||
const float32_t SCAN_TIME = 0.146432;
|
||||
const float32_t SYNC_PULSE = 0.004862;
|
||||
const float32_t SYNC_PORCH = 0.000572;
|
||||
|
||||
const float32_t CHAN_TIME = SYNC_PORCH + SCAN_TIME;
|
||||
const float32_t LINE_TIME = SYNC_PULSE + SYNC_PORCH + CHAN_TIME * 3;
|
||||
const float32_t LINE_TIME = SYNC_PULSE + SYNC_PORCH + CHAN_TIME;
|
||||
const float32_t PIXEL_TIME = SCAN_TIME / WIDTH;
|
||||
const float32_t CHAN_OFFSETS[] = {
|
||||
SYNC_PULSE + SYNC_PORCH,
|
||||
SYNC_PULSE + SYNC_PORCH + CHAN_TIME,
|
||||
SYNC_PULSE + SYNC_PORCH + CHAN_TIME * 2,
|
||||
};
|
||||
const float32_t CHAN_OFFSETS = SYNC_PULSE + SYNC_PORCH;
|
||||
|
||||
const float32_t FWHM = 2.34;
|
||||
const float32_t HALF_SAMPLE_TIME = (PIXEL_TIME * FWHM) / 2;
|
||||
const uint8_t len = (uint8_t)(HALF_SAMPLE_TIME * 2 * FS);
|
||||
|
||||
uint16_t idx, fre;
|
||||
uint16_t idx, fre, rgb;
|
||||
uint32_t start, cSampleI = 0;
|
||||
float32_t cSampleF = 0;
|
||||
|
||||
printf("Start Decoding\r\n");
|
||||
for (uint16_t h = 0; h < HEIGHT; h++) {
|
||||
printf("Line: %d / 255\r\n", h);
|
||||
char buf[15];
|
||||
|
||||
uart_printf(UART_MSG, "Start Decoding\r\n");
|
||||
for (uint16_t h = 0; h < HEIGHT; h = (h + 1) % HEIGHT) {
|
||||
string_format(buf, "Line: %3d/240", h);
|
||||
LCD_ShowString(LCD_W - 8, 0, &buf[0], 16, 1, 0);
|
||||
|
||||
if (h) {
|
||||
cSampleF += LINE_TIME * FS;
|
||||
cSampleI = (uint32_t)round(cSampleF);
|
||||
}
|
||||
|
||||
for (uint8_t c = 0; c < 3; c++) {
|
||||
for (uint16_t w = 0; w < WIDTH; w++) {
|
||||
start = (uint32_t)round(cSampleI + (CHAN_OFFSETS[c] + w * PIXEL_TIME - HALF_SAMPLE_TIME) * FS);
|
||||
read_samples(start, len);
|
||||
hanning(len);
|
||||
// RGB 565: 5 bit R, 6 bit G, 5 bit B
|
||||
for (uint16_t w = 0; w < WIDTH; w++) {
|
||||
start = (uint32_t)round(cSampleI + (CHAN_OFFSETS + w * PIXEL_TIME - HALF_SAMPLE_TIME) * FS);
|
||||
read_samples(start, len);
|
||||
FFT(pData, len);
|
||||
idx = find_peak(119, 457); // 1875 - 7125 Hz
|
||||
fre = FFT_BIN(idx, RE);
|
||||
rgb = fre2lum(fre);
|
||||
|
||||
FFT(pData);
|
||||
idx = find_peak(119, 457); // 1875 - 7125 Hz
|
||||
fre = FFT_BIN(idx, RE);
|
||||
colorBuf[w + WIDTH * c] = fre2lum(fre);
|
||||
}
|
||||
rgb = (uint16_t)(((rgb / 2) & 0x1F) << 11) // R
|
||||
| (uint16_t)((rgb & 0x3F) << 5) // G
|
||||
| (uint16_t)((rgb / 2) & 0x1F); // B
|
||||
LCD_DrawPoint(h, w, rgb);
|
||||
}
|
||||
for (uint16_t w = 0; w < WIDTH; w++)
|
||||
fprintf(fp, "%d %d %d \r\n", colorBuf[w + WIDTH * 2], colorBuf[w], colorBuf[w + WIDTH]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t decode_sstv() {
|
||||
uint8_t mode;
|
||||
|
||||
init();
|
||||
read_header();
|
||||
mode = read_mode();
|
||||
|
||||
if (mode == 44) decode_martin1();
|
||||
else {
|
||||
printf("Mode Error: %d\r\n", mode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
decode_martin1();
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue