From 50ee62911a1d5aa60d8072c0146f8f5232926ce1 Mon Sep 17 00:00:00 2001 From: liuyihui Date: Fri, 28 Apr 2023 16:20:46 +0800 Subject: [PATCH] feat: convert sound to image --- include/adc.h | 7 +- include/sstv.h | 2 +- include/uart.h | 6 ++ main.c | 31 +-------- src/adc.c | 10 ++- src/sstv.c | 176 ++++++++++--------------------------------------- 6 files changed, 57 insertions(+), 175 deletions(-) diff --git a/include/adc.h b/include/adc.h index ba31ee2..ef699d1 100644 --- a/include/adc.h +++ b/include/adc.h @@ -1,11 +1,12 @@ #pragma once -#include +#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); diff --git a/include/sstv.h b/include/sstv.h index 854b8fc..ab7996d 100644 --- a/include/sstv.h +++ b/include/sstv.h @@ -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 diff --git a/include/uart.h b/include/uart.h index 832d5fd..d82e301 100644 --- a/include/uart.h +++ b/include/uart.h @@ -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); +} diff --git a/main.c b/main.c index 3379d35..9fa4841 100644 --- a/main.c +++ b/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(); } } diff --git a/src/adc.c b/src/adc.c index 764ac50..54f8528 100644 --- a/src/adc.c +++ b/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; + } +} diff --git a/src/sstv.c b/src/sstv.c index 8b8c28b..25de35c 100644 --- a/src/sstv.c +++ b/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 #include #include -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; }