ref: 7e0179bad8fc63294696a465e1583be5c08b9417
parent: c7ec663a0bf490169a910a3bba6ff5ba094a4b4e
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sat Oct 15 15:01:46 EDT 2022
zuke: basic replay gain support
--- a/sys/man/1/zuke
+++ b/sys/man/1/zuke
@@ -130,6 +130,9 @@
.B r
Toggle ``repeat one''.
.TP
+.B g
+Switch between no gain, track gain, and album gain applied.
+.TP
.B s
Toggle ``shuffle''.
.TP
--- a/sys/src/cmd/audio/zuke/mkplist.c
+++ b/sys/src/cmd/audio/zuke/mkplist.c
@@ -122,6 +122,16 @@
aux->imagereader = f != nil;
}
break;
+ case Ttrackgain:
+ aux->rgtrack = atof(v);
+ if(strncmp(k, "R128_", 5) == 0)
+ aux->rgtrack /= 256.0;
+ break;
+ case Talbumgain:
+ aux->rgalbum = atof(v);
+ if(strncmp(k, "R128_", 5) == 0)
+ aux->rgalbum /= 256.0;
+ break;
}
}
@@ -393,8 +403,8 @@
if(icyfill(m) != 0){
fprint(2, "%s: %r\n", argv[i]);
free(m);
- }
- sendp(cmeta, m);
+ }else
+ sendp(cmeta, m);
}else{
if(argv[i][0] == '/')
dir = strdup(argv[i]);
--- a/sys/src/cmd/audio/zuke/plist.c
+++ b/sys/src/cmd/audio/zuke/plist.c
@@ -21,6 +21,10 @@
Bprint(b, "%c %s\n", Ptrack, m->track);
if(m->duration > 0)
Bprint(b, "%c %llud\n", Pduration, m->duration);
+ if(m->rgtrack != 0.0)
+ Bprint(b, "%c %g\n", Prgtrack, m->rgtrack);
+ if(m->rgalbum != 0.0)
+ Bprint(b, "%c %g\n", Prgalbum, m->rgalbum);
if(m->imagesize > 0)
Bprint(b, "%c %d %d %d %s\n", Pimage, m->imageoffset, m->imagesize, m->imagereader, m->imagefmt);
Bprint(b, "\n");
--- a/sys/src/cmd/audio/zuke/plist.h
+++ b/sys/src/cmd/audio/zuke/plist.h
@@ -16,11 +16,13 @@
Pbasename= 'b',
Pdate= 'd',
Pduration= 'D',
+ Pfilefmt= 'f',
Pimage= 'i',
Ptitle= 't',
Ptrack= 'T',
Ppath= 'p',
- Pfilefmt= 'f',
+ Prgtrack= 'r',
+ Prgalbum= 'R',
/* unused */
Pchannels= 'c',
@@ -42,6 +44,8 @@
char *basename;
char *imagefmt;
char *filefmt;
+ double rgtrack;
+ double rgalbum;
uvlong duration;
int numartist;
int imageoffset;
--- a/sys/src/cmd/audio/zuke/zuke.c
+++ b/sys/src/cmd/audio/zuke/zuke.c
@@ -24,6 +24,11 @@
Ctoggle,
Cseekrel,
+ Rgdisabled = 0,
+ Rgtrack,
+ Rgalbum,
+ Numrg,
+
Everror = 1,
Evready,
@@ -57,6 +62,7 @@
Channel *ev;
Channel *img;
double seek;
+ double gain;
int pcur;
};
@@ -72,7 +78,7 @@
static int debug;
static int audio = -1;
-static int volume;
+static int volume, rg;
static int pnotifies;
static Playlist *pl;
static Player *playernext;
@@ -276,10 +282,11 @@
Image *col;
/* seekbar playback/duration text */
- i = snprint(tmp, sizeof(tmp), "%s%s%s",
+ i = snprint(tmp, sizeof(tmp), "%s%s%s%s",
+ rg ? (rg == Rgalbum ? "ᴬ" : "ᵀ") : "",
repeatone ? "¹" : "",
shuffle != nil ? "∫" : "",
- (repeatone || shuffle != nil) ? " " : ""
+ (rg || repeatone || shuffle != nil) ? " " : ""
);
msec = 0;
if(pcurplaying >= 0){
@@ -605,6 +612,20 @@
static void playerthread(void *player_);
+static void
+setgain(Player *player)
+{
+ if(player == nil)
+ return;
+ if(rg == Rgdisabled)
+ player->gain = 0.0;
+ if(rg == Rgtrack)
+ player->gain = getmeta(player->pcur)->rgtrack;
+ else if(rg == Rgalbum)
+ player->gain = getmeta(player->pcur)->rgalbum;
+ player->gain = pow(10.0, player->gain/20.0);
+}
+
static Player *
newplayer(int pcur, int loadnext)
{
@@ -624,6 +645,7 @@
player->ctl = chancreate(sizeof(ulong), 0);
player->ev = chancreate(sizeof(ulong), 0);
player->pcur = pcur;
+ setgain(player);
threadcreate(playerthread, player, 32768);
if(getmeta(pcur)->filefmt[0] && playerret(player) < 0)
@@ -637,6 +659,18 @@
}
static void
+gain(double g, char *buf, long n)
+{
+ s16int *f;
+
+ if(g != 1.0)
+ for(f = (s16int*)buf; n >= 4; n -= 4){
+ *f = g * *f++;
+ *f = g * *f++;
+ }
+}
+
+static void
playerthread(void *player_)
{
char *buf, cmd[64], seekpos[12], *fmt;
@@ -718,6 +752,7 @@
if(n < 1)
goto next;
audioon();
+ gain(player->gain, buf, n);
boffset = iowrite(io, audio, buf, n);
noinit = 1;
}
@@ -767,6 +802,7 @@
boffset += n;
byteswritten = boffset;
audioon();
+ gain(player->gain, buf, n);
iowrite(io, audio, buf, n);
if(trycoverload){
trycoverload = 0;
@@ -930,6 +966,8 @@
case Pdate: m->date = s; break;
case Ptitle: m->title = s; break;
case Ptrack: m->track = s; break;
+ case Prgtrack: m->rgtrack = atof(s); break;
+ case Prgalbum: m->rgalbum = atof(s); break;
case Ppath:
m->path = s;
m->basename = (b = utfrrune(s, '/')) == nil ? s : b+1;
@@ -1502,6 +1540,12 @@
freeimage(cover);
cover = nil;
full = 1;
+ break;
+ case 'g':
+ rg = (rg+1) % Numrg;
+ setgain(playercurr);
+ setgain(playernext);
+ redraw(0);
break;
case 's':
toggleshuffle();