123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- #include "util.h"
- #include "global.h"
- #include "players.h"
- #include "sound.h"
- #include <math.h>
- #if PAL_HAS_OGG
- #include <vorbis\vorbisfile.h>
- #include "resampler.h"
- #define FLAG_OY 0x01
- #define FLAG_VI 0x02
- #define FLAG_VC 0x04
- #define FLAG_OS 0x08
- #define FLAG_VD 0x10
- #define FLAG_VB 0x20
- #define STAGE_PAGEOUT 1
- #define STAGE_PACKETOUT 2
- #define STAGE_PCMOUT 3
- #define STAGE_REWIND 4
- #define OGG_BUFFER_LENGTH 4096
- typedef struct tagOGGPLAYER
- {
- MUSICPLAYER_FUNCTIONS;
- ogg_sync_state oy;
- ogg_stream_state os;
- ogg_page og;
- vorbis_info vi;
- vorbis_comment vc;
- vorbis_dsp_state vd;
- vorbis_block vb;
- FILE *fp;
- void *resampler[2];
- INT iFlags;
- INT iMusic;
- INT iStage;
- INT nChannels;
- BOOL fLoop;
- BOOL fReady;
- BOOL fUseResampler;
- } OGGPLAYER, *LPOGGPLAYER;
- static SDL_FORCE_INLINE ogg_int16_t OGG_GetSample(float pcm, double volume)
- {
- int val = (int)(floor(pcm * 32767.f + .5f) * volume);
-
- if (val > 32767) {
- val = 32767;
- }
- else if (val < -32768) {
- val = -32768;
- }
- return (ogg_int16_t)val;
- }
- static SDL_FORCE_INLINE void OGG_FillResample(LPOGGPLAYER player, ogg_int16_t* stream)
- {
- if (gpGlobals->iAudioChannels == 2) {
- stream[0] = SDL_SwapLE16(resampler_get_and_remove_sample(player->resampler[0]));
- stream[1] = (player->vi.channels > 1) ? SDL_SwapLE16(resampler_get_and_remove_sample(player->resampler[1])) : stream[0];
- }
- else {
- if (player->vi.channels > 1) {
- *stream = SDL_SwapLE16((short)((int)(resampler_get_and_remove_sample(player->resampler[0]) + resampler_get_and_remove_sample(player->resampler[1])) >> 1));
- }
- else {
- *stream = SDL_SwapLE16(resampler_get_and_remove_sample(player->resampler[0]));
- }
- }
- }
- static void OGG_Cleanup(LPOGGPLAYER player)
- {
- int i;
- for (i = 0; i < gpGlobals->iAudioChannels; i++) resampler_clear(player->resampler[0]);
-
- if (player->iFlags & FLAG_VB) vorbis_block_clear(&player->vb);
- if (player->iFlags & FLAG_VD) vorbis_dsp_clear(&player->vd);
- if (player->iFlags & FLAG_OS) ogg_stream_clear(&player->os);
- if (player->iFlags & FLAG_VC) vorbis_comment_clear(&player->vc);
- if (player->iFlags & FLAG_VI) vorbis_info_clear(&player->vi);
- if (player->iFlags & FLAG_OY) ogg_sync_clear(&player->oy);
- player->iFlags = player->iStage = 0;
- player->fReady = FALSE;
- }
- static BOOL OGG_Rewind(LPOGGPLAYER player)
- {
- ogg_packet op;
- char *buffer;
- int i, bytes;
- OGG_Cleanup(player);
- fseek(player->fp, 0, SEEK_SET);
- ogg_sync_init(&player->oy); player->iFlags = FLAG_OY;
-
-
- buffer = ogg_sync_buffer(&player->oy, OGG_BUFFER_LENGTH);
- bytes = fread(buffer, 1, OGG_BUFFER_LENGTH, player->fp);
- ogg_sync_wrote(&player->oy, bytes);
-
- if (ogg_sync_pageout(&player->oy, &player->og) != 1) {
-
-
- OGG_Cleanup(player);
- return (player->fReady = FALSE);
- }
-
-
- ogg_stream_init(&player->os, ogg_page_serialno(&player->og));
- player->iFlags |= FLAG_OS;
-
-
- vorbis_info_init(&player->vi); player->iFlags |= FLAG_VI;
- vorbis_comment_init(&player->vc); player->iFlags |= FLAG_VC;
- if (ogg_stream_pagein(&player->os, &player->og)<0) {
-
- OGG_Cleanup(player);
- return (player->fReady = FALSE);
- }
- if (ogg_stream_packetout(&player->os, &op) != 1) {
-
- OGG_Cleanup(player);
- return (player->fReady = FALSE);
- }
- if (vorbis_synthesis_headerin(&player->vi, &player->vc, &op)<0) {
-
- OGG_Cleanup(player);
- return (player->fReady = FALSE);
- }
-
-
- i = 0;
- while (i < 2) {
- while (i < 2) {
- int result = ogg_sync_pageout(&player->oy, &player->og);
- if (result == 0)break;
-
- if (result == 1) {
- ogg_stream_pagein(&player->os, &player->og);
- while (i < 2) {
- result = ogg_stream_packetout(&player->os, &op);
- if (result == 0)break;
- if (result < 0) {
-
- OGG_Cleanup(player);
- return (player->fReady = FALSE);
- }
- result = vorbis_synthesis_headerin(&player->vi, &player->vc, &op);
- if (result < 0) {
- OGG_Cleanup(player);
- return (player->fReady = FALSE);
- }
- i++;
- }
- }
- }
-
- buffer = ogg_sync_buffer(&player->oy, OGG_BUFFER_LENGTH);
- bytes = fread(buffer, 1, OGG_BUFFER_LENGTH, player->fp);
- if (bytes == 0 && i < 2) {
- OGG_Cleanup(player);
- return (player->fReady = FALSE);
- }
- ogg_sync_wrote(&player->oy, bytes);
- }
- if (vorbis_synthesis_init(&player->vd, &player->vi) == 0) {
- vorbis_block_init(&player->vd, &player->vb);
- player->iStage = STAGE_PAGEOUT;
- player->iFlags |= FLAG_VD | FLAG_VB;
- if (player->fUseResampler = player->vi.rate != gpGlobals->iSampleRate) {
- double factor = (double)player->vi.rate / (double)gpGlobals->iSampleRate;
- for (i = 0; i < min(player->vi.channels, 2); i++)
- {
- resampler_set_quality(player->resampler[i], SOUND_IsIntegerConversion(player->vi.rate) ? RESAMPLER_QUALITY_MIN : gpGlobals->iResampleQuality);
- resampler_set_rate(player->resampler[i], factor);
- resampler_clear(player->resampler[i]);
- }
- }
- return (player->fReady = TRUE);
- }
- else {
- OGG_Cleanup(player);
- return (player->fReady = FALSE);
- }
- }
- static VOID
- OGG_FillBuffer(
- VOID *object,
- LPBYTE stream,
- INT len
- )
- {
- LPOGGPLAYER player = (LPOGGPLAYER)object;
- if (player->fReady) {
- ogg_packet op;
- double volume = (double)gpGlobals->iVolume / (SDL_MIX_MAXVOLUME * 3 / 4);
- int total_bytes = 0, stage = player->iStage;
- while (total_bytes < len) {
- float **pcm;
- int samples, result;
- switch (stage)
- {
- case STAGE_PAGEOUT:
- result = ogg_sync_pageout(&player->oy, &player->og);
- if (result > 0) {
-
- ogg_stream_pagein(&player->os, &player->og);
- stage = STAGE_PACKETOUT;
- }
- else {
- if (result == 0) {
- char *buffer = ogg_sync_buffer(&player->oy, OGG_BUFFER_LENGTH);
- int bytes = fread(buffer, 1, OGG_BUFFER_LENGTH, player->fp);
- ogg_sync_wrote(&player->oy, bytes);
- stage = (bytes > 0) ? STAGE_PAGEOUT : STAGE_REWIND;
- }
- break;
- }
- case STAGE_PACKETOUT:
- result = ogg_stream_packetout(&player->os, &op);
- if (result > 0) {
-
- if (vorbis_synthesis(&player->vb, &op) == 0) {
- vorbis_synthesis_blockin(&player->vd, &player->vb);
- }
- stage = STAGE_PCMOUT;
- }
- else {
- if (result == 0) {
- if (ogg_page_eos(&player->og)) {
- if (player->fLoop) {
- stage = STAGE_REWIND;
- }
- else {
- OGG_Cleanup(player);
- UTIL_CloseFile(player->fp);
- player->fp = NULL;
- return;
- }
- }
- else {
- stage = STAGE_PAGEOUT;
- }
- }
- break;
- }
- case STAGE_PCMOUT:
- if ((samples = vorbis_synthesis_pcmout(&player->vd, &pcm)) > 0) {
- int bout;
- if (player->fUseResampler) {
- bout = 0;
- while (total_bytes < len && samples > 0) {
- int i, j, to_write = resampler_get_free_count(player->resampler[0]);
- if (to_write > 0) {
- if (to_write >= samples) to_write = samples;
- for (i = 0; i < min(player->vi.channels, 2); i++) {
- float *mono = pcm[i] + bout;
- for (j = 0; j < to_write; j++) {
- resampler_write_sample(player->resampler[i], OGG_GetSample(mono[j], volume));
- }
- }
- }
-
- j = resampler_get_sample_count(player->resampler[0]);
- while (total_bytes < len && resampler_get_sample_count(player->resampler[0]) > 0) {
- OGG_FillResample(player, (ogg_int16_t *)(stream + total_bytes));
- total_bytes += gpGlobals->iAudioChannels * sizeof(ogg_int16_t);
- }
- samples -= to_write; bout += to_write;
- }
- }
- else {
- int i;
- ogg_int16_t *ptr = (ogg_int16_t *)(stream + total_bytes);
- bout = (len - total_bytes) / gpGlobals->iAudioChannels / sizeof(ogg_int16_t);
- if (bout > samples) bout = samples;
- for (i = 0; i < bout; i++) {
- if (gpGlobals->iAudioChannels == 2) {
- ptr[0] = SDL_SwapLE16(OGG_GetSample(pcm[0][i], volume));
- ptr[1] = (player->vi.channels > 1) ? SDL_SwapLE16(OGG_GetSample(pcm[1][i], volume)) : ptr[0];
- }
- else {
- if (player->vi.channels > 1) {
- ptr[0] = SDL_SwapLE16((short)((int)(OGG_GetSample(pcm[0][i], volume) + OGG_GetSample(pcm[1][i], volume)) >> 1));
- }
- else {
- ptr[0] = SDL_SwapLE16(OGG_GetSample(pcm[0][i], volume));
- }
- }
- ptr += gpGlobals->iAudioChannels;
- }
- total_bytes += bout * gpGlobals->iAudioChannels * sizeof(ogg_int16_t);
- }
-
- vorbis_synthesis_read(&player->vd, bout);
- }
- else {
- stage = STAGE_PACKETOUT;
- }
- break;
- case STAGE_REWIND:
- if (player->vi.rate != gpGlobals->iSampleRate) {
- while (total_bytes < len && resampler_get_sample_count(player->resampler[0]) > 0) {
- OGG_FillResample(player, (ogg_int16_t *)(stream + total_bytes));
- total_bytes += gpGlobals->iAudioChannels * sizeof(ogg_int16_t);
- }
-
- if (resampler_get_sample_count(player->resampler[0]) > 0) break;
- }
- OGG_Rewind(player);
- stage = player->iStage;
- break;
- default:
- return;
- }
- }
- player->iStage = stage;
- }
- }
- static BOOL
- OGG_Play(
- VOID *object,
- INT iNum,
- BOOL fLoop,
- FLOAT flFadeTime
- )
- {
- char filename[256];
- LPOGGPLAYER player = (LPOGGPLAYER)object;
-
-
-
- if (player == NULL)
- {
- return FALSE;
- }
- player->fLoop = fLoop;
- if (iNum == player->iMusic)
- {
- return TRUE;
- }
- player->fReady = FALSE;
- OGG_Cleanup(player);
- if (player->fp)
- {
- UTIL_CloseFile(player->fp);
- player->fp = NULL;
- }
- if (iNum == -1)
- {
- return TRUE;
- }
- player->fp = UTIL_OpenFile(strcpy(filename, va("ogg/%.2d.ogg", iNum)));
- if (player->fp == NULL)
- {
- return FALSE;
- }
- else
- {
- player->iMusic = iNum;
- }
- if (!OGG_Rewind(player))
- {
- UTIL_CloseFile(player->fp);
- player->fp = NULL;
- return FALSE;
- }
- return TRUE;
- }
- static VOID
- OGG_Shutdown(
- VOID *object
- )
- {
- if (object)
- {
- LPOGGPLAYER player = (LPOGGPLAYER)object;
- OGG_Cleanup(player);
- resampler_delete(player->resampler[0]);
- resampler_delete(player->resampler[1]);
- UTIL_CloseFile(player->fp);
- free(player);
- }
- }
- LPMUSICPLAYER
- OGG_Init(
- LPCSTR szFileName
- )
- {
- LPOGGPLAYER player;
- if (player = (LPOGGPLAYER)malloc(sizeof(OGGPLAYER)))
- {
- memset(player, 0, sizeof(LPOGGPLAYER));
- player->FillBuffer = OGG_FillBuffer;
- player->Play = OGG_Play;
- player->Shutdown = OGG_Shutdown;
- player->fp = NULL;
- player->iMusic = -1;
- player->iFlags = 0;
- player->iStage = 0;
- player->fLoop = FALSE;
- player->fReady = FALSE;
- player->fUseResampler = FALSE;
- player->resampler[0] = resampler_create();
- if (player->resampler[0])
- {
- player->resampler[1] = resampler_create();
- if (player->resampler[1] == NULL)
- {
- resampler_delete(player->resampler[0]);
- player->resampler[0] = NULL;
- }
- }
- return (LPMUSICPLAYER)player;
- }
- else
- {
- return NULL;
- }
- }
- #endif
|