mirror of
https://github.com/luksamuk/engine-psx.git
synced 2025-04-28 13:28:02 +03:00
Merge pull request #12 from luksamuk/bug/cdxa-crash
Fix crash on CDXA playback loop
This commit is contained in:
commit
dbba059986
5 changed files with 44 additions and 22 deletions
2
Makefile
2
Makefile
|
@ -34,7 +34,7 @@ run: ./build/sonicxa.cue
|
|||
|
||||
# Target for running the image on Mednafen
|
||||
run-mednafen: ./build/sonicxa.cue
|
||||
mednafen $<
|
||||
mednafen -force_module psx $<
|
||||
|
||||
# Target for running the image on PCSX-ReARMed
|
||||
run-rearmed: ./build/sonicxa.cue
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="255" height="31" tilewidth="128" tileheight="128" infinite="0" backgroundcolor="#3f007f" nextlayerid="5" nextobjectid="191">
|
||||
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="255" height="31" tilewidth="128" tileheight="128" infinite="0" backgroundcolor="#3f007f" nextlayerid="5" nextobjectid="194">
|
||||
<tileset firstgid="1" source="128x128.tsx"/>
|
||||
<tileset firstgid="81" source="../COMMON/objects_common.tsx"/>
|
||||
<layer id="1" name="LAYER0" width="255" height="31">
|
||||
|
@ -18,9 +18,9 @@
|
|||
7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,14,12,0,19,2,0,25,18,20,12,0,0,4,12,23,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,18,9,9,9,9,9,18,20,12,12,13,19,0,12,0,0,39,12,23,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,69,70,71,12,12,12,2,2,2,2,2,66,67,69,70,19,19,19,17,12,3,0,0,10,26,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,7,12,38,9,39,12,61,30,30,66,67,69,70,30,66,67,69,70,66,67,0,0,69,70,2,2,68,12,38,9,9,11,0,0,0,0,0,0,0,0,10,9,39,12,30,5,18,18,12,12,13,19,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,10,9,9,9,9,64,72,9,9,9,64,72,9,9,64,9,9,72,9,9,9,9,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,39,12,13,5,0,0,77,78,76,12,12,12,61,2,2,2,2,2,2,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,9,9,9,9,9,9,9,9,9,9,9,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,7,12,38,9,39,12,61,30,30,66,67,69,70,30,66,67,69,70,66,67,0,0,69,70,2,2,68,12,38,9,9,11,0,0,0,0,0,0,0,0,10,9,39,12,0,18,18,18,9,39,13,19,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,10,9,9,9,9,64,72,9,9,9,64,72,9,9,64,9,9,72,9,9,9,9,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,39,12,12,65,66,67,69,70,71,12,12,12,61,2,2,2,2,2,2,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,9,9,9,9,72,9,9,9,9,9,9,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
|
@ -115,9 +115,9 @@
|
|||
</object>
|
||||
<object id="93" gid="89" x="5909" y="1469" width="64" height="64"/>
|
||||
<object id="95" gid="89" x="5086" y="1726" width="64" height="64"/>
|
||||
<object id="98" gid="81" x="6409" y="2007.5" width="64" height="64"/>
|
||||
<object id="99" gid="81" x="6433" y="2018.5" width="64" height="64"/>
|
||||
<object id="100" gid="81" x="6457" y="2030.5" width="64" height="64"/>
|
||||
<object id="98" gid="81" x="6425" y="1956.5" width="64" height="64"/>
|
||||
<object id="99" gid="81" x="6449" y="1967.5" width="64" height="64"/>
|
||||
<object id="100" gid="81" x="6473" y="1979.5" width="64" height="64"/>
|
||||
<object id="101" gid="81" x="6803" y="1821.5" width="64" height="64"/>
|
||||
<object id="102" gid="81" x="6827" y="1832.5" width="64" height="64"/>
|
||||
<object id="103" gid="81" x="6851" y="1844.5" width="64" height="64"/>
|
||||
|
@ -166,7 +166,6 @@
|
|||
<object id="150" gid="85" x="6304" y="1440" width="64" height="64"/>
|
||||
<object id="151" gid="85" x="6528" y="1680" width="64" height="64" rotation="-90"/>
|
||||
<object id="152" gid="85" x="6528" y="1840" width="64" height="64" rotation="-90"/>
|
||||
<object id="153" gid="86" x="6016" y="1808" width="64" height="64" rotation="90"/>
|
||||
<object id="154" gid="2147483735" x="2128" y="1152" width="64" height="64"/>
|
||||
<object id="155" gid="82" x="112" y="608" width="64" height="64">
|
||||
<properties>
|
||||
|
@ -208,6 +207,8 @@
|
|||
<object id="188" gid="81" x="4120" y="1194.5" width="64" height="64"/>
|
||||
<object id="189" gid="81" x="4144" y="1183.5" width="64" height="64"/>
|
||||
<object id="190" gid="87" x="112" y="896" width="64" height="64"/>
|
||||
<object id="192" gid="2147483735" x="1168" y="912" width="64" height="64"/>
|
||||
<object id="193" gid="85" x="6016" y="1872" width="64" height="64" rotation="90"/>
|
||||
</objectgroup>
|
||||
</group>
|
||||
</map>
|
||||
|
|
|
@ -235,7 +235,7 @@ screen_levelselect_update(void *d)
|
|||
} else if(data->menu_choice == CHOICE_SOUNDTEST) {
|
||||
if(data->soundtest_selection > 0) {
|
||||
sound_bgm_play(data->soundtest_selection - 1);
|
||||
data->music_selected = data->soundtest_selection;
|
||||
data->music_selected = data->soundtest_selection - 1;
|
||||
}
|
||||
} else {
|
||||
screen_level_setlevel(data->menu_choice);
|
||||
|
|
39
src/sound.c
39
src/sound.c
|
@ -7,6 +7,13 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef enum {
|
||||
CDXA_NONE,
|
||||
CDXA_LOOP_BACK,
|
||||
CDXA_STOP,
|
||||
} CDXAInternalCommand;
|
||||
|
||||
|
||||
// First 4KB of SPU RAM are reserved for capture buffers.
|
||||
// psxspu additionally uploads a dummy sample (16 bytes) at 0x1000
|
||||
// by default, so the samples must be placed after those.
|
||||
|
@ -32,11 +39,12 @@ static int32_t next_channel = 0;
|
|||
// callback's stack, whose size is very limited.
|
||||
/* static volatile XACDSector _sector; */
|
||||
|
||||
// Current .XA audio data start location.
|
||||
// Current .XA audio data start location and other stuff
|
||||
static volatile CdlLOC _xa_loc;
|
||||
static volatile int _xa_should_play = 0;
|
||||
static volatile uint32_t _cd_status = 0;
|
||||
static volatile uint32_t _xa_loopback_sector = 0;
|
||||
static volatile CDXAInternalCommand _xa_command = CDXA_NONE;
|
||||
|
||||
// Read error threshold. If surpasses the limit, restart the music.
|
||||
#define CD_MAX_ERR_THRESHOLD 10
|
||||
|
@ -78,6 +86,25 @@ sound_update(void)
|
|||
{
|
||||
CdControl(CdlNop, 0, 0);
|
||||
_cd_status = CdStatus();
|
||||
|
||||
EnterCriticalSection();
|
||||
if(_xa_command != CDXA_NONE) {
|
||||
switch(_xa_command) {
|
||||
case CDXA_LOOP_BACK:
|
||||
_cd_elapsed_sectors = 0;
|
||||
CdControlF(CdlReadS, (const void *)&_xa_loc);
|
||||
break;
|
||||
case CDXA_STOP:
|
||||
_xa_should_play = 0;
|
||||
_xa_loopback_sector = 0;
|
||||
_cd_elapsed_sectors = 0;
|
||||
CdControlF(CdlPause, 0);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
_xa_command = CDXA_NONE;
|
||||
}
|
||||
ExitCriticalSection();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -231,11 +258,8 @@ _xa_cd_event_callback(CdlIntrResult event, uint8_t * /* payload */)
|
|||
if((_xa_loopback_sector > 0) && (_cd_elapsed_sectors > _xa_loopback_sector)) {
|
||||
// Loop back to beginning
|
||||
_cd_err_threshold = 0;
|
||||
_cd_elapsed_sectors = 0;
|
||||
CdControlF(CdlReadS, (const void *)&_xa_loc);
|
||||
_xa_command = CDXA_LOOP_BACK;
|
||||
}
|
||||
|
||||
/* CdGetSector((void*)(&_sector), sizeof(XACDSector) / 4); */
|
||||
break;
|
||||
case CdlDiskError:
|
||||
printf("Caught CD error\n");
|
||||
|
@ -243,11 +267,8 @@ _xa_cd_event_callback(CdlIntrResult event, uint8_t * /* payload */)
|
|||
if(_cd_err_threshold > CD_MAX_ERR_THRESHOLD) {
|
||||
// Stop music if too many errs
|
||||
_cd_err_threshold = 0;
|
||||
_cd_elapsed_sectors = 0;
|
||||
printf("Too many CD errors -- stop playback!\n");
|
||||
CdControlF(CdlPause, 0);
|
||||
_xa_should_play = 0;
|
||||
_xa_loopback_sector = 0;
|
||||
_xa_command = CDXA_STOP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -5,14 +5,14 @@ const BGMTableEntry bgm_table[] = {
|
|||
// Filename - Channel - Loop sector - Stop sector
|
||||
{"\\BGM\\MNU001.XA;1", 0, 0, 1550}, // Level select
|
||||
{"\\BGM\\MNU001.XA;1", 1, 0, 450}, // Title
|
||||
{"\\BGM\\MNU001.XA;1", 2, 0, 4850}, // Credits
|
||||
{"\\BGM\\MNU001.XA;1", 2, 0, 4500}, // Credits
|
||||
|
||||
{"\\BGM\\MNU002.XA;1", 0, 1300, 0}, // Speed shoes
|
||||
|
||||
{"\\BGM\\EVENT001.XA;1", 0, 0, 300}, // Level clear
|
||||
|
||||
{"\\BGM\\BGM001.XA;1", 0, 4000, 0}, // PZ1
|
||||
{"\\BGM\\BGM001.XA;1", 1, 4800, 0}, // PZ2
|
||||
{"\\BGM\\BGM001.XA;1", 0, 3850, 0}, // PZ1
|
||||
{"\\BGM\\BGM001.XA;1", 1, 4650, 0}, // PZ2
|
||||
{"\\BGM\\BGM001.XA;1", 2, 3230, 0}, // PZ3
|
||||
|
||||
{"\\BGM\\BGM002.XA;1", 0, 4050, 0}, // PZ4
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue