@@ -61,6 +61,8 @@ static soxr_datatype_t to_soxr_split_dtype(const type_info& ntype) {
6161class CSoxr {
6262 soxr_t _soxr = nullptr ;
6363 const double _oi_rate;
64+ std::unique_ptr<uint8_t []> _y_buf;
65+ size_t _y_buf_size = 0 ;
6466
6567public:
6668 const double _in_rate;
@@ -121,12 +123,20 @@ class CSoxr {
121123
122124 const size_t ilen = x.shape (0 );
123125
124- // This is slower then allocating fixed `ilen * _oi_rate`.
125- // But it insures lowest output delay provided by libsoxr.
126+ // This is slower than returning fixed `ilen * _oi_rate` buffers w/o copying .
127+ // But it ensures the lowest output delay provided by libsoxr.
126128 const size_t olen = soxr_delay (_soxr) + ilen * _oi_rate + 1 ;
127129
128- // alloc
129- y = new T[olen * channels] { 0 };
130+ // Reuse output buffer if possible, else reallocate
131+ size_t req_size = sizeof (T) * olen * channels;
132+ if (!_y_buf || _y_buf_size < req_size) {
133+ // Grow to next power of 2
134+ size_t new_size = 1 ;
135+ while (new_size < req_size) new_size <<= 1 ;
136+ _y_buf = std::make_unique<uint8_t []>(new_size);
137+ _y_buf_size = new_size;
138+ }
139+ y = reinterpret_cast <T*>(_y_buf.get ());
130140
131141 // divide long input and process
132142 size_t odone = 0 ;
@@ -150,15 +160,11 @@ class CSoxr {
150160 }
151161
152162 if (err) {
153- delete[] y;
154163 throw std::runtime_error (err);
155164 }
156165
157- // Delete 'y' when the 'owner' capsule expires
158- nb::capsule owner (y, [](void *p) noexcept {
159- delete[] (T *) p;
160- });
161- return ndarray<nb::numpy, T>(y, { out_pos, channels }, owner);
166+ // Return a copy
167+ return ndarray<nb::numpy, T>(y, { out_pos, channels }).cast ();
162168 }
163169
164170 size_t num_clips () { return *soxr_num_clips (_soxr); }
0 commit comments