2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
16 #include "pcm_reader.h"
19 typedef struct buffer_t
{
26 typedef struct limiter_t
{
27 pcm_reader_vtbl_t
*vtbl
;
29 pcm_sample_description_t format
;
34 static inline pcm_reader_t
*get_source(pcm_reader_t
*reader
)
36 return ((limiter_t
*)reader
)->src
;
40 pcm_sample_description_t
*get_format(pcm_reader_t
*reader
)
42 return pcm_get_format(get_source(reader
));
45 static int64_t get_length(pcm_reader_t
*reader
)
47 return pcm_get_length(get_source(reader
));
50 static int64_t get_position(pcm_reader_t
*reader
)
52 return ((limiter_t
*)reader
)->position
;
55 static int reserve_buffer(buffer_t
*bp
, size_t required
, unsigned unit
)
57 if (bp
->capacity
< required
) {
60 while (newsize
< required
)
62 p
= realloc(bp
->data
, newsize
* unit
);
65 bp
->capacity
= newsize
;
70 static int read_frames(pcm_reader_t
*reader
, void *buffer
, unsigned nframes
)
72 limiter_t
*self
= (limiter_t
*)reader
;
73 unsigned i
, n
, res
, nch
= self
->format
.channels_per_frame
;
74 size_t bytes
= nframes
* pcm_get_format(self
->src
)->bytes_per_frame
;
75 buffer_t
*ibp
= &self
->buffers
[nch
];
79 if (reserve_buffer(ibp
, bytes
, 1) < 0)
81 res
= pcm_read_frames(self
->src
, ibp
->data
, nframes
);
82 for (n
= 0; n
< nch
; ++n
) {
83 float *ip
= (float *)ibp
->data
, *x
;
84 buffer_t
*bp
= &self
->buffers
[n
];
86 if (reserve_buffer(bp
, bp
->count
+ res
, sizeof(float)) < 0)
89 for (i
= 0; i
< res
; ++i
)
90 x
[bp
->count
++] = pcm_clip(ip
[i
* nch
+ n
], -3.0, 3.0);
92 if (limit
> 0 && res
> 0) {
93 float last
= x
[limit
- 1];
94 for (; limit
> 0 && x
[limit
-1] * last
> 0; --limit
)
99 unsigned start
, peak_pos
;
101 for (peak_pos
= end
; peak_pos
< limit
; ++peak_pos
)
102 if (x
[peak_pos
] > 1.0f
|| x
[peak_pos
] < -1.0f
)
104 if (peak_pos
== limit
)
107 peak
= fabs(x
[peak_pos
]);
108 while (start
> bp
->head
&& x
[peak_pos
] * x
[start
] >= 0.0f
)
111 for (end
= peak_pos
+ 1; end
< limit
; ++end
) {
113 if (x
[peak_pos
] * x
[end
] < 0.0f
)
122 float a
= (peak
- 1.0f
) / (peak
* peak
);
123 if (x
[peak_pos
] > 0.0f
) a
= -a
;
124 for (i
= start
; i
< end
; ++i
)
125 x
[i
] = x
[i
] + a
* x
[i
] * x
[i
];
127 float u
= peak
, v
= 1.0f
;
128 float a
= (u
- 2.0f
* v
) / (u
* u
* u
);
129 float b
= (3.0f
* v
- 2.0f
* u
) / (u
* u
);
130 if (x
[peak_pos
] < 0.0f
) b
= -b
;
131 for (i
= start
; i
< end
; ++i
)
132 x
[i
] = x
[i
] + b
* x
[i
] * x
[i
] + a
* x
[i
] * x
[i
] * x
[i
];
138 for (n
= 0; n
< nch
; ++n
)
139 if (self
->buffers
[n
].head
< res
)
140 res
= self
->buffers
[n
].head
;
141 for (i
= 0; i
< res
; ++i
)
142 for (n
= 0; n
< nch
; ++n
)
143 *obp
++ = ((float *)self
->buffers
[n
].data
)[i
];
145 for (n
= 0; n
< nch
; ++n
) {
146 buffer_t
*bp
= &self
->buffers
[n
];
148 memmove(p
, p
+ res
, (bp
->count
- res
) * sizeof(float));
153 } while (res
== 0 && self
->buffers
[0].count
);
154 self
->position
+= res
;
158 static void teardown(pcm_reader_t
**reader
)
161 limiter_t
*self
= (limiter_t
*)*reader
;
162 pcm_teardown(&self
->src
);
163 for (i
= 0; i
< self
->format
.channels_per_frame
+ 1; ++i
)
164 free(self
->buffers
[i
].data
);
169 static pcm_reader_vtbl_t my_vtable
= {
170 get_format
, get_length
, get_position
, read_frames
, teardown
173 pcm_reader_t
*limiter_open(pcm_reader_t
*reader
)
176 int n
= pcm_get_format(reader
)->channels_per_frame
;
177 size_t size
= sizeof(limiter_t
) + offsetof(limiter_t
, buffers
[n
+ 1]);
179 if ((self
= calloc(1, size
)) == 0)
182 self
->vtbl
= &my_vtable
;
183 self
->format
= *pcm_get_format(reader
);
184 self
->format
.bits_per_channel
= 32;
185 return (pcm_reader_t
*)self
;