10 #include "pcm_reader.h"
13 typedef int16_t sample_t
;
15 typedef struct buffer_t
{
17 unsigned count
; /* count in frames */
18 unsigned capacity
; /* size in bytes */
21 typedef struct extrapolater_t
{
22 pcm_reader_vtbl_t
*vtbl
;
24 pcm_sample_description_t format
;
27 int (*process
)(struct extrapolater_t
*, void *, unsigned);
32 static inline pcm_reader_t
*get_source(pcm_reader_t
*reader
)
34 return ((extrapolater_t
*)reader
)->src
;
38 pcm_sample_description_t
*get_format(pcm_reader_t
*reader
)
40 return pcm_get_format(get_source(reader
));
43 static int64_t get_length(pcm_reader_t
*reader
)
45 return pcm_get_length(get_source(reader
));
48 static int64_t get_position(pcm_reader_t
*reader
)
50 return pcm_get_position(get_source(reader
));
53 static int realloc_buffer(buffer_t
*bp
, size_t size
)
55 if (bp
->capacity
< size
) {
56 void *p
= realloc(bp
->data
, size
);
64 static void reverse_buffer(sample_t
*data
, unsigned nframes
, unsigned nchannels
)
66 unsigned i
= 0, j
= nchannels
* (nframes
- 1), n
;
68 for (; i
< j
; i
+= nchannels
, j
-= nchannels
) {
69 for (n
= 0; n
< nchannels
; ++n
) {
70 sample_t tmp
= data
[i
+ n
];
71 data
[i
+ n
] = data
[j
+ n
];
77 static int fetch(extrapolater_t
*self
, unsigned nframes
)
79 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
80 buffer_t
*bp
= &self
->buffer
[self
->nbuffer
];
83 if (realloc_buffer(bp
, nframes
* sfmt
->bytes_per_frame
) == 0) {
84 rc
= pcm_read_frames(self
->src
, bp
->data
, nframes
);
85 bp
->count
= rc
> 0 ? rc
: 0;
92 static int extrapolate(extrapolater_t
*self
, const buffer_t
*bp
,
93 void *dst
, unsigned nframes
)
95 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
96 unsigned i
, n
= sfmt
->channels_per_frame
;
99 for (i
= 0; i
< n
; ++i
) {
100 vorbis_lpc_from_data(bp
->data
+ i
, lpc
, bp
->count
, LPC_ORDER
, n
);
101 vorbis_lpc_predict(lpc
, &bp
->data
[i
+ n
* (bp
->count
- LPC_ORDER
)],
102 LPC_ORDER
, (sample_t
*)dst
+ i
, nframes
, n
);
107 static int process1(extrapolater_t
*self
, void *buffer
, unsigned nframes
);
108 static int process2(extrapolater_t
*self
, void *buffer
, unsigned nframes
);
109 static int process3(extrapolater_t
*self
, void *buffer
, unsigned nframes
);
111 static int process0(extrapolater_t
*self
, void *buffer
, unsigned nframes
)
113 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
114 unsigned nchannels
= sfmt
->channels_per_frame
;
115 buffer_t
*bp
= &self
->buffer
[self
->nbuffer
];
117 if (fetch(self
, nframes
) < 2 * LPC_ORDER
)
118 memset(buffer
, 0, nframes
* sfmt
->bytes_per_frame
);
120 reverse_buffer(bp
->data
, bp
->count
, nchannels
);
121 extrapolate(self
, bp
, buffer
, nframes
);
122 reverse_buffer(buffer
, nframes
, nchannels
);
123 reverse_buffer(bp
->data
, bp
->count
, nchannels
);
125 self
->process
= bp
->count
? process1
: process2
;
129 static int process1(extrapolater_t
*self
, void *buffer
, unsigned nframes
)
131 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
132 buffer_t
*bp
= &self
->buffer
[self
->nbuffer
^ 1];
134 assert(bp
->count
<= nframes
);
135 memcpy(buffer
, bp
->data
, bp
->count
* sfmt
->bytes_per_frame
);
136 if (!fetch(self
, nframes
))
137 self
->process
= process2
;
141 static int process2(extrapolater_t
*self
, void *buffer
, unsigned nframes
)
143 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
144 buffer_t
*bp
= &self
->buffer
[self
->nbuffer
];
145 buffer_t
*bbp
= &self
->buffer
[self
->nbuffer
^ 1];
147 if (bp
->count
< 2 * LPC_ORDER
) {
148 size_t total
= bp
->count
+ bbp
->count
;
150 realloc_buffer(bbp
, total
* sfmt
->bytes_per_frame
) == 0)
152 memcpy(bbp
->data
+ bbp
->count
* sfmt
->channels_per_frame
,
153 bp
->data
, bp
->count
* sfmt
->bytes_per_frame
);
160 self
->process
= process3
;
162 if (bp
->count
>= 2 * LPC_ORDER
)
163 extrapolate(self
, bp
, buffer
, nframes
);
165 memset(buffer
, 0, nframes
* sfmt
->bytes_per_frame
);
169 static int process3(extrapolater_t
*self
, void *buffer
, unsigned nframes
)
174 static int read_frames(pcm_reader_t
*reader
, void *buffer
, unsigned nframes
)
176 extrapolater_t
*self
= (extrapolater_t
*)reader
;
177 return self
->process(self
, buffer
, nframes
);
180 static void teardown(pcm_reader_t
**reader
)
182 extrapolater_t
*self
= (extrapolater_t
*)*reader
;
183 pcm_teardown(&self
->src
);
184 free(self
->buffer
[0].data
);
185 free(self
->buffer
[1].data
);
190 static pcm_reader_vtbl_t my_vtable
= {
191 get_format
, get_length
, get_position
, read_frames
, teardown
194 pcm_reader_t
*extrapolater_open(pcm_reader_t
*reader
)
196 extrapolater_t
*self
= 0;
198 if ((self
= calloc(1, sizeof(extrapolater_t
))) == 0)
201 self
->vtbl
= &my_vtable
;
202 self
->process
= process0
;
203 return (pcm_reader_t
*)self
;