improve midi visualizer
This commit is contained in:
parent
93eb756d3c
commit
1e5b2995af
1 changed files with 92 additions and 127 deletions
|
@ -22,6 +22,7 @@ import client.gui.element.PressType;
|
|||
import client.renderer.Drawing;
|
||||
import common.log.Log;
|
||||
import common.rng.Random;
|
||||
import common.util.Color;
|
||||
|
||||
public class GuiPlayer extends GuiList<GuiPlayer.SongEntry> {
|
||||
protected class SongEntry implements ListEntry {
|
||||
|
@ -43,6 +44,7 @@ public class GuiPlayer extends GuiList<GuiPlayer.SongEntry> {
|
|||
|
||||
private class Visualizer extends Element {
|
||||
private static final int[] plr_waveforms = {0xff00ff00, 0xffff0000, 0xff0000ff, 0xff00ffff, 0xffff00ff, 0xffffff00, 0xff80ff00, 0xff00ff80};
|
||||
private static final char[] plr_wheel = { '/', '-', '\\', '|'};
|
||||
|
||||
public Visualizer(int x, int y, int w, int h) {
|
||||
super(x, y, w, h, null);
|
||||
|
@ -52,6 +54,14 @@ public class GuiPlayer extends GuiList<GuiPlayer.SongEntry> {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected int getMarginX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int getMarginY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int gui_render_bar(int x, int y, int w, int h, int top, int bottom, int bg, int v) {
|
||||
v = (v < 0) ? 0 : v;
|
||||
Drawing.drawGradient(this.pos_x + x, this.pos_y + y, w, h, 0xff000000 | top, 0xff000000 | bottom);
|
||||
|
@ -77,7 +87,7 @@ public class GuiPlayer extends GuiList<GuiPlayer.SongEntry> {
|
|||
return Font.SMALL.getHeight();
|
||||
}
|
||||
|
||||
protected void drawBackground() {
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
gui_render_grad(0, 0, this.size_x, this.size_y, this.gm.style.field_btm, this.gm.style.field_top);
|
||||
if(!this.gm.midiVisualizer)
|
||||
return;
|
||||
|
@ -88,20 +98,20 @@ public class GuiPlayer extends GuiList<GuiPlayer.SongEntry> {
|
|||
MidiHandle bank = midi.bank;
|
||||
try {
|
||||
int nch = chip.channel.length * 2;
|
||||
int bx = this.size_x / 2 - (nch * 6 + 2) / 2;
|
||||
int by = this.size_y / 2 - (698 + 20 * 4) / 2;
|
||||
int bx = this.size_x / 2 - (nch * 3 + 1) / 2;
|
||||
int by = this.size_y / 2 - (349 + 10 * 4) / 2;
|
||||
int x = bx;
|
||||
int y = by;
|
||||
|
||||
y += 20;
|
||||
y += gui_render_rect(x, y, nch * 6 + 2, 226, 0x3f0000) + 20;
|
||||
y += gui_render_rect(x, y, nch * 6 + 2, 232, 0x003f00) + 20;
|
||||
y += gui_render_rect(x, y, nch * 6 + 2, 232, 0x00003f) + 20;
|
||||
y += gui_render_rect(x, y, nch * 6 + 2, 8, 0x2f2f2f);
|
||||
y += 10;
|
||||
y += gui_render_rect(x, y, nch * 3 + 1, 113, 0x3f0000) + 10;
|
||||
y += gui_render_rect(x, y, nch * 3 + 1, 116, 0x003f00) + 10;
|
||||
y += gui_render_rect(x, y, nch * 3 + 1, 116, 0x00003f) + 10;
|
||||
y += gui_render_rect(x, y, nch * 3 + 1, 4, 0x2f2f2f);
|
||||
for(int c = 0; c < nch; c++) {
|
||||
OPLChannel channel = chip.channel[c / 2];
|
||||
x = bx + 2 + 6 * c;
|
||||
y = by + 2;
|
||||
x = bx + 1 + 3 * c;
|
||||
y = by + 1;
|
||||
ModGen[] out = channel.out;
|
||||
int accm = 0;
|
||||
for(int z = 0; z < out.length; z++) {
|
||||
|
@ -109,106 +119,86 @@ public class GuiPlayer extends GuiList<GuiPlayer.SongEntry> {
|
|||
}
|
||||
int chnlvl = (short)((accm * channel.level[c % 2]) >> 16);
|
||||
chnlvl = chnlvl < 0 ? (-chnlvl) : chnlvl;
|
||||
chnlvl = (chnlvl * 16) / 1024;
|
||||
chnlvl = chnlvl > 64 ? 64 : chnlvl;
|
||||
int freq = (int)(((float)channel.slots[0].read_freq) / 6210000.0f * 128.0f);
|
||||
y += 20;
|
||||
y += gui_render_bar(x, y, 4, 64, 0xff0000, 0x00ff00, 0x000000, chnlvl) + 2;
|
||||
y += gui_render_rect(x, y, 4, 4, ((channel.slots[0].eg_out <= 0x100) || (channel.slots[1].eg_out <= 0x100)) ? 0x00ff00 : 0x000000) + 2;
|
||||
y += gui_render_rect(x - (c % 2), y, 5, 4, (channel.read_algo & 0x04) != 0 ? 0xff00ff : 0x000000) + 2;
|
||||
y += gui_render_grad(x, y, 4, 4, (channel.read_algo & (c % 2 == 0 ? 0x01 : 0x02)) != 0 ? 0x00ff00 : 0x808080, 0x0000ff) + 2;
|
||||
y += gui_render_bar(x, y, 4, 8, 0x00ff00, 0xffff00, 0x000000, c % 2 == 0 ? channel.read_fb1 : channel.read_fb2) + 2;
|
||||
y += gui_render_bar(x, y, 4, 128, 0x707070, 0x505050, 0x000000, freq) + 2;
|
||||
gui_render_rect(x, y - 130 + (127 - freq), 4, 1, 0xff0000);
|
||||
chnlvl = (chnlvl * 16) / 2048;
|
||||
chnlvl = chnlvl > 32 ? 32 : chnlvl;
|
||||
int freq = (int)(((float)channel.slots[0].read_freq) / 6210000.0f * 64.0f);
|
||||
y += 10;
|
||||
y += gui_render_bar(x, y, 2, 32, 0xff0000, 0x00ff00, 0x000000, chnlvl) + 1;
|
||||
y += gui_render_rect(x, y, 2, 2, ((channel.slots[0].eg_out <= 0x100) || (channel.slots[1].eg_out <= 0x100)) ? 0x00ff00 : 0x000000) + 1;
|
||||
y += gui_render_rect(x, y, (c % 2) == 0 ? 3 : 2, 2, (channel.read_algo & 0x04) != 0 ? 0xff00ff : 0x000000) + 1;
|
||||
y += gui_render_grad(x, y, 2, 2, (channel.read_algo & (c % 2 == 0 ? 0x01 : 0x02)) != 0 ? 0x00ff00 : 0x808080, 0x0000ff) + 1;
|
||||
y += gui_render_bar(x, y, 2, 4, 0x00ff00, 0xffff00, 0x000000, (c % 2 == 0 ? channel.read_fb1 : channel.read_fb2) / 2) + 1;
|
||||
y += gui_render_bar(x, y, 2, 64, 0x707070, 0x505050, 0x000000, freq) + 1;
|
||||
gui_render_rect(x, y - 65 + (63 - freq), 2, 1, 0xff0000);
|
||||
for(int o = 0; o < 2; o++) {
|
||||
OPLSlot slot = channel.slots[(c % 2) * 2 + o];
|
||||
y += 2;
|
||||
y += 20;
|
||||
y += gui_render_rect(x, y, 4, 4, slot.key ? 0x00ff00 : 0x000000) + 2;
|
||||
y += gui_render_rect(x, y, 4, 4, slot.trem != chip.zeromod ? 0x5fdf00 : 0x000000);
|
||||
y += gui_render_rect(x, y, 4, 4, slot.reg_vib ? 0xffff00 : 0x000000);
|
||||
y += gui_render_rect(x, y, 4, 4, slot.reg_type ? 0xff0000 : 0x000000);
|
||||
y += gui_render_rect(x, y, 4, 4, slot.reg_ksr ? 0x5f00bf : 0x000000) + 2;
|
||||
y += gui_render_bar(x, y, 4, 16, 0xff0000, 0xffff00, 0x000000, slot.reg_mult) + 2;
|
||||
y += gui_render_bar(x, y, 4, 64, 0xff0000, 0x00ff00, 0x000000, 63 - slot.reg_tl) + 2;
|
||||
y += gui_render_bar(x, y, 4, 4, 0x7f00ff, 0x3f00ff, 0x000000, slot.reg_ksl) + 2;
|
||||
y += gui_render_rect(x, y, 4, 8, 0x000000) + 2;
|
||||
gui_render_rect(x, y - 10 + (7 - slot.reg_wf), 4, 1, plr_waveforms[slot.reg_wf]);
|
||||
y += 1;
|
||||
y += 10;
|
||||
y += gui_render_rect(x, y, 2, 2, slot.key ? 0x00ff00 : 0x000000) + 1;
|
||||
y += gui_render_rect(x, y, 2, 2, slot.trem != chip.zeromod ? 0x5fdf00 : 0x000000);
|
||||
y += gui_render_rect(x, y, 2, 2, slot.reg_vib ? 0xffff00 : 0x000000);
|
||||
y += gui_render_rect(x, y, 2, 2, slot.reg_type ? 0xff0000 : 0x000000);
|
||||
y += gui_render_rect(x, y, 2, 2, slot.reg_ksr ? 0x5f00bf : 0x000000) + 1;
|
||||
y += gui_render_bar(x, y, 2, 8, 0xff0000, 0xffff00, 0x000000, slot.reg_mult / 2) + 1;
|
||||
y += gui_render_bar(x, y, 2, 32, 0xff0000, 0x00ff00, 0x000000, (63 - slot.reg_tl) / 2) + 1;
|
||||
y += gui_render_bar(x, y, 2, 2, 0x7f00ff, 0x3f00ff, 0x000000, slot.reg_ksl / 2) + 1;
|
||||
y += gui_render_rect(x, y, 2, 4, 0x000000) + 1;
|
||||
gui_render_rect(x, y - 5 + (7 - slot.reg_wf) / 2, 2, 1, plr_waveforms[slot.reg_wf]);
|
||||
|
||||
y += gui_render_bar(x, y, 4, 16, slot.eg_gen == EnvState.ATTACK ? 0xff0000 : 0xaf0000, slot.eg_gen == EnvState.ATTACK ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_ar) + 2;
|
||||
y += gui_render_bar(x, y, 4, 16, slot.eg_gen == EnvState.DECAY ? 0xff0000 : 0xaf0000, slot.eg_gen == EnvState.DECAY ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_dr) + 2;
|
||||
y += gui_render_bar(x, y, 4, 16, slot.eg_gen == EnvState.SUSTAIN ? 0xff0000 : 0xaf0000, slot.eg_gen == EnvState.SUSTAIN ? 0x00ffff : 0x00afaf, 0x000000, (slot.reg_sl > 15) ? 0 : (15 - slot.reg_sl)) + 2;
|
||||
y += gui_render_bar(x, y, 4, 16, slot.eg_gen == EnvState.RELEASE ? 0xff0000 : 0xaf0000, slot.eg_gen == EnvState.RELEASE ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_rr) + 2;
|
||||
y += gui_render_bar(x, y, 4, 32, 0xff0000, 0x0000ff, 0x000000, (0x1ff - slot.eg_rout) / 16) + 2;
|
||||
}
|
||||
y += 2;
|
||||
y += 20;
|
||||
gui_render_rect(x, y, 4, 4, bank.index == c / 2 ? 0x00ffff : 0x000000);
|
||||
}
|
||||
}
|
||||
catch(Throwable e) {
|
||||
y += gui_render_bar(x, y, 2, 8, slot.eg_gen == EnvState.ATTACK ? 0xff0000 : 0xaf0000, slot.eg_gen == EnvState.ATTACK ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_ar / 2) + 1;
|
||||
y += gui_render_bar(x, y, 2, 8, slot.eg_gen == EnvState.DECAY ? 0xff0000 : 0xaf0000, slot.eg_gen == EnvState.DECAY ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_dr / 2) + 1;
|
||||
y += gui_render_bar(x, y, 2, 8, slot.eg_gen == EnvState.SUSTAIN ? 0xff0000 : 0xaf0000, slot.eg_gen == EnvState.SUSTAIN ? 0x00ffff : 0x00afaf, 0x000000, ((slot.reg_sl > 15) ? 0 : (15 - slot.reg_sl)) / 2) + 1;
|
||||
y += gui_render_bar(x, y, 2, 8, slot.eg_gen == EnvState.RELEASE ? 0xff0000 : 0xaf0000, slot.eg_gen == EnvState.RELEASE ? 0x00ffff : 0x00afaf, 0x000000, slot.reg_rr / 2) + 1;
|
||||
y += gui_render_bar(x, y, 2, 16, 0xff0000, 0x0000ff, 0x000000, (0x1ff - slot.eg_rout) / 32) + 1;
|
||||
}
|
||||
y += 1;
|
||||
y += 10;
|
||||
gui_render_rect(x, y, 2, 2, bank.index == c / 2 ? 0x00ffff : 0x000000);
|
||||
}
|
||||
|
||||
protected void drawForeground(int x1, int y1, int x2, int y2) {
|
||||
if(!this.gm.midiVisualizer)
|
||||
return;
|
||||
MidiDecoder midi = this.gm.getAudioInterface().alGetMidi();
|
||||
if(midi == null)
|
||||
return;
|
||||
OPLChip chip = midi.chip;
|
||||
MidiHandle bank = midi.bank;
|
||||
try {
|
||||
int nch = chip.channel.length;
|
||||
int bx = this.size_x / 2 - (nch * 6 + 2) / 2;
|
||||
int by = this.size_y / 2 - (698 + 20 * 4) / 2;
|
||||
int x = bx;
|
||||
int y = by;
|
||||
/*
|
||||
x = bx - 84;
|
||||
sprintf(&sys.work_buf[str_time(sys.work_buf, sgt.mid_time)], "\n%c%c%c%c %c",
|
||||
(sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 0)) ? '*' : '.',
|
||||
(sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 1)) ? '*' : '.',
|
||||
(sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 2)) ? '*' : '.',
|
||||
(sgt.mid.tpqn && (((sgt.mid_tick / sgt.mid.tpqn) & 3) == 3)) ? '*' : '.',
|
||||
plr_wheel[(sgt.mid_tick >> 5) & 3]);
|
||||
gui_render_text(x, y + 20, 0xffffff, sys.work_buf);
|
||||
sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d", STR_OPL_TICK, sgt.mid_tick);
|
||||
gui_render_text(x, y + 60, 0xffffff, sys.work_buf);
|
||||
sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d / %d", STR_OPL_ACTIVE, bank.v_used, bank.voices.length);
|
||||
gui_render_text(x, y + 100, 0xffffff, sys.work_buf);
|
||||
sprintf(sys.work_buf, COL_NEON"%s"COL_RESET"\n%d +%dQ", STR_OPL_TEMPO, sgt.mid.uspb ? (60000000 / sgt.mid.uspb) : 0, sgt.mid.tpqn);
|
||||
gui_render_text(x, y + 140, 0xffffff, sys.work_buf);
|
||||
x = bx - 68;
|
||||
y = by;
|
||||
if(midi.tracks != null) {
|
||||
long time = midi.time / 1000L;
|
||||
gui_render_text(x, y + 10, 0xffffff, String.format("%02d:%02d.%03d", time / 1000L / 60L % 60L, time / 1000L % 60L, time % 1000L));
|
||||
gui_render_text(x, y + 10 + 9, 0xffffff, String.format("%c%c%c%c %c",
|
||||
(midi.tpqn != 0 && (((midi.tick / midi.tpqn) & 3) == 0)) ? '*' : '.',
|
||||
(midi.tpqn != 0 && (((midi.tick / midi.tpqn) & 3) == 1)) ? '*' : '.',
|
||||
(midi.tpqn != 0 && (((midi.tick / midi.tpqn) & 3) == 2)) ? '*' : '.',
|
||||
(midi.tpqn != 0 && (((midi.tick / midi.tpqn) & 3) == 3)) ? '*' : '.',
|
||||
plr_wheel[(midi.tick >> 5) & 3]));
|
||||
gui_render_text(x, y + 30, 0xffffff, Color.NEON + "Tick/Pos.");
|
||||
gui_render_text(x, y + 30 + 9, 0xffffff, String.format("%d", midi.tick));
|
||||
gui_render_text(x, y + 50, 0xffffff, Color.NEON + "Tempo BPM");
|
||||
gui_render_text(x, y + 50 + 9, 0xffffff, String.format("%d +%dQ", midi.uspb != 0 ? (60000000 / midi.uspb) : 0, midi.tpqn));
|
||||
}
|
||||
gui_render_text(x, y + 70, 0xffffff, Color.NEON + "Aktiv");
|
||||
gui_render_text(x, y + 70 + 9, 0xffffff, String.format("%d / %d", bank.used, bank.voices.length));
|
||||
x = bx;
|
||||
pthread_mutex_unlock(&sgt.lock);
|
||||
y += 3;
|
||||
gui_render_text(x, y, 0xffffff, STR_OPL_CHANNEL);
|
||||
gui_render_text(x, y + 20 + 226, 0xffffff, STR_OPL_MODULATOR);
|
||||
gui_render_text(x, y + 40 + 226 + 232, 0xffffff, STR_OPL_CARRIER);
|
||||
gui_render_text(x, y + 60 + 226 + 232 * 2, 0xffffff, STR_OPL_POINTER);
|
||||
y -= 3;
|
||||
// x -= 86;
|
||||
x += nch * 6 + 2 + 1;
|
||||
y += 20;
|
||||
gui_render_text(x, y + 0, 0xffffff, STR_OPL_OUTPUT);
|
||||
gui_render_text(x, y + 70, 0xffffff, STR_OPL_MODE);
|
||||
gui_render_text(x, y + 84, 0xffffff, STR_OPL_FEEDBACK);
|
||||
gui_render_text(x, y + 98, 0xffffff, STR_OPL_FREQUENCY);
|
||||
y += 226 + 20;
|
||||
gui_render_text(x, y, 0xffffff, "Kanal");
|
||||
gui_render_text(x, y + 10 + 113, 0xffffff, "Operator 1 + 3 / Modulator");
|
||||
gui_render_text(x, y + 20 + 113 + 116, 0xffffff, "Operator 2 + 4 / Träger");
|
||||
gui_render_text(x, y + 30 + 113 + 116 * 2, 0xffffff, "Stimmen-Zeiger");
|
||||
x += nch * 3 + 2;
|
||||
y += 10;
|
||||
gui_render_text(x, y + 0, 0xffffff, "Pegel");
|
||||
gui_render_text(x, y + 35, 0xffffff, "Modus/Al.");
|
||||
gui_render_text(x, y + 42, 0xffffff, "Feedback");
|
||||
gui_render_text(x, y + 49, 0xffffff, "Frequenz");
|
||||
y += 113 + 10;
|
||||
for(int o = 0; o < 2; o++) {
|
||||
gui_render_text(x, y + 6, 0xffffff, STR_OPL_FLAGS);
|
||||
gui_render_text(x, y + 24, 0xffffff, STR_OPL_MULTIPLIER);
|
||||
gui_render_text(x, y + 42, 0xffffff, STR_OPL_LEVEL);
|
||||
gui_render_text(x, y + 96, 0xffffff, STR_OPL_KEYSCALE);
|
||||
gui_render_text(x, y + 110, 0xffffff, STR_OPL_WAVEFORM);
|
||||
gui_render_text(x, y + 124, 0xffffff, STR_OPL_ATTACK);
|
||||
gui_render_text(x, y + 142, 0xffffff, STR_OPL_DECAY);
|
||||
gui_render_text(x, y + 160, 0xffffff, STR_OPL_SUSTAIN);
|
||||
gui_render_text(x, y + 178, 0xffffff, STR_OPL_RELEASE);
|
||||
gui_render_text(x, y + 196, 0xffffff, STR_OPL_ENVELOPE);
|
||||
y += 232 + 20;
|
||||
gui_render_text(x, y + 3, 0xffffff, "T-V-S-K");
|
||||
gui_render_text(x, y + 12, 0xffffff, "Frq.-Mult.");
|
||||
gui_render_text(x, y + 21, 0xffffff, "Op.-Pegel");
|
||||
gui_render_text(x, y + 48, 0xffffff, "Tst.-Skale");
|
||||
gui_render_text(x, y + 55, 0xffffff, "Wellenf.");
|
||||
gui_render_text(x, y + 62, 0xffffff, "Attack");
|
||||
gui_render_text(x, y + 71, 0xffffff, "Decay");
|
||||
gui_render_text(x, y + 80, 0xffffff, "Sustain");
|
||||
gui_render_text(x, y + 89, 0xffffff, "Release");
|
||||
gui_render_text(x, y + 98, 0xffffff, "Hüllkurve");
|
||||
y += 116 + 10;
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch(Throwable e) {
|
||||
}
|
||||
|
@ -501,28 +491,6 @@ public class GuiPlayer extends GuiList<GuiPlayer.SongEntry> {
|
|||
}
|
||||
|
||||
/*
|
||||
STR(OPL_CHANNEL, "", "Kanal")
|
||||
STR(OPL_MODULATOR, "", "Operator 1 + 3 / Modulator")
|
||||
STR(OPL_CARRIER, "", "Operator 2 + 4 / Träger")
|
||||
STR(OPL_POINTER, "", "Stimmen-Zeiger")
|
||||
STR(OPL_OUTPUT, "", "Pegel")
|
||||
STR(OPL_MODE, "", "Modus/Al.")
|
||||
STR(OPL_FEEDBACK, "", "Feedback")
|
||||
STR(OPL_FREQUENCY, "", "Frequenz")
|
||||
STR(OPL_FLAGS, "", "T-V-S-K")
|
||||
STR(OPL_MULTIPLIER, "", "Frq.-Mult.")
|
||||
STR(OPL_LEVEL, "", "Op.-Pegel")
|
||||
STR(OPL_KEYSCALE, "", "Tst.-Skale")
|
||||
STR(OPL_WAVEFORM, "", "Wellenf.")
|
||||
STR(OPL_ATTACK, "", "Attack")
|
||||
STR(OPL_DECAY, "", "Decay")
|
||||
STR(OPL_SUSTAIN, "", "Sustain")
|
||||
STR(OPL_RELEASE, "", "Release")
|
||||
STR(OPL_ENVELOPE, "", "Hüllkurve")
|
||||
STR(OPL_TICK, "", "Tick/Pos.")
|
||||
STR(OPL_ACTIVE, "", "Aktiv")
|
||||
STR(OPL_TEMPO, "", "Tempo BPM")
|
||||
|
||||
#define SYM_PLAY "\U00100000"
|
||||
#define SYM_STOP "\U00100001"
|
||||
#define SYM_PAUSE "\U00100002"
|
||||
|
@ -540,9 +508,6 @@ STR(OPL_TEMPO, "", "Tempo BPM")
|
|||
#define SYM_DELETE "\U0010000e"
|
||||
#define SYM_SAVEDISK "\U0010000f"
|
||||
|
||||
|
||||
static const char plr_wheel[] = { '/', '-', '\\', '|'};
|
||||
|
||||
void gui_fmt_velofunc(gui_t *elem, int value) {
|
||||
snprintf(elem.text, elem.capacity, "%s %d: %s", elem.format_text, value, (value ? (value == -128 ? STR_MID_VELO_ONE : (value < 0 ? STR_MID_VELO_ATTN : STR_MID_VELO_LOG)) : STR_MID_VELO_LIN));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue