1
8
Fork
You've already forked nup
0

Replace nup-headless resampling code #141

Closed
opened 2026年03月25日 17:37:39 +01:00 by derat · 6 comments
Owner
Copy link

The audioFile class in nup-headless is currently using Ebitengine's ResampleReader class to upsample and downsample audio data that isn't 44.1 kHz.

I don't think it makes sense to pull in as big a dependency as Ebitengine now that it's not being used for audio playback (see #139). Ebitengine development looks like it went all-in on Claude Code about two weeks ago, and I'd noticed weird behavior even before then (e.g. ResampleReader doesn't seem to report EOF correctly).

I'd prefer to find some other small resampling library that I can use instead. A brief survey:

  • libsamplerate gets mentioned as the best resampling library in various places. It's written in C, but there are some minimal Go bindings at https://github.com/dh1tw/gosamplerate. It looks like it only operates on float32 and float64, but I think that ResampleReader is already converting to float64 behind-the-scenes so that's probably not a big deal. At first glance, the Go bindings look like they make a bunch of probably-unnecessary copies, so I'd probably want to write my own.
  • resample is a small CGo wrapper around libsoxr. It looks like it implements io.Writer. It has the downside that it requires the C library to be installed on the system.
  • gomplerate is a simple, public domain pure Go library. I have no idea about the quality of the resampling or its performance.
  • oov/audio has a resampler package with a pure Go port of opus-tools' audio resampler. The code hasn't been touched since 2014.
  • beep looks like it has a small pure Go Resampler class. It's MIT-licensed, but it pulls a ton of other dependencies (including Ebitengine).
  • go-audio-resampler is a recent vibecoded port of libsoxr, complete with a 13.5k LOC initial commit. :-/
  • Ron's Digital Signal Processing Page provides some small snippets in Basic, in case I want to try to port them to Go.
  • Julius Orion Smith III's Digital Audio Resampling Home Page goes into the theory behind resampling, but it's way over my head given my lack of DSP experience.
The `audioFile` class in `nup-headless` is currently using Ebitengine's `ResampleReader` class to upsample and downsample audio data that isn't 44.1 kHz. I don't think it makes sense to pull in as big a dependency as Ebitengine now that it's not being used for audio playback (see #139). Ebitengine development looks like it went all-in on Claude Code about two weeks ago, and I'd noticed weird behavior even before then (e.g. `ResampleReader` doesn't seem to report EOF correctly). I'd prefer to find some other small resampling library that I can use instead. A brief survey: * [libsamplerate](http://www.mega-nerd.com/SRC/) gets mentioned as the best resampling library in various places. It's written in C, but there are some minimal Go bindings at https://github.com/dh1tw/gosamplerate. It looks like it only operates on float32 and float64, but I think that `ResampleReader` is already converting to float64 behind-the-scenes so that's probably not a big deal. At first glance, the Go bindings look like they make a bunch of probably-unnecessary copies, so I'd probably want to write my own. * [resample](https://github.com/zaf/resample) is a small CGo wrapper around libsoxr. It looks like it implements `io.Writer`. It has the downside that it requires the C library to be installed on the system. * [gomplerate](https://github.com/zeozeozeo/gomplerate) is a simple, public domain pure Go library. I have no idea about the quality of the resampling or its performance. * [oov/audio](https://github.com/oov/audio) has a [resampler](https://pkg.go.dev/github.com/oov/audio/resampler) package with a pure Go port of opus-tools' audio resampler. The code hasn't been touched since 2014. * [beep](https://github.com/gopxl/beep) looks like it has a small pure Go [Resampler](https://pkg.go.dev/github.com/gopxl/beep#Resampler) class. It's MIT-licensed, but it pulls a ton of other dependencies (including Ebitengine). * [go-audio-resampler](https://github.com/tphakala/go-audio-resampler) is a recent vibecoded port of libsoxr, complete with a [13.5k LOC initial commit](https://github.com/tphakala/go-audio-resampler/commit/d02270343ace12a95f6b0c51404886f038e80c7c). :-/ * [Ron's Digital Signal Processing Page](https://www.nicholson.com/rhn/dsp.html) provides some small snippets in Basic, in case I want to try to port them to Go. * [Julius Orion Smith III's Digital Audio Resampling Home Page](https://ccrma.stanford.edu/~jos/resample/resample.html) goes into the theory behind resampling, but it's way over my head given my lack of DSP experience.
Author
Owner
Copy link

I'm writing a little program to compare the different libraries. I probably won't bother with beep's resampler; it looks like it's a huge pain to use from anything that isn't beep (it has its own Streamer interface and only operates on 64-bit floats).

I'm writing a little program to compare the different libraries. I probably won't bother with beep's resampler; it looks like it's a huge pain to use from anything that isn't beep (it has its own `Streamer` interface and only operates on 64-bit floats).
Author
Owner
Copy link

I did some basic testing. I didn't spend any time optimizing my code (e.g. I'm doing a bunch of copies for libraries that require slices of int16 or float32 instead of a slice of s16 bytes), and this is just for a single run of each resampler.


piano2-48.wav (6.3066875s, 605424 samples at 48000 Hz, 1210848 audio bytes)

Name Size Time
ebiten 2097152 754 ms
gomplerate 1112466 98 ms
gosamplerate_linear 1112468 19 ms
gosamplerate_zero_order_hold 1112468 15 ms
gosamplerate_sinc_fastest 1112468 87 ms
gosamplerate_sinc_medium 1112468 168 ms
gosamplerate_sinc_best 1112468 531 ms
sox_quick 1112468 31 ms
sox_low 1112468 18 ms
sox_medium 1112468 19 ms
sox_high 1112468 20 ms
sox_very_high 1112468 37 ms
opus_0 1112466 13 ms
opus_2 1112466 35 ms
opus_5 1112466 66 ms
opus_7 1112466 111 ms
opus_10 1112466 219 ms

All of the opus_ resamplers sound bad (and opus_0 is notably terrible). Most of the other ones sound fine to me. gosamplerate_zero_order_hold has a bit of aliasing on the high end. ebiten has the distinction of being both slow and unable to return the correct number of samples; the extra samples are fortunately just silence.


honey_bee-22.mp3 (10s, 22.1kHz mono, 220500 samples)

Name Size Time
ebiten 2097152 729 ms
gomplerate 1764000 136 ms
gosamplerate_linear 1764000 24 ms
gosamplerate_zero_order_hold 1764004 15 ms
gosamplerate_sinc_fastest 1764000 131 ms
gosamplerate_sinc_medium 1764000 222 ms
gosamplerate_sinc_best 1764000 664 ms
sox_quick 1764000 37 ms
sox_low 1764000 18 ms
sox_medium 1764000 24 ms
sox_high 1764000 21 ms
sox_very_high 1764000 28 ms
opus_0 1764000 18 ms
opus_2 1764000 52 ms
opus_5 1764000 93 ms
opus_7 1764000 151 ms
opus_10 1764000 308 ms

gomplerate, gosamplerate_sinc_*, and opus_* all add annoying scratching sounds. Everything else sounds fine (or at least as fine as the original 22.05 kHz audio does).


Based on what I've tried so far, I'm strongly leaning toward zaf/resample, since it's both fast and didn't exhibit any problems. I'll experiment with some more files, though. It's too bad that none of the native Go options provide good results, even ignoring performance. (Well, Ebitengine at least sounds okay, if I ignore it returning a bunch of extra empty data and being very slow.)

I did some basic testing. I didn't spend any time optimizing my code (e.g. I'm doing a bunch of copies for libraries that require slices of `int16` or `float32` instead of a slice of s16 bytes), and this is just for a single run of each resampler. --- **`piano2-48.wav` (6.3066875s, 605424 samples at 48000 Hz, 1210848 audio bytes)** | Name | Size | Time | | :--------------------------- | --------: | -------: | | ebiten | 2097152 | 754 ms | | gomplerate | 1112466 | 98 ms | | gosamplerate_linear | 1112468 | 19 ms | | gosamplerate_zero_order_hold | 1112468 | 15 ms | | gosamplerate_sinc_fastest | 1112468 | 87 ms | | gosamplerate_sinc_medium | 1112468 | 168 ms | | gosamplerate_sinc_best | 1112468 | 531 ms | | sox_quick | 1112468 | 31 ms | | sox_low | 1112468 | 18 ms | | sox_medium | 1112468 | 19 ms | | sox_high | 1112468 | 20 ms | | sox_very_high | 1112468 | 37 ms | | opus_0 | 1112466 | 13 ms | | opus_2 | 1112466 | 35 ms | | opus_5 | 1112466 | 66 ms | | opus_7 | 1112466 | 111 ms | | opus_10 | 1112466 | 219 ms | All of the `opus_` resamplers sound bad (and `opus_0` is notably terrible). Most of the other ones sound fine to me. `gosamplerate_zero_order_hold` has a bit of aliasing on the high end. `ebiten` has the distinction of being both slow and unable to return the correct number of samples; the extra samples are fortunately just silence. --- **`honey_bee-22.mp3` (10s, 22.1kHz mono, 220500 samples)** | Name | Size | Time | | :--------------------------- | --------: | -------: | | ebiten | 2097152 | 729 ms | | gomplerate | 1764000 | 136 ms | | gosamplerate_linear | 1764000 | 24 ms | | gosamplerate_zero_order_hold | 1764004 | 15 ms | | gosamplerate_sinc_fastest | 1764000 | 131 ms | | gosamplerate_sinc_medium | 1764000 | 222 ms | | gosamplerate_sinc_best | 1764000 | 664 ms | | sox_quick | 1764000 | 37 ms | | sox_low | 1764000 | 18 ms | | sox_medium | 1764000 | 24 ms | | sox_high | 1764000 | 21 ms | | sox_very_high | 1764000 | 28 ms | | opus_0 | 1764000 | 18 ms | | opus_2 | 1764000 | 52 ms | | opus_5 | 1764000 | 93 ms | | opus_7 | 1764000 | 151 ms | | opus_10 | 1764000 | 308 ms | `gomplerate`, `gosamplerate_sinc_*`, and `opus_*` all add annoying scratching sounds. Everything else sounds fine (or at least as fine as the original 22.05 kHz audio does). --- Based on what I've tried so far, I'm strongly leaning toward [zaf/resample](https://github.com/zaf/resample), since it's both fast and didn't exhibit any problems. I'll experiment with some more files, though. It's too bad that none of the native Go options provide good results, even ignoring performance. (Well, Ebitengine at least sounds okay, if I ignore it returning a bunch of extra empty data and being very slow.)
Author
Owner
Copy link

For future reference: I think I have 136 MP3s that are 48 kHz instead of 44.1 and exactly 1 that's 22.05 (and 48 kb/s CBR!).

For future reference: I think I have 136 MP3s that are 48 kHz instead of 44.1 and exactly 1 that's 22.05 (and 48 kb/s CBR!).
Author
Owner
Copy link

Here's a longer 48 kHz file:

v-flower.mp3 (3m9.830916666s, 18223768 samples at 48000 Hz, 36447536 audio bytes)

Name Size Time
ebiten 33554432 10492 ms
gomplerate 33486172 2835 ms
gosamplerate_linear 33486176 351 ms
gosamplerate_zero_order_hold 33486176 273 ms
gosamplerate_sinc_fastest 33486176 2653 ms
gosamplerate_sinc_medium 33486176 4642 ms
gosamplerate_sinc_best 33486176 17300 ms
sox_quick 33486172 426 ms
sox_low 33486172 575 ms
sox_medium 33486172 520 ms
sox_high 33486172 535 ms
sox_very_high 33486172 1405 ms
opus_0 33486172 372 ms
opus_2 33486172 944 ms
opus_5 33486172 1803 ms
opus_7 33486172 3206 ms
opus_10 33486172 6200 ms

Weirdly, ebiten is at least close to the correct number of samples now, and gosamplerate_sinc_best managed to be even slower than it. I think that the difference in sizes is due to rounding up vs. truncating (36447536 * 44.1 / 48 = 33486173.7).


Here's my one 22050 Hz file:

virt-play-ball.mp3 (1m21.110204081s, 3576960 samples at 22050 Hz, 7153920 audio bytes)

Name Size Time
ebiten 16777216 6117 ms
gomplerate 14307840 771 ms
gosamplerate_linear 14307840 138 ms
gosamplerate_zero_order_hold 14307844 140 ms
gosamplerate_sinc_fastest 14307840 948 ms
gosamplerate_sinc_medium 14307840 1813 ms
gosamplerate_sinc_best 14307840 5827 ms
sox_quick 14307840 133 ms
sox_low 14307840 117 ms
sox_medium 14307840 122 ms
sox_high 14307840 154 ms
sox_very_high 14307840 192 ms
opus_0 14307840 130 ms
opus_2 14307840 304 ms
opus_5 14307840 730 ms
opus_7 14307840 1216 ms
opus_10 14307840 2534 ms

Harder to judge quality on this one, as the audio is meant to sound terrible.

Here's a longer 48 kHz file: **`v-flower.mp3` (3m9.830916666s, 18223768 samples at 48000 Hz, 36447536 audio bytes)** | Name | Size | Time | | :--------------------------- | --------: | -------: | | ebiten | 33554432 | 10492 ms | | gomplerate | 33486172 | 2835 ms | | gosamplerate_linear | 33486176 | 351 ms | | gosamplerate_zero_order_hold | 33486176 | 273 ms | | gosamplerate_sinc_fastest | 33486176 | 2653 ms | | gosamplerate_sinc_medium | 33486176 | 4642 ms | | gosamplerate_sinc_best | 33486176 | 17300 ms | | sox_quick | 33486172 | 426 ms | | sox_low | 33486172 | 575 ms | | sox_medium | 33486172 | 520 ms | | sox_high | 33486172 | 535 ms | | sox_very_high | 33486172 | 1405 ms | | opus_0 | 33486172 | 372 ms | | opus_2 | 33486172 | 944 ms | | opus_5 | 33486172 | 1803 ms | | opus_7 | 33486172 | 3206 ms | | opus_10 | 33486172 | 6200 ms | Weirdly, `ebiten` is at least close to the correct number of samples now, and `gosamplerate_sinc_best` managed to be even slower than it. I think that the difference in sizes is due to rounding up vs. truncating (36447536 * 44.1 / 48 = 33486173.7). --- Here's my one 22050 Hz file: **`virt-play-ball.mp3` (1m21.110204081s, 3576960 samples at 22050 Hz, 7153920 audio bytes)** | Name | Size | Time | | :--------------------------- | --------: | -------: | | ebiten | 16777216 | 6117 ms | | gomplerate | 14307840 | 771 ms | | gosamplerate_linear | 14307840 | 138 ms | | gosamplerate_zero_order_hold | 14307844 | 140 ms | | gosamplerate_sinc_fastest | 14307840 | 948 ms | | gosamplerate_sinc_medium | 14307840 | 1813 ms | | gosamplerate_sinc_best | 14307840 | 5827 ms | | sox_quick | 14307840 | 133 ms | | sox_low | 14307840 | 117 ms | | sox_medium | 14307840 | 122 ms | | sox_high | 14307840 | 154 ms | | sox_very_high | 14307840 | 192 ms | | opus_0 | 14307840 | 130 ms | | opus_2 | 14307840 | 304 ms | | opus_5 | 14307840 | 730 ms | | opus_7 | 14307840 | 1216 ms | | opus_10 | 14307840 | 2534 ms | Harder to judge quality on this one, as the audio is meant to sound terrible.
Author
Owner
Copy link

Now with testing.B for proper benchmarking, plus with beep added:


piano2-48.wav (6.3066875s, 605424 samples at 48000 Hz, 1210848 audio bytes)

Name Size Time
beep_1 1112468 124 ms
beep_3 1112468 159 ms
beep_6 1112468 294 ms
ebiten 2097152 909 ms
gomplerate 1112466 81 ms
gosamplerate_linear 1112468 18 ms
gosamplerate_zero_order_hold 1112468 19 ms
gosamplerate_sinc_fastest 1112468 101 ms
gosamplerate_sinc_medium 1112468 188 ms
gosamplerate_sinc_best 1112468 638 ms
sox_quick 1112468 15 ms
sox_low 1112468 20 ms
sox_medium 1112468 21 ms
sox_high 1112468 23 ms
sox_very_high 1112468 32 ms
opus_0 1112466 16 ms
opus_2 1112466 38 ms
opus_5 1112466 72 ms
opus_7 1112466 123 ms
opus_10 1112466 241 ms

honey_bee-22.mp3 (10s, 441000 samples at 22050 Hz, 882000 audio bytes)

Name Size Time
beep_1 1764000 166 ms
beep_3 1764000 247 ms
beep_6 1764000 403 ms
ebiten 2097152 822 ms
gomplerate 1764000 130 ms
gosamplerate_linear 1764000 25 ms
gosamplerate_zero_order_hold 1764004 22 ms
gosamplerate_sinc_fastest 1764000 133 ms
gosamplerate_sinc_medium 1764000 252 ms
gosamplerate_sinc_best 1764000 678 ms
sox_quick 1764000 21 ms
sox_low 1764000 24 ms
sox_medium 1764000 19 ms
sox_high 1764000 20 ms
sox_very_high 1764000 25 ms
opus_0 1764000 19 ms
opus_2 1764000 46 ms
opus_5 1764000 110 ms
opus_7 1764000 185 ms
opus_10 1764000 377 ms

v-flower.mp3 (3m9.830916666s, 18223768 samples at 48000 Hz, 36447536 audio bytes)

Name Size Time
beep_1 33486176 3439 ms
beep_3 33486176 4179 ms
beep_6 33486176 7792 ms
ebiten 33554432 12246 ms
gomplerate 33486172 3319 ms
gosamplerate_linear 33486176 386 ms
gosamplerate_zero_order_hold 33486176 356 ms
gosamplerate_sinc_fastest 33486176 2901 ms
gosamplerate_sinc_medium 33486176 6381 ms
gosamplerate_sinc_best 33486176 18869 ms
sox_quick 33486172 417 ms
sox_low 33486172 596 ms
sox_medium 33486172 524 ms
sox_high 33486172 533 ms
sox_very_high 33486172 1217 ms
opus_0 33486172 366 ms
opus_2 33486172 927 ms
opus_5 33486172 1929 ms
opus_7 33486172 3514 ms
opus_10 33486172 7263 ms

virt-play-ball.mp3 (1m21.110204081s, 3576960 samples at 22050 Hz, 7153920 audio bytes)

Name Size Time
beep_1 14307840 1215 ms
beep_3 14307840 1670 ms
beep_6 14307840 2957 ms
ebiten 16777216 5483 ms
gomplerate 14307840 727 ms
gosamplerate_linear 14307840 146 ms
gosamplerate_zero_order_hold 14307844 141 ms
gosamplerate_sinc_fastest 14307840 950 ms
gosamplerate_sinc_medium 14307840 1894 ms
gosamplerate_sinc_best 14307840 5387 ms
sox_quick 14307840 143 ms
sox_low 14307840 114 ms
sox_medium 14307840 116 ms
sox_high 14307840 146 ms
sox_very_high 14307840 181 ms
opus_0 14307840 119 ms
opus_2 14307840 387 ms
opus_5 14307840 880 ms
opus_7 14307840 1281 ms
opus_10 14307840 2577 ms

This is still very unscientific (running in a ChromeOS VM with who knows what scheduler while I'm doing stuff in the background).

beep_1 ("very high performance, on-the-fly resampling, low quality") sounds okay enough to me. I'd still really like to use a native Go implentation, so I'll probably experiment with adapting beep's code to see if I can make it do fewer copies (right now it's very tied to beep's Streamer interface and operates on float64s).

Now with `testing.B` for proper benchmarking, plus with beep added: --- **`piano2-48.wav` (6.3066875s, 605424 samples at 48000 Hz, 1210848 audio bytes)** | Name | Size | Time | | :--------------------------- | --------: | -------: | | beep_1 | 1112468 | 124 ms | | beep_3 | 1112468 | 159 ms | | beep_6 | 1112468 | 294 ms | | ebiten | 2097152 | 909 ms | | gomplerate | 1112466 | 81 ms | | gosamplerate_linear | 1112468 | 18 ms | | gosamplerate_zero_order_hold | 1112468 | 19 ms | | gosamplerate_sinc_fastest | 1112468 | 101 ms | | gosamplerate_sinc_medium | 1112468 | 188 ms | | gosamplerate_sinc_best | 1112468 | 638 ms | | sox_quick | 1112468 | 15 ms | | sox_low | 1112468 | 20 ms | | sox_medium | 1112468 | 21 ms | | sox_high | 1112468 | 23 ms | | sox_very_high | 1112468 | 32 ms | | opus_0 | 1112466 | 16 ms | | opus_2 | 1112466 | 38 ms | | opus_5 | 1112466 | 72 ms | | opus_7 | 1112466 | 123 ms | | opus_10 | 1112466 | 241 ms | --- **`honey_bee-22.mp3` (10s, 441000 samples at 22050 Hz, 882000 audio bytes)** | Name | Size | Time | | :--------------------------- | --------: | -------: | | beep_1 | 1764000 | 166 ms | | beep_3 | 1764000 | 247 ms | | beep_6 | 1764000 | 403 ms | | ebiten | 2097152 | 822 ms | | gomplerate | 1764000 | 130 ms | | gosamplerate_linear | 1764000 | 25 ms | | gosamplerate_zero_order_hold | 1764004 | 22 ms | | gosamplerate_sinc_fastest | 1764000 | 133 ms | | gosamplerate_sinc_medium | 1764000 | 252 ms | | gosamplerate_sinc_best | 1764000 | 678 ms | | sox_quick | 1764000 | 21 ms | | sox_low | 1764000 | 24 ms | | sox_medium | 1764000 | 19 ms | | sox_high | 1764000 | 20 ms | | sox_very_high | 1764000 | 25 ms | | opus_0 | 1764000 | 19 ms | | opus_2 | 1764000 | 46 ms | | opus_5 | 1764000 | 110 ms | | opus_7 | 1764000 | 185 ms | | opus_10 | 1764000 | 377 ms | --- **`v-flower.mp3` (3m9.830916666s, 18223768 samples at 48000 Hz, 36447536 audio bytes)** | Name | Size | Time | | :--------------------------- | --------: | -------: | | beep_1 | 33486176 | 3439 ms | | beep_3 | 33486176 | 4179 ms | | beep_6 | 33486176 | 7792 ms | | ebiten | 33554432 | 12246 ms | | gomplerate | 33486172 | 3319 ms | | gosamplerate_linear | 33486176 | 386 ms | | gosamplerate_zero_order_hold | 33486176 | 356 ms | | gosamplerate_sinc_fastest | 33486176 | 2901 ms | | gosamplerate_sinc_medium | 33486176 | 6381 ms | | gosamplerate_sinc_best | 33486176 | 18869 ms | | sox_quick | 33486172 | 417 ms | | sox_low | 33486172 | 596 ms | | sox_medium | 33486172 | 524 ms | | sox_high | 33486172 | 533 ms | | sox_very_high | 33486172 | 1217 ms | | opus_0 | 33486172 | 366 ms | | opus_2 | 33486172 | 927 ms | | opus_5 | 33486172 | 1929 ms | | opus_7 | 33486172 | 3514 ms | | opus_10 | 33486172 | 7263 ms | --- **`virt-play-ball.mp3` (1m21.110204081s, 3576960 samples at 22050 Hz, 7153920 audio bytes)** | Name | Size | Time | | :--------------------------- | --------: | -------: | | beep_1 | 14307840 | 1215 ms | | beep_3 | 14307840 | 1670 ms | | beep_6 | 14307840 | 2957 ms | | ebiten | 16777216 | 5483 ms | | gomplerate | 14307840 | 727 ms | | gosamplerate_linear | 14307840 | 146 ms | | gosamplerate_zero_order_hold | 14307844 | 141 ms | | gosamplerate_sinc_fastest | 14307840 | 950 ms | | gosamplerate_sinc_medium | 14307840 | 1894 ms | | gosamplerate_sinc_best | 14307840 | 5387 ms | | sox_quick | 14307840 | 143 ms | | sox_low | 14307840 | 114 ms | | sox_medium | 14307840 | 116 ms | | sox_high | 14307840 | 146 ms | | sox_very_high | 14307840 | 181 ms | | opus_0 | 14307840 | 119 ms | | opus_2 | 14307840 | 387 ms | | opus_5 | 14307840 | 880 ms | | opus_7 | 14307840 | 1281 ms | | opus_10 | 14307840 | 2577 ms | --- This is still very unscientific (running in a ChromeOS VM with who knows what scheduler while I'm doing stuff in the background). `beep_1` ("very high performance, on-the-fly resampling, low quality") sounds okay enough to me. I'd still really like to use a native Go implentation, so I'll probably experiment with adapting beep's code to see if I can make it do fewer copies (right now it's very tied to beep's `Streamer` interface and operates on `float64`s).
Author
Owner
Copy link

I got beep to run at speeds in the same ballpark as SoX by rewriting my dumb code that calls it, so it's probably not necessary to rewrite it to try to make it faster for int16 samples.

Weirdly, beep_1 actually sounds better than beep_3 or beep_6 in at least some upsampling cases: in honey_bee-22.mp3, it doesn't have high-frequency scratching sounds on the drumbeats, but the higher-quality settings do. Quality levels 2, 16, and even 63 have the problem too.

Otherwise, I still can't really hear any differences between beep_1 and beep_6, so I think I'll just go with beep_1.

I got beep to run at speeds in the same ballpark as SoX by rewriting my dumb code that calls it, so it's probably not necessary to rewrite it to try to make it faster for `int16` samples. Weirdly, `beep_1` actually sounds better than `beep_3` or `beep_6` in at least some upsampling cases: in `honey_bee-22.mp3`, it doesn't have high-frequency scratching sounds on the drumbeats, but the higher-quality settings do. Quality levels 2, 16, and even 63 have the problem too. Otherwise, I still can't really hear any differences between `beep_1` and `beep_6`, so I think I'll just go with `beep_1`.
Sign in to join this conversation.
No Branch/Tag specified
main
headless
picture
datastore
No results found.
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
derat/nup#141
Reference in a new issue
derat/nup
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?