sentriz/gonic 520
music streaming server / subsonic server API implementation
🐟🐍 a fish plugin that automatically activates the pipenv subshell
sentriz/betanin 111
beets based mitm of your torrent client and music player
a python 3.6 facebook/telegram bot
my dotfiles
a python 3+ script for downloading, renaming, and tagging albums from Bandcamp
simple home server status page, compose and traefik aware
sentriz/hexchat_python_addons 5
a python 3+ collection of HexChat addons
wayland clipboard manager
wayland clipboard manager
push eventsentriz/dotfiles
commit sha ab8bf377a2b268aeb4f2c6c31f50cb32f33e7683
docs: add daw
push time in a day
push eventsentriz/dotfiles
commit sha e8ad578632072df7096b334aa5ebd629a57d2f5f
fish: add more VST3_PATH
commit sha ea558881c7c8d43e2482f739e6a6bf519a8618ef
block_playing: show browser playback
commit sha fd9d588f83d498fcdd5eac46078fd33fee152789
docs: add daw
push time in a day
issue commentsentriz/gonic
support for prometheus-style metrics
Yeah cool idea. Would the output of using expvar be suitable?
https://pkg.go.dev/expvar
This would be then /debug/vars instead of /metrics
comment created time in 4 days
startedtamland/airsonic-refix
started time in 5 days
startedRustAudio/rust-lv2
started time in 7 days
push eventsentriz/standardnotes-extensions
commit sha 19df1d6f80f03fc41e5604d1bb66821ca8fa6b67
add new extensions Co-authored-by: Eric Pierce <[email protected]>
push time in 13 days
push eventsentriz/dotfiles
commit sha 6401670dbb1d852e05a5491371aaa7807286f943
fish: add more VST_PATH/VST3_PATH https://developer.steinberg.help/display/VST/Plug-in+Locations#PluginLocations-FortheWindowsplatform https://developer.steinberg.help/display/VST/Plug-in+Locations#PluginLocations-ForLinuxplatform
commit sha 73f938a34da1020c48a6344ddcb1f2c6ebc067d3
sway: make qjackctl floating
push time in 15 days
push eventsentriz/dotfiles
commit sha c7757e49bb3378de218ce74da1abfe800b563656
fish: add more VST_PATH/VST3_PATH https://developer.steinberg.help/display/VST/Plug-in+Locations#PluginLocations-FortheWindowsplatform https://developer.steinberg.help/display/VST/Plug-in+Locations#PluginLocations-ForLinuxplatform
commit sha 6a4ed78935eca6b33d8e39d35aef0139d7c8349d
sway: make qjackctl floating
push time in 15 days
push eventsentriz/dotfiles
commit sha 2fae2a4901ec2b5b698dc2b134ba3215bc54c089
vim: update gopls_organise_imports
commit sha 07baf95a5a0dc9050eff6a29bc0b538ebbf112bd
fish: set VST_PATH to use yabridge
commit sha 9b6c07a79df6943299216ea1ac0144f33ec3c554
sway: remove wl-gammactld
commit sha 8c8ab4fcf1ff7076bc7e1f54bcd955fd1bbbf181
fish: escape nvim args in __super_vim
commit sha c0d454d14e4fb65b5c4c24fbb62a8b5c8e202fed
fish: configure more programs to use XDG dirs
commit sha 9046b3088508232c99a7483996195f8aff9d02c3
flatpak: setup bottles and insomnia
commit sha 5b68357614ee637ebaa2c7a2db4f0a5b601eb97d
fish: add more VST_PATH/VST3_PATH https://developer.steinberg.help/display/VST/Plug-in+Locations#PluginLocations-FortheWindowsplatform https://developer.steinberg.help/display/VST/Plug-in+Locations#PluginLocations-ForLinuxplatform
push time in 23 days
push eventsentriz/cliphist
commit sha c1457991f6b32f75c8af065627cf7d2820cf1d6b
add delete command
push time in 24 days
push eventsentriz/nvim-lsp-compose
push time in a month
startedrobbert-vdh/yabridge
started time in a month
push eventsentriz/gonic
commit sha ccc0e3c58d9fb1975bc0bdcf4f87829e9f705b74
fix(build): add zlib
push time in a month
push eventsentriz/gonic
commit sha 4d5c245872680dddce67c0a45afeb4346b6ba2e3
fix(build): add zlib
push time in a month
startedtummychow/git-absorb
started time in a month
push eventsentriz/gonic
commit sha c0ca6aaf0337a23b3f1d2a867884afe89fd4a281
fix(scanner): spawn interval scans in a goroutine this way, if the average scan takes longer than the tick interval, the ticker will be unblocked and scans won't stack on top of each other related #63
push time in a month
Pull request review commentsentriz/gonic
feat(encode): rework encoding profiles to use true VBR and add optional upsample support
func fileExists(filename string) bool { func Profiles() map[string]Profile { return map[string]Profile{- "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false},- "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true},- "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "constrained"}, false},- "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "constrained"}, true},+ "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false, false, false},+ "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true, false, false},+ "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, false, false, false},+ "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, false, false},+ "opus_car": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, true, true},
I would be in favour of this :+1: seems nice a simple
though if it were a real yaml file, I'd be hesitant to add a second configuration file to gonic. maybe an idea could be to store the profiles as structs first? then later to make them configurable my the web UI. this would help with #121
comment created time in a month
Pull request review commentsentriz/gonic
feat(encode): rework encoding profiles to use true VBR and add optional upsample support
func fileExists(filename string) bool { func Profiles() map[string]Profile { return map[string]Profile{- "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false},- "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true},- "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "constrained"}, false},- "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "constrained"}, true},+ "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false, false, false},+ "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true, false, false},+ "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, false, false, false},+ "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, false, false},+ "opus_car": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, true, true},
ah good shout, thanks! then in that case, as we want to add more functionality to the ffmpegCommand function, it might get a bit complicated in future. what about a "functional options" pattern - where we can centralise the the different behaviours of each profile - and possibly make adding future functionality easier?
it could look something like this

