forked from xdsopl/robot36
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wav.c
163 lines (151 loc) · 4.37 KB
/
wav.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
robot36 - encode and decode images using SSTV in Robot 36 mode
Written in 2011 by <Ahmet Inan> <[email protected]>
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "wav.h"
#include "mmap_file.h"
struct wav_head {
uint32_t ChunkID;
uint32_t ChunkSize;
uint32_t Format;
uint32_t Subchunk1ID;
uint32_t Subchunk1Size;
uint16_t AudioFormat;
uint16_t NumChannels;
uint32_t SampleRate;
uint32_t ByteRate;
uint16_t BlockAlign;
uint16_t BitsPerSample;
uint32_t Subchunk2ID;
uint32_t Subchunk2Size;
};
struct wav {
struct pcm base;
void *p;
short *b;
size_t size;
int index;
int frames;
int r;
int c;
};
void close_wav(struct pcm *pcm)
{
struct wav *wav = (struct wav *)(pcm->data);
munmap_file(wav->p, wav->size);
free(wav);
}
void info_wav(struct pcm *pcm)
{
struct wav *wav = (struct wav *)(pcm->data);
fprintf(stderr, "%d channel(s), %d rate, %.2f seconds\n", wav->c, wav->r, (float)wav->frames / (float)wav->r);
}
int rate_wav(struct pcm *pcm)
{
struct wav *wav = (struct wav *)(pcm->data);
return wav->r;
}
int channels_wav(struct pcm *pcm)
{
struct wav *wav = (struct wav *)(pcm->data);
return wav->c;
}
int read_wav(struct pcm *pcm, short *buff, int frames)
{
struct wav *wav = (struct wav *)(pcm->data);
if ((wav->index + frames) > wav->frames)
return 0;
memcpy(buff, wav->b + wav->index * wav->c, sizeof(short) * frames * wav->c);
wav->index += frames;
return 1;
}
int write_wav(struct pcm *pcm, short *buff, int frames)
{
struct wav *wav = (struct wav *)(pcm->data);
if ((wav->index + frames) > wav->frames)
return 0;
memcpy(wav->b + wav->index * wav->c, buff, sizeof(short) * frames * wav->c);
wav->index += frames;
return 1;
}
int open_wav_read(struct pcm **p, char *name)
{
struct wav *wav = (struct wav *)malloc(sizeof(struct wav));
wav->base.close = close_wav;
wav->base.info = info_wav;
wav->base.rate = rate_wav;
wav->base.channels = channels_wav;
wav->base.rw = read_wav;
wav->base.data = (void *)wav;
if (!mmap_file_ro(&wav->p, name, &wav->size)) {
fprintf(stderr, "couldnt open wav file %s!\n", name);
free(wav);
return 0;
}
struct wav_head *head = (struct wav_head *)wav->p;
wav->b = (short *)(wav->p + sizeof(struct wav_head));
if (head->ChunkID != 0x46464952 || head->Format != 0x45564157 ||
head->Subchunk1ID != 0x20746d66 || head->Subchunk1Size != 16 ||
head->AudioFormat != 1 || head->Subchunk2ID != 0x61746164) {
fprintf(stderr, "unsupported WAV file!\n");
munmap_file(wav->p, wav->size);
free(wav);
return 0;
}
if (head->BitsPerSample != 16) {
fprintf(stderr, "only 16bit WAV supported!\n");
munmap_file(wav->p, wav->size);
free(wav);
return 0;
}
wav->index = 0;
wav->frames = head->Subchunk2Size / (sizeof(short) * head->NumChannels);
wav->r = head->SampleRate;
wav->c = head->NumChannels;
*p = &(wav->base);
return 1;
}
int open_wav_write(struct pcm **p, char *name, int rate, int channels, float seconds)
{
struct wav *wav = (struct wav *)malloc(sizeof(struct wav));
wav->base.close = close_wav;
wav->base.info = info_wav;
wav->base.rate = rate_wav;
wav->base.channels = channels_wav;
wav->base.rw = write_wav;
wav->base.data = (void *)wav;
int frames = seconds * rate;
wav->size = frames * channels * sizeof(short) + sizeof(struct wav_head);
if (!mmap_file_rw(&wav->p, name, wav->size)) {
fprintf(stderr, "couldnt open wav file %s!\n", name);
free(wav);
return 0;
}
struct wav_head *head = (struct wav_head *)wav->p;
wav->b = (short *)(wav->p + sizeof(struct wav_head));
head->ChunkID = 0x46464952;
head->ChunkSize = 36 + frames * sizeof(short) * channels;
head->Format = 0x45564157;
head->Subchunk1ID = 0x20746d66;
head->Subchunk1Size = 16;
head->AudioFormat = 1;
head->NumChannels = channels;
head->SampleRate = rate;
head->ByteRate = 2 * rate;
head->BlockAlign = 2;
head->BitsPerSample = 16;
head->Subchunk2ID = 0x61746164;
head->Subchunk2Size = frames * sizeof(short) * channels;
wav->r = rate;
wav->c = channels;
wav->frames = frames;
wav->index = 0;
*p = &(wav->base);
return 1;
}