2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
14 #include "pcm_reader.h"
17 typedef int16_t sample_t
;
19 typedef struct buffer_t
{
21 unsigned count
; /* count in frames */
22 unsigned capacity
; /* size in bytes */
25 typedef struct extrapolater_t
{
26 pcm_reader_vtbl_t
*vtbl
;
28 pcm_sample_description_t format
;
31 int (*process
)(struct extrapolater_t
*, void *, unsigned);
36 static inline pcm_reader_t
*get_source(pcm_reader_t
*reader
)
38 return ((extrapolater_t
*)reader
)->src
;
42 pcm_sample_description_t
*get_format(pcm_reader_t
*reader
)
44 return pcm_get_format(get_source(reader
));
47 static int64_t get_length(pcm_reader_t
*reader
)
49 return pcm_get_length(get_source(reader
));
52 static int64_t get_position(pcm_reader_t
*reader
)
54 return pcm_get_position(get_source(reader
));
57 static int realloc_buffer(buffer_t
*bp
, size_t size
)
59 if (bp
->capacity
< size
) {
60 void *p
= realloc(bp
->data
, size
);
68 static void reverse_buffer(sample_t
*data
, unsigned nframes
, unsigned nchannels
)
70 unsigned i
= 0, j
= nchannels
* (nframes
- 1), n
;
72 for (; i
< j
; i
+= nchannels
, j
-= nchannels
) {
73 for (n
= 0; n
< nchannels
; ++n
) {
74 sample_t tmp
= data
[i
+ n
];
75 data
[i
+ n
] = data
[j
+ n
];
81 static int fetch(extrapolater_t
*self
, unsigned nframes
)
83 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
84 buffer_t
*bp
= &self
->buffer
[self
->nbuffer
];
87 if (realloc_buffer(bp
, nframes
* sfmt
->bytes_per_frame
) == 0) {
88 rc
= pcm_read_frames(self
->src
, bp
->data
, nframes
);
89 if (rc
> 0) bp
->count
= rc
;
93 return rc
<= 0 ? 0 : bp
->count
;
96 static int extrapolate(extrapolater_t
*self
, const buffer_t
*bp
,
97 void *dst
, unsigned nframes
)
99 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
100 unsigned i
, n
= sfmt
->channels_per_frame
;
101 float lpc
[LPC_ORDER
];
103 for (i
= 0; i
< n
; ++i
) {
104 vorbis_lpc_from_data(bp
->data
+ i
, lpc
, bp
->count
, LPC_ORDER
, n
);
105 vorbis_lpc_predict(lpc
, &bp
->data
[i
+ n
* (bp
->count
- LPC_ORDER
)],
106 LPC_ORDER
, (sample_t
*)dst
+ i
, nframes
, n
);
111 static int process1(extrapolater_t
*self
, void *buffer
, unsigned nframes
);
112 static int process2(extrapolater_t
*self
, void *buffer
, unsigned nframes
);
113 static int process3(extrapolater_t
*self
, void *buffer
, unsigned nframes
);
115 static int process0(extrapolater_t
*self
, void *buffer
, unsigned nframes
)
117 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
118 unsigned nchannels
= sfmt
->channels_per_frame
;
119 buffer_t
*bp
= &self
->buffer
[self
->nbuffer
];
121 if (fetch(self
, nframes
) < 2 * LPC_ORDER
)
122 memset(buffer
, 0, nframes
* sfmt
->bytes_per_frame
);
124 reverse_buffer(bp
->data
, bp
->count
, nchannels
);
125 extrapolate(self
, bp
, buffer
, nframes
);
126 reverse_buffer(buffer
, nframes
, nchannels
);
127 reverse_buffer(bp
->data
, bp
->count
, nchannels
);
130 self
->process
= process1
;
132 memset(bp
->data
, 0, nframes
* sfmt
->bytes_per_frame
);
134 self
->process
= process2
;
139 static int process1(extrapolater_t
*self
, void *buffer
, unsigned nframes
)
141 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
142 buffer_t
*bp
= &self
->buffer
[self
->nbuffer
^ 1];
144 assert(bp
->count
<= nframes
);
145 memcpy(buffer
, bp
->data
, bp
->count
* sfmt
->bytes_per_frame
);
146 if (!fetch(self
, nframes
)) {
147 buffer_t
*bbp
= &self
->buffer
[self
->nbuffer
];
148 if (bp
->count
< 2 * LPC_ORDER
) {
149 size_t total
= bp
->count
+ bbp
->count
;
151 realloc_buffer(bbp
, total
* sfmt
->bytes_per_frame
) == 0 &&
152 realloc_buffer(bp
, total
* sfmt
->bytes_per_frame
) == 0)
154 memcpy(bbp
->data
+ bbp
->count
* sfmt
->channels_per_frame
,
155 bp
->data
, bp
->count
* sfmt
->bytes_per_frame
);
156 memcpy(bp
->data
, bbp
->data
, total
* sfmt
->bytes_per_frame
);
160 if (bp
->count
>= 2 * LPC_ORDER
)
161 extrapolate(self
, bp
, bbp
->data
, nframes
);
163 memset(bbp
->data
, 0, nframes
* sfmt
->bytes_per_frame
);
164 bbp
->count
= nframes
;
165 self
->process
= process2
;
170 static int process2(extrapolater_t
*self
, void *buffer
, unsigned nframes
)
172 const pcm_sample_description_t
*sfmt
= pcm_get_format(self
->src
);
173 buffer_t
*bp
= &self
->buffer
[self
->nbuffer
];
174 if (bp
->count
< nframes
)
176 memcpy(buffer
, bp
->data
, nframes
* sfmt
->bytes_per_frame
);
177 if (bp
->count
> nframes
)
178 memmove(bp
->data
, bp
->data
+ nframes
* sfmt
->channels_per_frame
,
179 (bp
->count
- nframes
) * sfmt
->bytes_per_frame
);
180 bp
->count
-= nframes
;
182 self
->process
= process3
;
186 static int process3(extrapolater_t
*self
, void *buffer
, unsigned nframes
)
191 static int read_frames(pcm_reader_t
*reader
, void *buffer
, unsigned nframes
)
193 extrapolater_t
*self
= (extrapolater_t
*)reader
;
194 return self
->process(self
, buffer
, nframes
);
197 static void teardown(pcm_reader_t
**reader
)
199 extrapolater_t
*self
= (extrapolater_t
*)*reader
;
200 pcm_teardown(&self
->src
);
201 free(self
->buffer
[0].data
);
202 free(self
->buffer
[1].data
);
207 static pcm_reader_vtbl_t my_vtable
= {
208 get_format
, get_length
, get_position
, read_frames
, teardown
211 pcm_reader_t
*extrapolater_open(pcm_reader_t
*reader
)
213 extrapolater_t
*self
= 0;
215 if ((self
= calloc(1, sizeof(extrapolater_t
))) == 0)
218 self
->vtbl
= &my_vtable
;
219 self
->process
= process0
;
220 return (pcm_reader_t
*)self
;