https://termbin.com/p7ee
(not at all tested, but just wondering if you like this idea)
comment created time in a month
Pull request review commentsentriz/gonic
feat(encode): rework encoding profiles to use true VBR and add optional upsample support
func fileExists(filename string) bool { func Profiles() map[string]Profile { return map[string]Profile{- "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false},- "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true},- "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "constrained"}, false},- "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "constrained"}, true},+ "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false, false, false},+ "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true, false, false},+ "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, false, false, false},+ "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, false, false},+ "opus_car": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, true, true},
yeah the enum is interesting. do you think something like this could work?
diff --git a/server/encode/encode.go b/server/encode/encode.go
index 550b6f7..58d0a0b 100644
--- a/server/encode/encode.go
+++ b/server/encode/encode.go
@@ -20,13 +20,20 @@ const (
ffmpeg = "ffmpeg"
)
+type ReplayGain int
+
+const (
+ RGNone ReplayGain = iota
+ RGForce
+ RGHigh
+)
+
type Profile struct {
- Format string
- Bitrate int
- ffmpegOptions []string
- forceRG bool
- hiGainRG bool
- upsample bool
+ Format string
+ Bitrate int
+ Options []string
+ ReplayGain ReplayGain
+ Upsample bool
}
func fileExists(filename string) bool {
@@ -39,11 +46,35 @@ func fileExists(filename string) bool {
func Profiles() map[string]Profile {
return map[string]Profile{
- "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false, false, false},
- "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true, false, false},
- "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, false, false, false},
- "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, false, false},
- "opus_car": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, true, true},
+ "mp3": {
+ Format: "mp3",
+ Bitrate: 128,
+ Options: []string{"-c:a", "libmp3lame"},
+ },
+ "mp3_rg": {
+ Format: "mp3",
+ Bitrate: 128,
+ Options: []string{"-c:a", "libmp3lame"},
+ ReplayGain: RGForce,
+ },
+ "opus": {
+ Format: "opus",
+ Bitrate: 96,
+ Options: []string{"-c:a", "libopus", "-vbr", "on"},
+ },
+ "opus_rg": {
+ Format: "opus",
+ Bitrate: 96,
+ Options: []string{"-c:a", "libopus", "-vbr", "on"},
+ ReplayGain: RGForce,
+ },
+ "opus_car": {
+ Format: "opus",
+ Bitrate: 96,
+ Options: []string{"-c:a", "libopus", "-vbr", "on"},
+ ReplayGain: RGHigh,
+ Upsample: true,
+ },
}
}
@@ -96,35 +127,34 @@ func ffmpegCommand(filePath string, profile Profile) (*exec.Cmd, error) {
"-vn",
"-b:a", fmt.Sprintf("%dk", profile.Bitrate),
}
- args = append(args, profile.ffmpegOptions...)
- if profile.forceRG {
- aBaselineGain := 6
- if profile.hiGainRG {
- // This baseline gain results in final track being +3~5dB louder
- // than Foobar2000's default ReplayGain target volume.
- // This makes it easier to listen to music in a car, where all other
- // sources are usually ten thousand times louder than RG-adjusted music.
- // -- @spijet
- aBaselineGain = 15
- }
- aFilters := []string{
- fmt.Sprintf("volume=replaygain=track:replaygain_preamp=%ddB:replaygain_noclip=0", aBaselineGain),
- "alimiter=level=disabled",
- "asidedata=mode=delete:type=REPLAYGAIN",
- }
+ args = append(args, profile.Options...)
- // opus always forces output to 48kHz sampling rate, but we can still use upsampling
- // to increase RG and alimiter's peak limiting precision, which is desirable in some
- // cases. ffmpeg's `soxr` resampler is quite fast on x86-64: it takes around 5 seconds
- // on my Ryzen 3600 to transcode an 8-minute FLAC with 2x upsample and RG applied.
+ var aFilters []string
+ // opus always forces output to 48kHz sampling rate, but we can still use upsampling
+ // to increase RG and alimiter's peak limiting precision, which is desirable in some
+ // cases. ffmpeg's `soxr` resampler is quite fast on x86-64: it takes around 5 seconds
+ // on my Ryzen 3600 to transcode an 8-minute FLAC with 2x upsample and RG applied.
+ // -- @spijet
+ if profile.Upsample {
+ aFilters = append(aFilters, "aresample=96000:resampler=soxr")
+ }
+
+ switch profile.ReplayGain {
+ case RGForce:
+ aFilters = append(aFilters, ffmpegPreamp(6)...)
+ case RGHigh:
+ // This baseline gain results in final track being +3~5dB louder
+ // than Foobar2000's default ReplayGain target volume.
+ // This makes it easier to listen to music in a car, where all other
+ // sources are usually ten thousand times louder than RG-adjusted music.
// -- @spijet
- if profile.upsample {
- aFilters = append([]string{"aresample=96000:resampler=soxr"}, aFilters...)
- }
- aFilterString := strings.Join(aFilters, ", ")
+ aFilters = append(aFilters, ffmpegPreamp(15)...)
+ }
+
+ if len(aFilters) > 0 {
args = append(args,
// set up replaygain processing
- "-af", aFilterString,
+ "-af", strings.Join(aFilters, ", "),
// drop redundant replaygain tags
"-metadata", "replaygain_album_gain=",
"-metadata", "replaygain_album_peak=",
@@ -134,6 +164,7 @@ func ffmpegCommand(filePath string, profile Profile) (*exec.Cmd, error) {
"-metadata", "r128_track_gain=",
)
}
+
args = append(args, "-f", profile.Format, "-")
ffmpegPath, err := exec.LookPath(ffmpeg)
if err != nil {
@@ -144,6 +175,14 @@ func ffmpegCommand(filePath string, profile Profile) (*exec.Cmd, error) {
// but please do let me know if you see otherwise
}
+func ffmpegPreamp(dB int) []string {
+ return []string{
+ fmt.Sprintf("volume=replaygain=track:replaygain_preamp=%ddB:replaygain_noclip=0", dB),
+ "alimiter=level=disabled",
+ "asidedata=mode=delete:type=REPLAYGAIN",
+ }
+}
+
func encode(out io.Writer, trackPath, cachePath string, profile Profile) error {
// prepare cache part file path
cachePartPath := fmt.Sprintf("%s.part", cachePath)

comment created time in a month
Pull request review commentsentriz/gonic
feat(encode): rework encoding profiles to use true VBR and add optional upsample support
func ffmpegCommand(filePath string, profile Profile) (*exec.Cmd, error) { } args = append(args, profile.ffmpegOptions...) if profile.forceRG {+ aBaselineGain := 6+ if profile.hiGainRG {+ // This baseline gain results in final track being +3~5dB louder+ // than Foobar2000's default ReplayGain target volume.+ // This makes it easier to listen to music in a car, where all other+ // sources are usually ten thousand times louder than RG-adjusted music.+ // -- @spijet+ aBaselineGain = 15+ }+ aFilters := []string{+ fmt.Sprintf("volume=replaygain=track:replaygain_preamp=%ddB:replaygain_noclip=0", aBaselineGain),+ "alimiter=level=disabled",+ "asidedata=mode=delete:type=REPLAYGAIN",+ }++ // opus always forces output to 48kHz sampling rate, but we can still use upsampling+ // to increase RG and alimiter's peak limiting precision, which is desirable in some+ // cases. ffmpeg's `soxr` resampler is quite fast on x86-64: it takes around 5 seconds+ // on my Ryzen 3600 to transcode an 8-minute FLAC with 2x upsample and RG applied.+ // -- @spijet+ if profile.upsample {+ aFilters = append([]string{"aresample=96000:resampler=soxr"}, aFilters...)+ }
Gotcha thanks 👍
comment created time in a month
Pull request review commentsentriz/gonic
feat(encode): rework encoding profiles to use true VBR and add optional upsample support
func ffmpegCommand(filePath string, profile Profile) (*exec.Cmd, error) { } args = append(args, profile.ffmpegOptions...) if profile.forceRG {+ aBaselineGain := 6+ if profile.hiGainRG {+ // This baseline gain results in final track being +3~5dB louder+ // than Foobar2000's default ReplayGain target volume.+ // This makes it easier to listen to music in a car, where all other+ // sources are usually ten thousand times louder than RG-adjusted music.+ // -- @spijet+ aBaselineGain = 15+ }+ aFilters := []string{+ fmt.Sprintf("volume=replaygain=track:replaygain_preamp=%ddB:replaygain_noclip=0", aBaselineGain),+ "alimiter=level=disabled",+ "asidedata=mode=delete:type=REPLAYGAIN",+ }++ // opus always forces output to 48kHz sampling rate, but we can still use upsampling+ // to increase RG and alimiter's peak limiting precision, which is desirable in some+ // cases. ffmpeg's `soxr` resampler is quite fast on x86-64: it takes around 5 seconds+ // on my Ryzen 3600 to transcode an 8-minute FLAC with 2x upsample and RG applied.+ // -- @spijet+ if profile.upsample {+ aFilters = append([]string{"aresample=96000:resampler=soxr"}, aFilters...)+ }
nit, if the order doesn't matter here this can be a bit simpler
if profile.upsample {
aFilters = append(aFilters, "aresample=96000:resampler=soxr")
}
comment created time in a month
Pull request review commentsentriz/gonic
feat(encode): rework encoding profiles to use true VBR and add optional upsample support
func fileExists(filename string) bool { func Profiles() map[string]Profile { return map[string]Profile{- "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false},- "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true},- "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "constrained"}, false},- "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "constrained"}, true},+ "mp3": {"mp3", 128, []string{"-c:a", "libmp3lame"}, false, false, false},+ "mp3_rg": {"mp3", 128, []string{"-c:a", "libmp3lame"}, true, false, false},+ "opus": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, false, false, false},+ "opus_rg": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, false, false},+ "opus_car": {"opus", 96, []string{"-c:a", "libopus", "-vbr", "on"}, true, true, true},
now with all these booleans, it's little bit hard to know what's going on with for example false, false, false
maybe we could add some field names, and use go's false bool zero-value?
"mp3": {
Format: "mp3",
Bitrate: 128,
ffmpegOptions: []string{"-c:a", "libmp3lame"},
},
"mp3_rg": {
Format: "mp3",
Bitrate: 128,
ffmpegOptions: []string{"-c:a", "libmp3lame"},
forceRG: true,
},
"opus": {
Format: "opus",
Bitrate: 96,
ffmpegOptions: []string{"-c:a", "libopus", "-vbr", "on"},
},
"opus_rg": {
Format: "opus",
Bitrate: 96,
ffmpegOptions: []string{"-c:a", "libopus", "-vbr", "on"},
forceRG: true,
},
"opus_car": {
Format: "opus",
Bitrate: 96,
ffmpegOptions: []string{"-c:a", "libopus", "-vbr", "on"},
forceRG: true,
hiGainRG: true,
upsample: true,
},
comment created time in a month
pull request commentsentriz/gonic
feat(encode): rework encoding profiles to use true VBR and add optional upsample support
yep I'd say this can be rebased now :+1:
comment created time in a month
pull request commentsentriz/gonic
Add MIME-type and content length hints to cache handlers
cool thanks! :)
comment created time in a month