mirror of
https://github.com/luksamuk/engine-psx.git
synced 2025-04-28 13:28:02 +03:00
Add sound effects
This commit is contained in:
parent
b4d7be0cda
commit
a33a11b716
14 changed files with 147 additions and 34 deletions
2
assets/sfx/.gitignore
vendored
Normal file
2
assets/sfx/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
\*.WAV
|
||||
|
BIN
assets/sfx/JUMP.VAG
Normal file
BIN
assets/sfx/JUMP.VAG
Normal file
Binary file not shown.
BIN
assets/sfx/JUMP.ogg
Normal file
BIN
assets/sfx/JUMP.ogg
Normal file
Binary file not shown.
BIN
assets/sfx/RING.VAG
Normal file
BIN
assets/sfx/RING.VAG
Normal file
Binary file not shown.
BIN
assets/sfx/RING.ogg
Normal file
BIN
assets/sfx/RING.ogg
Normal file
Binary file not shown.
BIN
assets/sfx/SKIDDING.VAG
Normal file
BIN
assets/sfx/SKIDDING.VAG
Normal file
Binary file not shown.
BIN
assets/sfx/SKIDDING.ogg
Normal file
BIN
assets/sfx/SKIDDING.ogg
Normal file
Binary file not shown.
8
assets/sfx/convert.sh
Executable file
8
assets/sfx/convert.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
for f in *.ogg; do
|
||||
ffmpeg -y -i "$f" -acodec pcm_s16le -ac 1 -ar 22050 "${f%%.ogg}.WAV";
|
||||
wav2vag "${f%%.ogg}.WAV" "${f%%.ogg}.VAG";
|
||||
rm "${f%%.ogg}.WAV";
|
||||
done
|
||||
|
|
@ -4,6 +4,27 @@
|
|||
#include <stdint.h>
|
||||
#include <psxcd.h>
|
||||
|
||||
// .VAG audio header
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t interleave; // Unused in mono
|
||||
uint32_t size; // Big-endian, bytes
|
||||
uint32_t sample_rate; // Big-endian, Hz
|
||||
uint16_t _reserved[5];
|
||||
uint16_t channels; // Unused in mono
|
||||
char name[16];
|
||||
} VAGHeader;
|
||||
|
||||
// Struct holding information on an uploaded sample.
|
||||
typedef struct {
|
||||
uint32_t addr;
|
||||
uint32_t sample_rate;
|
||||
} SoundEffect;
|
||||
|
||||
// "VAGp" text
|
||||
#define VAG_MAGIC 0x70474156
|
||||
|
||||
// .XA audio header
|
||||
typedef struct {
|
||||
uint8_t file;
|
||||
|
@ -37,7 +58,9 @@ void sound_init(void);
|
|||
void sound_reset_mem(void);
|
||||
void sound_update(void);
|
||||
|
||||
uint32_t sound_upload_sample(const uint32_t *data, uint32_t size);
|
||||
SoundEffect sound_load_vag(const char *filename);
|
||||
uint32_t sound_upload_vag(const uint32_t *data, uint32_t size);
|
||||
void sound_play_vag(SoundEffect sfx);
|
||||
|
||||
uint32_t sound_get_cd_status(void);
|
||||
void sound_play_xa(const char *filename, int double_speed,
|
||||
|
|
18
iso.xml
18
iso.xml
|
@ -12,7 +12,9 @@
|
|||
<!-- <license file="${PROJECT_SOURCE_DIR}/LCNSFILE/LICENSEA.DAT" /> -->
|
||||
<directory_tree>
|
||||
<file name="SYSTEM.CNF" type="data" source="${PROJECT_SOURCE_DIR}/system.cnf" />
|
||||
|
||||
<file name="SONIC.EXE" type="data" source="sonic.exe" />
|
||||
|
||||
<dir name="SPRITES">
|
||||
<file name="SONIC.TIM"
|
||||
type="data"
|
||||
|
@ -21,11 +23,25 @@
|
|||
type="data"
|
||||
source="${PROJECT_SOURCE_DIR}/assets/sprites/SONIC.CHARA" />
|
||||
</dir>
|
||||
<dir name="AUDIO">
|
||||
|
||||
<dir name="SFX">
|
||||
<file name="JUMP.VAG"
|
||||
type="data"
|
||||
source="${PROJECT_SOURCE_DIR}/assets/sfx/JUMP.VAG" />
|
||||
<file name="RING.VAG"
|
||||
type="data"
|
||||
source="${PROJECT_SOURCE_DIR}/assets/sfx/RING.VAG" />
|
||||
<file name="SKIDDING.VAG"
|
||||
type="data"
|
||||
source="${PROJECT_SOURCE_DIR}/assets/sfx/SKIDDING.VAG" />
|
||||
</dir>
|
||||
|
||||
<dir name="BGM">
|
||||
<file name="BGM001.XA"
|
||||
type="xa"
|
||||
source="${PROJECT_SOURCE_DIR}/assets/bgm/BGM001.XA" />
|
||||
</dir>
|
||||
|
||||
<dummy sectors="1024"/>
|
||||
</directory_tree>
|
||||
</track>
|
||||
|
|
|
@ -14,7 +14,7 @@ load_chara(Chara *chara, const char *filename, TIM_IMAGE *tim)
|
|||
|
||||
bytes = file_read(filename, &length);
|
||||
if(bytes == NULL) {
|
||||
printf("Error reading %s from the CD.\n", bytes);
|
||||
printf("Error reading CHARA file %s from the CD.\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
53
src/main.c
53
src/main.c
|
@ -14,10 +14,10 @@
|
|||
#include "input.h"
|
||||
#include "player.h"
|
||||
|
||||
#define SPRTSZ 56
|
||||
/* #define SPRTSZ 56 */
|
||||
|
||||
static int x = (SPRTSZ >> 1), y = (SPRTSZ >> 1);
|
||||
static int dx = 1, dy = 1;
|
||||
/* static int x = (SPRTSZ >> 1), y = (SPRTSZ >> 1); */
|
||||
/* static int dx = 1, dy = 1; */
|
||||
|
||||
static SVECTOR vertices[] = {
|
||||
{ -64, -64, -64, 0 },
|
||||
|
@ -67,11 +67,14 @@ engine_init()
|
|||
}
|
||||
|
||||
load_player(&player, "\\SPRITES\\SONIC.CHARA;1", &tim);
|
||||
player.pos = (VECTOR){ (uint32_t)(SCREEN_XRES) << 9, (uint32_t)(SCREEN_YRES) << 11, 0 };
|
||||
|
||||
player.pos = (VECTOR){
|
||||
(uint32_t)(SCREEN_XRES) << 9,
|
||||
(uint32_t)(SCREEN_YRES) << 11,
|
||||
0
|
||||
};
|
||||
|
||||
// Start playback after we don't need the CD anymore.
|
||||
sound_play_xa("\\AUDIO\\BGM001.XA;1", 0, music_channel, 7100);
|
||||
sound_play_xa("\\BGM\\BGM001.XA;1", 0, music_channel, 7100);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -80,21 +83,17 @@ engine_update()
|
|||
sound_update();
|
||||
pad_update();
|
||||
|
||||
if(x < (SPRTSZ >> 1) || x > (SCREEN_XRES - 32)) dx = -dx;
|
||||
if(y < (SPRTSZ >> 1) || y > (SCREEN_YRES - 32)) dy = -dy;
|
||||
/* if(x < (SPRTSZ >> 1) || x > (SCREEN_XRES - 32)) dx = -dx; */
|
||||
/* if(y < (SPRTSZ >> 1) || y > (SCREEN_YRES - 32)) dy = -dy; */
|
||||
|
||||
x += dx;
|
||||
y += dy;
|
||||
/* x += dx; */
|
||||
/* y += dy; */
|
||||
|
||||
rotation.vx += 6;
|
||||
rotation.vy -= 8;
|
||||
rotation.vz -= 12;
|
||||
|
||||
int channel_changed = 0;
|
||||
/* if(pad_pressed(PAD_CROSS)) { */
|
||||
/* music_channel = (music_channel + 1) % MUSIC_NUM_CHANNELS; */
|
||||
/* sound_xa_set_channel(music_channel); */
|
||||
/* } */
|
||||
if(pad_pressed(PAD_R1)) {
|
||||
music_channel++;
|
||||
channel_changed = 1;
|
||||
|
@ -120,19 +119,19 @@ engine_draw()
|
|||
player_draw(&player);
|
||||
|
||||
// Gouraud-shaded SQUARE
|
||||
POLY_G4 *poly = (POLY_G4 *) get_next_prim();
|
||||
setPolyG4(poly);
|
||||
setXY4(poly,
|
||||
x - (SPRTSZ >> 1), y - (SPRTSZ >> 1),
|
||||
x + (SPRTSZ >> 1), y - (SPRTSZ >> 1),
|
||||
x - (SPRTSZ >> 1), y + (SPRTSZ >> 1),
|
||||
x + (SPRTSZ >> 1), y + (SPRTSZ >> 1));
|
||||
setRGB0(poly, 255, 0, 0);
|
||||
setRGB1(poly, 0, 255, 0);
|
||||
setRGB2(poly, 0, 0, 255);
|
||||
setRGB3(poly, 255, 255, 0);
|
||||
sort_prim(poly, 1);
|
||||
increment_prim(sizeof(POLY_G4));
|
||||
/* POLY_G4 *poly = (POLY_G4 *) get_next_prim(); */
|
||||
/* setPolyG4(poly); */
|
||||
/* setXY4(poly, */
|
||||
/* x - (SPRTSZ >> 1), y - (SPRTSZ >> 1), */
|
||||
/* x + (SPRTSZ >> 1), y - (SPRTSZ >> 1), */
|
||||
/* x - (SPRTSZ >> 1), y + (SPRTSZ >> 1), */
|
||||
/* x + (SPRTSZ >> 1), y + (SPRTSZ >> 1)); */
|
||||
/* setRGB0(poly, 255, 0, 0); */
|
||||
/* setRGB1(poly, 0, 255, 0); */
|
||||
/* setRGB2(poly, 0, 0, 255); */
|
||||
/* setRGB3(poly, 255, 255, 0); */
|
||||
/* sort_prim(poly, 1); */
|
||||
/* increment_prim(sizeof(POLY_G4)); */
|
||||
|
||||
// Gouraud-shaded cube
|
||||
RotMatrix(&rotation, &world);
|
||||
|
|
13
src/player.c
13
src/player.c
|
@ -1,10 +1,12 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "player.h"
|
||||
#include "util.h"
|
||||
#include "input.h"
|
||||
#include "render.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "sound.h"
|
||||
|
||||
#define TMP_ANIM_SPD 7
|
||||
#define ANIM_IDLE_TIMER_MAX 180
|
||||
|
@ -22,6 +24,8 @@
|
|||
#define ANIM_CROUCHDOWN 0x104802fd
|
||||
#define ANIM_LOOKUP 0x067001db
|
||||
|
||||
SoundEffect sfx_jump = { 0 };
|
||||
|
||||
void
|
||||
load_player(Player *player,
|
||||
const char *chara_filename,
|
||||
|
@ -36,6 +40,8 @@ load_player(Player *player,
|
|||
player->anim_dir = 1;
|
||||
player->idle_timer = ANIM_IDLE_TIMER_MAX;
|
||||
player->grnd = player->jmp = 0;
|
||||
|
||||
if(sfx_jump.addr == 0) sfx_jump = sound_load_vag("\\SFX\\JUMP.VAG;1");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -153,6 +159,7 @@ player_update(Player *player)
|
|||
player->grnd = 0;
|
||||
player->jmp = 1;
|
||||
player_set_animation_direct(player, ANIM_ROLLING);
|
||||
sound_play_vag(sfx_jump);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
60
src/sound.c
60
src/sound.c
|
@ -4,6 +4,7 @@
|
|||
#include <psxspu.h>
|
||||
#include <psxapi.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// First 4KB of SPU RAM are reserved for capture buffers.
|
||||
// psxspu additionally uploads a dummy sample (16 bytes) at 0x1000
|
||||
|
@ -18,6 +19,11 @@
|
|||
// everything (in this case, resetting this pointer).
|
||||
static uint32_t next_sample_addr = SPU_ALLOC_START_ADDR;
|
||||
|
||||
// Address of next channel for playing .VAG samples.
|
||||
// Channels are always cycling.
|
||||
#define MAX_CHANNELS 24
|
||||
static int32_t next_channel = 0;
|
||||
|
||||
// Used by the CD handler callback as a temporary area for
|
||||
// sectors read from the CD. Due to DMA limitations, it can't
|
||||
// be allocated on the stack -- especially not in the interrupt
|
||||
|
@ -34,6 +40,7 @@ static uint32_t _xa_loopback_sector = 0;
|
|||
#define CD_MAX_ERR_THRESHOLD 10
|
||||
static uint8_t _cd_err_threshold = 0;
|
||||
|
||||
// Elapsed CD sectors from start of .XA playback
|
||||
static uint32_t _cd_elapsed_sectors = 0;
|
||||
|
||||
void
|
||||
|
@ -63,7 +70,7 @@ sound_get_cd_status(void)
|
|||
}
|
||||
|
||||
uint32_t
|
||||
sound_upload_sample(const uint32_t *data, uint32_t size)
|
||||
sound_upload_vag(const uint32_t *data, uint32_t size)
|
||||
{
|
||||
uint32_t addr = next_sample_addr;
|
||||
// Round size up to a multiple of 64, since DMA transfers
|
||||
|
@ -83,6 +90,57 @@ sound_upload_sample(const uint32_t *data, uint32_t size)
|
|||
return addr;
|
||||
}
|
||||
|
||||
SoundEffect
|
||||
sound_load_vag(const char *filename)
|
||||
{
|
||||
uint8_t *bytes;
|
||||
uint32_t length;
|
||||
bytes = file_read(filename, &length);
|
||||
if(bytes == NULL) {
|
||||
printf("Error reading VAG file %s from the CD.\n", filename);
|
||||
return (SoundEffect){ 0 };
|
||||
}
|
||||
|
||||
const VAGHeader *hdr = (const VAGHeader *)bytes;
|
||||
const uint32_t *data = (const uint32_t *)(bytes + sizeof(VAGHeader));
|
||||
uint32_t sample_rate = __builtin_bswap32(hdr->sample_rate);
|
||||
uint32_t addr = sound_upload_vag(data, __builtin_bswap32(hdr->size));
|
||||
free(bytes);
|
||||
return (SoundEffect) { addr, sample_rate };
|
||||
}
|
||||
|
||||
int32_t
|
||||
_get_next_channel()
|
||||
{
|
||||
int32_t ch = next_channel;
|
||||
next_channel = (ch + 1) % MAX_CHANNELS;
|
||||
return ch;
|
||||
}
|
||||
|
||||
void
|
||||
sound_play_vag(SoundEffect sfx)
|
||||
{
|
||||
int ch = _get_next_channel();
|
||||
SpuSetKey(0, 1 << ch);
|
||||
|
||||
// SPU expects sample rate to be in 4.12 fixed-point format
|
||||
// (with 1.0 = 44100 Hz), and the address must be in 8-byte
|
||||
// units.
|
||||
SPU_CH_FREQ(ch) = getSPUSampleRate(sfx.sample_rate);
|
||||
SPU_CH_ADDR(ch) = getSPUAddr(sfx.addr);
|
||||
|
||||
// Set channel volume and ADSR parameters.
|
||||
// 0x80ff and 0x1fee are dummy values that disable ADSR envelope entirely.
|
||||
SPU_CH_VOL_L(ch) = 0x3fff;
|
||||
SPU_CH_VOL_R(ch) = 0x3fff;
|
||||
SPU_CH_ADSR1(ch) = 0x00ff;
|
||||
SPU_CH_ADSR2(ch) = 0x0000;
|
||||
|
||||
// Start playback
|
||||
SpuSetKey(1, 1 << ch);
|
||||
}
|
||||
|
||||
|
||||
void _xacd_event_callback(CdlIntrResult, uint8_t *);
|
||||
|
||||
void
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue