scottie modes added ; with dayton paper copy
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -54,6 +54,10 @@ dkms.conf
|
|||||||
# debug information files
|
# debug information files
|
||||||
*.dwo
|
*.dwo
|
||||||
|
|
||||||
|
## our application (binary)
|
||||||
|
|
||||||
|
sstv
|
||||||
|
e36
|
||||||
|
|
||||||
|
|
||||||
# special
|
# special
|
||||||
|
|||||||
BIN
Dayton Paper.pdf
Normal file
BIN
Dayton Paper.pdf
Normal file
Binary file not shown.
4
Makefile
4
Makefile
@@ -2,8 +2,8 @@ CC = gcc
|
|||||||
CFLAGS = -Wall -O2
|
CFLAGS = -Wall -O2
|
||||||
LDFLAGS = -lm
|
LDFLAGS = -lm
|
||||||
|
|
||||||
TARGET = sstv
|
TARGET = e36
|
||||||
SRCS = main.c sstv.c robot36.c image.c wav.c martin.c
|
SRCS = main.c sstv.c robot36.c image.c wav.c martin.c scottie.c
|
||||||
OBJS = $(SRCS:.c=.o)
|
OBJS = $(SRCS:.c=.o)
|
||||||
|
|
||||||
$(TARGET): $(OBJS)
|
$(TARGET): $(OBJS)
|
||||||
|
|||||||
2
image.c
2
image.c
@@ -36,6 +36,6 @@ void image_free(image_t *img) {
|
|||||||
|
|
||||||
void image_free_raw(image_t *img) {
|
void image_free_raw(image_t *img) {
|
||||||
if (img->data)
|
if (img->data)
|
||||||
free(img->data);
|
free(img->data); // if you do this call only once, cause of double frees
|
||||||
img->data = NULL;
|
img->data = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
53
main.c
53
main.c
@@ -1,44 +1,69 @@
|
|||||||
#include "sstv.h"
|
#include "sstv.h"
|
||||||
#include "martin.h"
|
#include "martin.h"
|
||||||
|
#include "scottie.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
static void usage(const char *prog) {
|
static void usage(const char *prog) {
|
||||||
printf("Usage: %s <mode> input_image output.wav\n", prog);
|
fprintf(stderr,
|
||||||
printf("Modes:\n");
|
"Usage: %s <mode> <input_image> <output_wav>\n"
|
||||||
printf(" robot36 - Robot 36 (default)\n");
|
"\n"
|
||||||
printf(" martin1 - Martin M1\n");
|
"Modes:\n"
|
||||||
printf(" martin2 - Martin M2\n");
|
" robot36 Robot 36 (320x240)\n"
|
||||||
|
" martin1 Martin M1 (320x256)\n"
|
||||||
|
" martin2 Martin M2 (320x256)\n"
|
||||||
|
" scottie1 Scottie S1 (320x256)\n"
|
||||||
|
" scottie2 Scottie S2 (320x256)\n"
|
||||||
|
" scottiedx Scottie DX (320x256)\n"
|
||||||
|
"\n"
|
||||||
|
"Example:\n"
|
||||||
|
" %s mode photo.jpg output.wav\n",
|
||||||
|
prog, prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc < 4) {
|
if (argc != 4) {
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *mode_str = argv[1];
|
const char *mode = argv[1];
|
||||||
const char *input_img = argv[2];
|
const char *input_img = argv[2];
|
||||||
const char *output_wav = argv[3];
|
const char *output_wav = argv[3];
|
||||||
|
|
||||||
|
clock_t start = clock();
|
||||||
|
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
||||||
if (strcmp(mode_str, "robot36") == 0) {
|
if (strcmp(mode, "robot36") == 0) {
|
||||||
ok = sstv_encode_robot36(input_img, output_wav);
|
ok = sstv_encode_robot36(input_img, output_wav);
|
||||||
} else if (strcmp(mode_str, "martin1") == 0) {
|
} else if (strcmp(mode, "martin1") == 0) {
|
||||||
ok = sstv_encode_martin(input_img, output_wav, &MARTIN_M1);
|
ok = sstv_encode_martin(input_img, output_wav, &MARTIN_M1);
|
||||||
} else if (strcmp(mode_str, "martin2") == 0) {
|
} else if (strcmp(mode, "martin2") == 0) {
|
||||||
ok = sstv_encode_martin(input_img, output_wav, &MARTIN_M2);
|
ok = sstv_encode_martin(input_img, output_wav, &MARTIN_M2);
|
||||||
|
} else if (strcmp(mode, "scottie1") == 0) {
|
||||||
|
ok = sstv_encode_scottie(input_img, output_wav, &SCOTTIE_S1);
|
||||||
|
} else if (strcmp(mode, "scottie2") == 0) {
|
||||||
|
ok = sstv_encode_scottie(input_img, output_wav, &SCOTTIE_S2);
|
||||||
|
} else if (strcmp(mode, "scottiedx") == 0) {
|
||||||
|
ok = sstv_encode_scottie(input_img, output_wav, &SCOTTIE_DX);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unknown mode: %s\n", mode_str);
|
fprintf(stderr, "unknown mode: %s\n\n", mode);
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr, "Encoding failed.\n");
|
fprintf(stderr, "make sure the file exsists");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Done.\n");
|
clock_t end = clock();
|
||||||
|
|
||||||
|
double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
|
||||||
|
printf("encoded '%s' -> '%s' using '%s'\n", input_img, output_wav, mode);
|
||||||
|
printf("took %.3f seconds\n", elapsed);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
2
martin.h
2
martin.h
@@ -5,7 +5,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t vis_code;
|
uint8_t vis_code; // in hexadecimal not normal decimal (ex 0x08)
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
double sync_ms;
|
double sync_ms;
|
||||||
|
|||||||
72
readme.md
72
readme.md
@@ -1,12 +1,79 @@
|
|||||||
# sstv e36 encoder
|
# sstv e36 encoder
|
||||||
|
|
||||||
This is a simple C SSTV Robot36 encoder!
|
This is a SSTV encoder, currently it is in work, but it has some modes already:
|
||||||
Written in pure C
|
|
||||||
|
|Support?|Mode |
|
||||||
|
|--------|------------|
|
||||||
|
|[x] |Martin 1 |
|
||||||
|
|[x] |Martin 2 |
|
||||||
|
|[x] |Robot 36 |
|
||||||
|
|[x] |Scottie 1 |
|
||||||
|
|[x] |Scottie 2 |
|
||||||
|
|[x] |ScottieD(S)X|
|
||||||
|
|
||||||
|
|
||||||
|
Written in _pure_ **C**
|
||||||
|
|
||||||
## License:
|
## License:
|
||||||
|
|
||||||
This project is distributed under the MiT License!
|
This project is distributed under the MiT License!
|
||||||
|
|
||||||
|
### For developing or adding to the source code:
|
||||||
|
|
||||||
|
_**This is just standard C17 Standard**_
|
||||||
|
|
||||||
|
Compilation is done via the gcc compiler, we do NOT allow MSVC here.
|
||||||
|
If you are on Windows then i suggest to use the WSL.
|
||||||
|
|
||||||
|
Be sure to follow this style of code, it is not that complex,
|
||||||
|
and some parts you can even tell Vim or Emacs or whatever you use to automate it,
|
||||||
|
like the header definitions (default i think on vs and some others).
|
||||||
|
|
||||||
|
#### Headers:
|
||||||
|
|
||||||
|
Try to follow this general pattern.
|
||||||
|
In of itself it is relativley easy to maintain this structure.
|
||||||
|
And it is also relativley easy to write in this style!
|
||||||
|
|
||||||
|
_**This is just standard C17 Standard**_
|
||||||
|
```h
|
||||||
|
#ifndef HEADER_H
|
||||||
|
#define HEADER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t type;
|
||||||
|
} mystruct_t;
|
||||||
|
|
||||||
|
int method_to_use(mystruct_t type);
|
||||||
|
|
||||||
|
#endif // !HEADER_H
|
||||||
|
```
|
||||||
|
|
||||||
|
#### C Files:
|
||||||
|
|
||||||
|
For a real implementation this stub below would make 0 sense,
|
||||||
|
but this is the general style you should follow, it includes CAPITAL definitions,
|
||||||
|
local imports in "" and at the top, others below.
|
||||||
|
|
||||||
|
Try to comment your code if it does not make sense.
|
||||||
|
If you encounter something like `Q_rsqrt` (The Quake inverse square root), then you are
|
||||||
|
permitted to comment some swear words.
|
||||||
|
|
||||||
|
Great example of commenting : "robot36.c"
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
#define PI 3
|
||||||
|
#define SOME_DEF 67
|
||||||
|
|
||||||
|
int method_to_use(mystruct_t type) {
|
||||||
|
return 67 * type;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Our License:
|
### Our License:
|
||||||
#### MIT :
|
#### MIT :
|
||||||
```
|
```
|
||||||
@@ -36,3 +103,4 @@ 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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
90
scottie.c
Normal file
90
scottie.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#include "scottie.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "sstv.h"
|
||||||
|
#include "wav.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
const scottie_mode_t SCOTTIE_S1 = {
|
||||||
|
.vis_code = 0x3C, // 60d
|
||||||
|
.width = 320,
|
||||||
|
.height = 256,
|
||||||
|
.separator_ms = 1.5,
|
||||||
|
.sync_ms = 9.0,
|
||||||
|
.sync_porch_ms = 1.5,
|
||||||
|
.scan_ms = 138.240,
|
||||||
|
};
|
||||||
|
|
||||||
|
const scottie_mode_t SCOTTIE_S2 = {
|
||||||
|
.vis_code = 0x38, // 56d
|
||||||
|
.width = 320,
|
||||||
|
.height = 256,
|
||||||
|
.separator_ms = 1.5,
|
||||||
|
.sync_ms = 9.0,
|
||||||
|
.sync_porch_ms = 1.5,
|
||||||
|
.scan_ms = 88.064,
|
||||||
|
};
|
||||||
|
|
||||||
|
const scottie_mode_t SCOTTIE_DX = {
|
||||||
|
.vis_code = 0x4C, // 76d
|
||||||
|
.width = 320,
|
||||||
|
.height = 256,
|
||||||
|
.separator_ms = 1.5,
|
||||||
|
.sync_ms = 9.0,
|
||||||
|
.sync_porch_ms = 1.5,
|
||||||
|
.scan_ms = 345.600,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void scan_line_channel(wav_t *wav, uint8_t *line, int width, int channel, double scan_ms) {
|
||||||
|
double px_ms = scan_ms / width;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
uint8_t val = line[x * 3 + channel];
|
||||||
|
double freq = 1500.0 + val * 3.1372549;
|
||||||
|
sstv_tone(wav, freq, px_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scottie_encode_image(wav_t *wav, uint8_t *rgb, const scottie_mode_t *mode) {
|
||||||
|
for (int y = 0; y < mode->height; y++) {
|
||||||
|
uint8_t *line = &rgb[y * mode->width * 3];
|
||||||
|
|
||||||
|
if (y == 0) {
|
||||||
|
sstv_tone(wav, 1200.0, mode->sync_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
sstv_tone(wav, 1500.0, mode->separator_ms);
|
||||||
|
scan_line_channel(wav, line, mode->width, 1, mode->scan_ms);
|
||||||
|
sstv_tone(wav, 1500.0, mode->separator_ms);
|
||||||
|
scan_line_channel(wav, line, mode->width, 2, mode->scan_ms);
|
||||||
|
sstv_tone(wav, 1200.0, mode->sync_ms);
|
||||||
|
sstv_tone(wav, 1500.0, mode->sync_porch_ms);
|
||||||
|
scan_line_channel(wav, line, mode->width, 0, mode->scan_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sstv_encode_scottie(const char *input_image, const char *output_wav, const scottie_mode_t *mode) {
|
||||||
|
image_t img, resized;
|
||||||
|
wav_t wav;
|
||||||
|
|
||||||
|
if (!image_load(&img, input_image))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!image_resize(&img, &resized, mode->width, mode->height)) {
|
||||||
|
image_free(&img);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wave_open(&wav, output_wav, 44100)) {
|
||||||
|
image_free(&img);
|
||||||
|
image_free_raw(&resized);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sstv_vis_header_ex(&wav, mode->vis_code);
|
||||||
|
scottie_encode_image(&wav, resized.data, mode);
|
||||||
|
wave_close(&wav);
|
||||||
|
|
||||||
|
image_free(&img);
|
||||||
|
image_free_raw(&resized);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
24
scottie.h
Normal file
24
scottie.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef SCOTTIE_H
|
||||||
|
#define SCOTTIE_H
|
||||||
|
|
||||||
|
#include "wav.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t vis_code;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
double separator_ms;
|
||||||
|
double sync_ms;
|
||||||
|
double sync_porch_ms;
|
||||||
|
double scan_ms;
|
||||||
|
} scottie_mode_t;
|
||||||
|
|
||||||
|
extern const scottie_mode_t SCOTTIE_S1;
|
||||||
|
extern const scottie_mode_t SCOTTIE_S2;
|
||||||
|
extern const scottie_mode_t SCOTTIE_DX;
|
||||||
|
|
||||||
|
void scottie_encode_image(wav_t *wav, uint8_t *rgb, const scottie_mode_t *mode);
|
||||||
|
int sstv_encode_scottie(const char *input_image, const char *output_wav, const scottie_mode_t *mode);
|
||||||
|
|
||||||
|
#endif // !SCOTTIE_H
|
||||||
Reference in New Issue
Block a user