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
|
||||
*.dwo
|
||||
|
||||
## our application (binary)
|
||||
|
||||
sstv
|
||||
e36
|
||||
|
||||
|
||||
# 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
|
||||
LDFLAGS = -lm
|
||||
|
||||
TARGET = sstv
|
||||
SRCS = main.c sstv.c robot36.c image.c wav.c martin.c
|
||||
TARGET = e36
|
||||
SRCS = main.c sstv.c robot36.c image.c wav.c martin.c scottie.c
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
$(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) {
|
||||
if (img->data)
|
||||
free(img->data);
|
||||
free(img->data); // if you do this call only once, cause of double frees
|
||||
img->data = NULL;
|
||||
}
|
||||
|
||||
53
main.c
53
main.c
@@ -1,44 +1,69 @@
|
||||
#include "sstv.h"
|
||||
#include "martin.h"
|
||||
#include "scottie.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
static void usage(const char *prog) {
|
||||
printf("Usage: %s <mode> input_image output.wav\n", prog);
|
||||
printf("Modes:\n");
|
||||
printf(" robot36 - Robot 36 (default)\n");
|
||||
printf(" martin1 - Martin M1\n");
|
||||
printf(" martin2 - Martin M2\n");
|
||||
fprintf(stderr,
|
||||
"Usage: %s <mode> <input_image> <output_wav>\n"
|
||||
"\n"
|
||||
"Modes:\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) {
|
||||
if (argc < 4) {
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 4) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *mode_str = argv[1];
|
||||
const char *mode = argv[1];
|
||||
const char *input_img = argv[2];
|
||||
const char *output_wav = argv[3];
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
int ok = 0;
|
||||
|
||||
if (strcmp(mode_str, "robot36") == 0) {
|
||||
if (strcmp(mode, "robot36") == 0) {
|
||||
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);
|
||||
} else if (strcmp(mode_str, "martin2") == 0) {
|
||||
} else if (strcmp(mode, "martin2") == 0) {
|
||||
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 {
|
||||
fprintf(stderr, "Unknown mode: %s\n", mode_str);
|
||||
fprintf(stderr, "unknown mode: %s\n\n", mode);
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
fprintf(stderr, "Encoding failed.\n");
|
||||
fprintf(stderr, "make sure the file exsists");
|
||||
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;
|
||||
}
|
||||
|
||||
2
martin.h
2
martin.h
@@ -5,7 +5,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t vis_code;
|
||||
uint8_t vis_code; // in hexadecimal not normal decimal (ex 0x08)
|
||||
int width;
|
||||
int height;
|
||||
double sync_ms;
|
||||
|
||||
72
readme.md
72
readme.md
@@ -1,12 +1,79 @@
|
||||
# sstv e36 encoder
|
||||
|
||||
This is a simple C SSTV Robot36 encoder!
|
||||
Written in pure C
|
||||
This is a SSTV encoder, currently it is in work, but it has some modes already:
|
||||
|
||||
|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:
|
||||
|
||||
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:
|
||||
#### 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
|
||||
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