dbeef / spelunky-psp

Spelunky remake for Sony PSP.
Other
138 stars 10 forks source link

Audio #63

Closed dbeef closed 4 years ago

dbeef commented 4 years ago

What worries me is that PSP refuses to open an audio device with any sampling rate other than 44100 Hz, forcing to use high precision audio format that bloats final binary size (as music and sounds are resource-compiled). Just for comparison, SpelunkyPSP Linux artifact before was ~5 MB, after ~16 MB.

Need to do some further research on this.

EDIT 1:

As I investigated, I started searching through the toolchain SDK sources and stumbled upon psp-ports/SDL/src/audio/psp/SDL_pspaudio.c, with the interesting fragment being:

...
static int PSPAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
    int format, mixlen, i;

    switch (spec->format & 0xff) {
        case 8:
        case 16:
            spec->format = AUDIO_S16LSB;
            break;
        default:
            SDL_SetError("Unsupported audio format");
            return -1;
    }

    /* The sample count must be a multiple of 64. */
    spec->samples = PSP_AUDIO_SAMPLE_ALIGN(spec->samples);
    spec->freq = 44100;

    /* Update the fragment size as size in bytes. */
    SDL_CalculateAudioSpec(spec);

    /* Allocate the mixing buffer.  Its size and starting address must
       be a multiple of 64 bytes.  Our sample count is already a multiple of
       64, so spec->size should be a multiple of 64 as well. */
    mixlen = spec->size * NUM_BUFFERS;
    this->hidden->rawbuf = (Uint8 *) memalign(64, mixlen);
    if (this->hidden->rawbuf == NULL) {
        SDL_SetError("Couldn't allocate mixing buffer");
        return -1;
    }

    /* Setup the hardware channel. */
    if (spec->channels == 1) {
        format = PSP_AUDIO_FORMAT_MONO;
    } else {
        format = PSP_AUDIO_FORMAT_STEREO;
    }
    this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, spec->samples, format);
    if (this->hidden->channel < 0) {
        SDL_SetError("Couldn't reserve hardware channel");
        free(this->hidden->rawbuf);
        this->hidden->rawbuf = NULL;
        return -1;
    }

    memset(this->hidden->rawbuf, 0, mixlen);
    for (i = 0; i < NUM_BUFFERS; i++) {
        this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * spec->size];
    }

    this->hidden->next_buffer = 0;
    return 0;
}
...

Which explains why I was refused to open an audio device with sampling frequency any other than 44100 Hz. Seems I am stuck to this format for good. Using platform-specific libraries directly most probably won't help either, judging by pspaudio_kernel.h:

/*
 * PSP Software Development Kit - https://github.com/pspdev
 * -----------------------------------------------------------------------
 * Licensed under the BSD license, see LICENSE in PSPSDK root for details.
 *
 * pspaudio.h - Prototypes for the sceAudio library.
 *
 * Copyright (c) 2005 Adresd
 * Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
 * Copyright (c) 2007 cooleyes
 * Copyright (c) 2007 Alexander Berl <raphael@fx-world.org>
 *
 */
#ifndef PSPAUDIO_KERNEL_H
#define PSPAUDIO_KERNEL_H

#ifdef __cplusplus
extern "C" {
#endif

/** @defgroup Audio User Audio Library */

/** @addtogroup Audio */

/*@{*/

enum PspAudioFrequencies {
    /** Sampling frequency set to 44100Hz. */
    PSP_AUDIO_FREQ_44K = 44100,
    /** Sampling frequency set to 48000Hz. */
    PSP_AUDIO_FREQ_48K = 48000
};

/**
  * Set audio sampling frequency
  *
  * @param frequency - Sampling frequency to set audio output to - either 44100 or 48000.
  *
  * @return 0 on success, an error if less than 0.
  */
int sceAudioSetFrequency(int frequency);
/*@}*/

#ifdef __cplusplus
}
#endif

#endif /* PSPAUDIO_KERNEL_H */

It must be some hardware constraint.

EDIT 2: Loading U8 encoded audio instead of S16LSB is not allowed either (same reason as in case of sampling rate, look at the SDL_pspaudio.c that I posted).

EDIT 3: Concluding - by resource-compiling sounds and music, SpelunkyPSP artifact for the PSP (the .PBP file) grew from 1.7 MB to 14 MB - more than 8 times bigger! That's awful, but in the same time, PSP has in the worst case 32 MB (the PSP-1000 "fat" model), and in the best case 64 MB (every other model). The game itself needs roughly 1MB in the runtime, that still leaves about 17 MB for further development.

The problem will definitely reoccur in the far future when implementing another biomes (jungle, lava city, yeti level), as they have their own audio themes that I do not add in this MR. In such case, implementing filesystem support may happen to be required to finish the project.

dbeef commented 4 years ago

Thanks to @TheMrIron2, here are Quake's PSP sources for a reference:

https://github.com/st1x51/DQuakePlus/blob/master/psp/sound.cpp

It uses 11025 Hz on input and upsamples them before passing to the platform-specific library.

dbeef commented 4 years ago

Thanks to @mrneo240 - in fact it is possible to use platform-specific libraries to play non 44.1 kHz audio on the PSP:

https://github.com/z2442/sm64-port/blob/master/src/pc/audio/audio_psp.c