Skip to content

Commit 210f72a

Browse files
committed
ref
1 parent d332a66 commit 210f72a

File tree

31 files changed

+306
-200
lines changed

31 files changed

+306
-200
lines changed

android/phiola/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ android {
88
applicationId "com.github.stsaz.phiola"
99
minSdkVersion 16
1010
targetSdk 33
11-
versionCode 20702
12-
versionName '2.7-beta2'
11+
versionCode 20703
12+
versionName '2.7-beta3'
1313
}
1414

1515
buildFeatures {

android/phiola/src/main/java/com/github/stsaz/phiola/Phiola.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ to the index within its parent (not filtered) list */
183183
QC_AUTO_NORM = 0x10,
184184
QC_RG_NORM = 0x20;
185185
native void quConf(int mask, int val);
186+
186187
static final int
187188
QC_EQUALIZER = 1;
188189
native void quConfStr(int setting, String val);

doc/arch/arch.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,51 @@ Example:
229229
aac-decode: decoded 2048 samples @2048 aot:29 rate:44100 chan:2 br:3789
230230

231231

232+
## Track Metadata
233+
234+
* There are 3 metadata sources: user, .cue, media file.
235+
User metadata may be set when converting or recording, and it has the highest priority (i.e. the values from .cue or media file are overwritten).
236+
* Queue-agent filter combines all metadata into one array; UI reads it to display the info on currently playing track; while converting, media-writer filter copies the unique entries from it into output file.
237+
* At any time UI thread may read or write the metadata associated with playlist rows.
238+
Normally, this metadata is updated by queue-agent filter in a worker thread when the file is being played back (or a new logical stream begins); for CUE entries the metadata *is not* updated.
239+
240+
```C
241+
user:
242+
q->conf.tconf.meta = ... <- e.g. `convert -m title=value`
243+
244+
-> cue.read
245+
qe->meta = ... <- e.g. `TITLE value`
246+
qe->meta_priority = 1
247+
248+
-> q
249+
250+
-> fmt.read:
251+
if (new stream)
252+
t->meta = ... <- e.g. `title=value` from .opus
253+
t->meta_changed = 1
254+
255+
-> icy.read:
256+
if (new meta)
257+
t->meta = ...
258+
t->meta_changed = 1
259+
260+
-> q.agent:
261+
if (qe->meta_priority)
262+
t->meta << qe->meta
263+
if (t->meta_changed && !qe->meta_priority)
264+
qe->meta = t->meta
265+
t->meta << q->conf.tconf.meta
266+
267+
-> ui:
268+
if (t->meta_changed)
269+
read t->meta
270+
271+
-> fmt.write
272+
output <- unique t->meta
273+
274+
ui: read qe->meta
275+
```
276+
232277
## GUI Playlist Synchronization
233278

234279
```C

src/adev/pulse-play.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ static int pulse_create(audio_out *a, phi_track *t)
104104
mod->dev_idx = a->dev_idx;
105105

106106
fin:
107-
dbglog(t, "%s buffer %ums, %uHz"
107+
dbglog(t, "%s buffer %ums, %s/%uHz"
108108
, reused ? "reused" : "opened", mod->buffer_length_msec
109-
, mod->fmt.rate);
109+
, phi_af_name(mod->fmt.format), mod->fmt.rate);
110110

111111
mod->usedby = a;
112112
t->oaudio.adev_ctx = a;

src/core/queue-entry.h

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -136,25 +136,6 @@ static void qe_close(void *f, phi_track *t)
136136
if (e->trk == t) {
137137
e->trk = NULL;
138138

139-
if (e->q && !e->q->conf.conversion && !e->pub.meta_priority) {
140-
int mod = (META_LEN(&e->pub.meta) || META_LEN(&t->meta)); // empty meta == not modified
141-
if (META_LEN(&t->meta)) {
142-
fflock_lock((fflock*)&e->pub.lock); // UI thread may read or write `conf.meta` at this moment
143-
core->metaif->destroy(&e->pub.meta);
144-
e->pub.meta = t->meta; // Remember the tags we read from file in this track
145-
fflock_unlock((fflock*)&e->pub.lock);
146-
meta_zero(&t->meta);
147-
}
148-
149-
if (t->audio.total != ~0ULL && t->audio.format.rate) {
150-
uint64 duration_msec = samples_to_msec(t->audio.total, t->audio.format.rate);
151-
e->pub.length_sec = duration_msec / 1000;
152-
}
153-
154-
if (mod)
155-
q_modified(e->q);
156-
}
157-
158139
if (e->expand || t->meta_reading)
159140
core->track->stop(t);
160141
}
@@ -193,6 +174,45 @@ static const phi_filter phi_queue_guard = {
193174
"queue-guard"
194175
};
195176

177+
178+
static int qagt_process(void *f, phi_track *t)
179+
{
180+
struct q_entry *e = t->qent;
181+
182+
// 't->meta' currently contains the metadata read from file
183+
184+
if (META_LEN(&e->pub.meta) && e->pub.meta_priority)
185+
core->metaif->copy(&t->meta, &e->pub.meta, PHI_META_REPLACE); // Copy tags from .cue, e.g. `TITLE value`
186+
187+
if (t->meta_changed && !e->pub.meta_priority) {
188+
189+
if (t->audio.total != ~0ULL && t->audio.format.rate)
190+
e->pub.length_sec = samples_to_msec(t->audio.total, t->audio.format.rate) / 1000;
191+
192+
if (META_LEN(&e->pub.meta) || META_LEN(&t->meta)) { // empty meta == not modified
193+
fflock_lock((fflock*)&e->pub.lock); // UI thread may read or write `meta` at this moment
194+
core->metaif->destroy(&e->pub.meta);
195+
core->metaif->copy(&e->pub.meta, &t->meta, 0); // Remember the tags we read from file
196+
fflock_unlock((fflock*)&e->pub.lock);
197+
q_modified(e->q);
198+
}
199+
}
200+
201+
if (META_LEN(&e->q->conf.tconf.meta))
202+
core->metaif->copy(&t->meta, &e->q->conf.tconf.meta, PHI_META_REPLACE); // Copy tags from user, e.g. `convert -m title=...`
203+
204+
// 't->meta' contains the aggregated metadata from user + from .cue + from file
205+
206+
t->data_out = t->data_in;
207+
return !(t->chain_flags & PHI_FFIRST) ? PHI_OK : PHI_DONE;
208+
}
209+
210+
static const phi_filter queue_agent = {
211+
NULL, NULL, qagt_process,
212+
"queue-agent"
213+
};
214+
215+
196216
static int qe_play(struct q_entry *e)
197217
{
198218
if (e->expand) {
@@ -215,13 +235,15 @@ static int qe_play(struct q_entry *e)
215235
&& !track->filter(t, e->q->conf.first_filter, 0))
216236
goto err;
217237

238+
track->filter(t, &phi_queue_guard, 0);
239+
track->filter(t, core->mod("core.auto-input"), 0);
240+
218241
if (e->q->conf.conversion) {
219-
if (!track->filter(t, &phi_queue_guard, 0)
220-
|| !track->filter(t, core->mod("core.auto-input"), 0)
221-
|| !track->filter(t, core->mod("format.detect"), 0)
242+
if (!track->filter(t, core->mod("format.detect"), 0)
222243
|| !track->filter(t, core->mod("afilter.until"), 0)
223244
|| (c.afilter.danorm
224245
&& !track->filter(t, core->mod("af-danorm.f"), 0))
246+
|| !track->filter(t, &queue_agent, 0)
225247
|| !track->filter(t, ui_if, 0)
226248
|| (c.afilter.gain_db
227249
&& !track->filter(t, core->mod("afilter.gain"), 0))
@@ -232,10 +254,9 @@ static int qe_play(struct q_entry *e)
232254
t->output.allow_async = 1;
233255

234256
} else if (e->q->conf.analyze) {
235-
if (!track->filter(t, &phi_queue_guard, 0)
236-
|| !track->filter(t, core->mod("core.auto-input"), 0)
237-
|| !track->filter(t, core->mod("format.detect"), 0)
257+
if (!track->filter(t, core->mod("format.detect"), 0)
238258
|| !track->filter(t, core->mod("afilter.until"), 0)
259+
|| !track->filter(t, &queue_agent, 0)
239260
|| !track->filter(t, ui_if, 0)
240261
|| ((c.afilter.peaks_info
241262
|| c.afilter.loudness_summary)
@@ -247,12 +268,11 @@ static int qe_play(struct q_entry *e)
247268
goto err;
248269

249270
} else {
250-
if (!track->filter(t, &phi_queue_guard, 0)
251-
|| !track->filter(t, core->mod("core.auto-input"), 0)
252-
|| (c.tee && !c.tee_output
271+
if ((c.tee && !c.tee_output
253272
&& !track->filter(t, core->mod("core.tee"), 0))
254273
|| !track->filter(t, core->mod("format.detect"), 0)
255274
|| !track->filter(t, core->mod("afilter.until"), 0)
275+
|| !track->filter(t, &queue_agent, 0)
256276
|| !track->filter(t, ui_if, 0)
257277
|| (c.afilter.rg_normalizer
258278
&& !track->filter(t, core->mod("afilter.rg-norm"), 0))
@@ -270,11 +290,6 @@ static int qe_play(struct q_entry *e)
270290
goto err;
271291
}
272292

273-
if (META_LEN(&e->q->conf.tconf.meta))
274-
core->metaif->copy(&t->meta, &e->q->conf.tconf.meta, 0); // from user
275-
if (META_LEN(&e->pub.meta) && e->pub.meta_priority)
276-
core->metaif->copy(&t->meta, &e->pub.meta, (META_LEN(&e->q->conf.tconf.meta)) ? PHI_META_UNIQUE : 0); // from .cue
277-
278293
e->trk = t;
279294
e->used++;
280295
e->q->active_n++;

src/exe/gui.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,20 @@ static int gui_help()
55
{
66
help_info_write("\
77
Show graphical interface:\n\
8-
`phiola gui` [INPUT...]\n\
8+
`phiola gui` [OPTIONS] [INPUT...]\n\
99
\n\
1010
INPUT File name, directory or URL\n\
11+
\n\
12+
Options:\n\
13+
`-multi` Multi-window mode\n\
1114
");
1215
x->exit_code = 0;
1316
return 1;
1417
}
1518

1619
struct cmd_gui {
1720
ffvec input; // ffstr[]
21+
u_char multi_window;
1822
};
1923

2024
static int gui_input(struct cmd_gui *g, ffstr s)
@@ -30,8 +34,9 @@ static void gui_log_ctl(uint flags)
3034
x->log.func = NULL;
3135
}
3236

33-
static int gui_action(struct cmd_gui *g)
37+
static int gui_single_mode(struct cmd_gui *g)
3438
{
39+
int rc = 1;
3540
const phi_remote_cl_if *rcl = x->core->mod("remote.client");
3641
ffvec inz = {};
3742
ffstr *it;
@@ -45,13 +50,25 @@ static int gui_action(struct cmd_gui *g)
4550

4651
const phi_remote_sv_if *rsv = x->core->mod("remote.server");
4752
rsv->start("gui");
53+
rc = 0;
54+
55+
end:
56+
ffvec_free(&inz);
57+
return rc;
58+
}
59+
60+
static int gui_action(struct cmd_gui *g)
61+
{
62+
if (!g->multi_window && gui_single_mode(g))
63+
goto end;
4864

4965
struct phi_queue_conf qc = {
5066
.first_filter = &phi_guard_gui,
5167
.ui_module = "gui.track",
5268
};
5369
x->queue->create(&qc);
5470

71+
ffstr *it;
5572
FFSLICE_WALK(&g->input, it) {
5673
struct phi_queue_entry qe = {
5774
.url = it->ptr,
@@ -73,7 +90,6 @@ static int gui_action(struct cmd_gui *g)
7390
}
7491

7592
end:
76-
ffvec_free(&inz);
7793
x->exit_code = 0;
7894
return 0;
7995
}
@@ -83,11 +99,14 @@ static int gui_open()
8399
return 0;
84100
}
85101

102+
#define O(m) (void*)FF_OFF(struct cmd_gui, m)
86103
static const struct ffarg cmd_gui[] = {
87104
{ "-help", 0, gui_help },
105+
{ "-multi", '1', O(multi_window) },
88106
{ "\0\1", 'S', gui_input },
89107
{ "", 0, gui_open },
90108
};
109+
#undef O
91110

92111
static void cmd_gui_free(struct cmd_gui *g)
93112
{

src/format/reader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ static int fmtr_process(struct fmt_rd *f, phi_track *t)
216216
ffmem_zero_obj(&res);
217217
switch (avpk_read(&f->rd, in, &res)) {
218218
case AVPK_HEADER: {
219+
t->meta_changed = 1;
219220
if (f->sample_rate) {
220221
if (!(t->audio.format.rate == res.hdr.sample_rate
221222
&& t->audio.format.channels == res.hdr.channels)) {
@@ -225,7 +226,6 @@ static int fmtr_process(struct fmt_rd *f, phi_track *t)
225226

226227
dbglog(t, "new logical stream");
227228
core->metaif->destroy(&t->meta);
228-
t->meta_changed = 1;
229229
t->audio.ogg_reset = 1;
230230
break;
231231
}

src/gui/about.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ static void wabout_action(ffui_window *wnd, int id)
3030

3131
void wabout_init()
3232
{
33-
gui_wabout *a = ffmem_new(gui_wabout);
33+
gui_wabout *a = gui_allocT(gui_wabout);
3434
a->wnd.hide_on_close = 1;
3535
a->wnd.on_action = wabout_action;
3636
gg->wabout = a;

src/gui/convert.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ static void wconvert_action(ffui_window *wnd, int id)
279279

280280
void wconvert_init()
281281
{
282-
gui_wconvert *c = ffmem_new(gui_wconvert);
282+
gui_wconvert *c = gui_allocT(gui_wconvert);
283283
c->wnd.hide_on_close = 1;
284284
c->wnd.on_action = wconvert_action;
285285
c->conf_mp3q = ~0U;

src/gui/goto.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void wgoto_show(uint pos)
5050

5151
void wgoto_init()
5252
{
53-
gui_wgoto *g = ffmem_new(gui_wgoto);
53+
gui_wgoto *g = gui_allocT(gui_wgoto);
5454
gg->wgoto = g;
5555
g->wnd.hide_on_close = 1;
5656
g->wnd.on_action = wgoto_action;

0 commit comments

Comments
 (0)