resample.c
4.23 KB
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/***************************************************************
*
* resample.c
*
* 10/6/94 bfs initial version
*
*
*
*/
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "sinc.h"
extern int errno;
#define FILTER_LENGTH 4
#define NUM_OF_BITS 16
#define NUM_OF_INT_BITS 1
#define NUM_OF_FRAC_BITS NUM_OF_BITS - NUM_OF_INT_BITS
#define MAX_PITCH 1.9999695
#define MIN_PITCH 0.0000305
#define CLIP(x) if (x > 32767) x = 32767; if (x < -32767) x = -32767;
/*
* Name: update_data_vector
*
* Description:
* This routine shifts the filter data delay line by an amount
* equal to the integer part of the current address (ca). For
* each shift, a new value is brought in from stdin.
*
* No value is returned since a read error causes program termination.
*
*/
short
update_data_vector(unsigned long ca, short* datav, char length, FILE* in)
{
short int_ca, i, j;
long decrementer;
int_ca = ca >> NUM_OF_FRAC_BITS;
decrementer = 1L << NUM_OF_FRAC_BITS;
if ( int_ca ) {
for ( i = int_ca; i > 0; i-- ) {
/* shift data in delay_line.. */
for ( j = length-1; j > 0; j-- )
datav[j] = datav[j-1];
#ifdef ASCII
fscanf(in, "%hd", datav);
#else
fread(datav, sizeof(short), 1, in);
#endif
ca -= decrementer;
}
}
return ca;
}
/*
* Name: update_coef_vector
*
* Description:
* This routine fills a coefficient vector with one point per
* lobe from the filter table. The address
*
*/
void
update_coef_vector(long ca, short* coefv, char length, short* table)
{
short index;
long frac_ca;
int i;
frac_ca = ca << ( NUM_OF_INT_BITS - 1 ); /* -1 is because ca is unsigned but frac_ca is signed */
index = (short)( (FILTER_LOBE_SIZE * frac_ca) >> 15 );
for ( i = 0; i < length; i++ ) {
coefv[i] = table[index];
index += FILTER_LOBE_SIZE;
}
}
/*
* Name: dot_product
*
* Description:
* This routine performs a dot product on the data and coefficient
* vectors passed to it. Note that the value is truncated
* after each accumulation.
*
*/
int
dot_product(short* data, short* coef, char length)
{
int temp = 0, i;
int output = 0;
for ( i = 0; i < length; i++ ) {
temp = data[i] * coef[i];
output += temp >> 15;
}
return output;
}
/*
* Name: do_resample
*
* Description:
* This routine resamples the input stream and sends it to the
* output stream.
*
*/
long
do_resample(FILE* in, FILE* out, unsigned short incr)
{
unsigned long ca = 0;
short datav[FILTER_LENGTH], coefv[FILTER_LENGTH];
int output, i;
long count = 0;
short sout;
for (i = 0; i < 4; i++) datav[i] = 0; /* clear data vector */
while ( !feof(in) ) {
ca = update_data_vector(ca, datav, FILTER_LENGTH, in);
update_coef_vector(ca, coefv, FILTER_LENGTH, sinc);
output = dot_product(datav, coefv, FILTER_LENGTH);
if (output >0x7fff)
output = 0x7fff;
else
if (output < -0x7fff)
output = -0x7fff;
sout = (short) output;
#ifdef ASCII
fprintf(sout, "%hd\n", output);
#else
fwrite(&sout, sizeof(short), 1, out);
#endif
ca += incr; /* update phase increment */
count++;
}
return count;
}
/*
* Name: encode_pitch
*
* Description:
* This routine encodes the floating point input pitch value
* in unsigned 1.15 format.
*
*/
unsigned short
encode_pitch(double p)
{
unsigned short inc;
double int_inc, frac_inc;
if ( p > MAX_PITCH ){
fprintf(stderr, "pitch has been clipped to %.7f...\n", MAX_PITCH);
p = MAX_PITCH;
}
if ( p < MIN_PITCH ){
fprintf(stderr, "pitch has been clamped to %.7f; (boy, that's really low)...\n", MIN_PITCH);
fprintf(stderr, "\n");
p = MIN_PITCH;
}
frac_inc = modf(p, &int_inc);
inc = (unsigned short)int_inc << NUM_OF_FRAC_BITS;
inc |= (unsigned short)(frac_inc * 32768);
return inc;
}
void
usage(char *pname){
fprintf(stderr, "USAGE: %s pitch < input > output\n", pname);
exit(1);
}
void
main(int argc, char **argv)
{
long count = 0;
unsigned short increment;
double pitch;
if (argc < 2) usage(argv[0]);
pitch = atof(argv[1]);
increment = encode_pitch(pitch);
count = do_resample(stdin, stdout, increment);
exit(0);
}