⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 load_voc.c

📁 SDL_mixer 是一个基于 SDL 的混音器
💻 C
字号:
/*    SDL_mixer:  An audio mixer library based on the SDL library    Copyright (C) 1997-2004 Sam Lantinga    This library is free software; you can redistribute it and/or    modify it under the terms of the GNU Library General Public    License as published by the Free Software Foundation; either    version 2 of the License, or (at your option) any later version.    This library is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    Library General Public License for more details.    You should have received a copy of the GNU Library General Public    License along with this library; if not, write to the Free    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA    This is the source needed to decode a Creative Labs VOC file into a    waveform. It's pretty straightforward once you get going. The only    externally-callable function is Mix_LoadVOC_RW(), which is meant to    act as identically to SDL_LoadWAV_RW() as possible.    This file by Ryan C. Gordon (icculus@linuxgames.com).    Heavily borrowed from sox v12.17.1's voc.c.        (http://www.freshmeat.net/projects/sox/)*//* $Id: load_voc.c 2394 2006-05-11 19:30:52Z slouken $ */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "SDL_mutex.h"#include "SDL_endian.h"#include "SDL_timer.h"#include "SDL_mixer.h"#include "load_voc.h"/* Private data for VOC file */typedef struct vocstuff {	Uint32	rest;			/* bytes remaining in current block */	Uint32	rate;			/* rate code (byte) of this chunk */	int 	silent;		/* sound or silence? */	Uint32	srate;			/* rate code (byte) of silence */	Uint32	blockseek;		/* start of current output block */	Uint32	samples;		/* number of samples output */	Uint32	size;		/* word length of data */	Uint8 	channels;	/* number of sound channels */	int     has_extended;       /* Has an extended block been read? */} vs_t;/* Size field */ /* SJB: note that the 1st 3 are sometimes used as sizeof(type) */#define	ST_SIZE_BYTE	1#define ST_SIZE_8BIT	1#define	ST_SIZE_WORD	2#define ST_SIZE_16BIT	2#define	ST_SIZE_DWORD	4#define ST_SIZE_32BIT	4#define	ST_SIZE_FLOAT	5#define ST_SIZE_DOUBLE	6#define ST_SIZE_IEEE	7	/* IEEE 80-bit floats. *//* Style field */#define ST_ENCODING_UNSIGNED	1 /* unsigned linear: Sound Blaster */#define ST_ENCODING_SIGN2	2 /* signed linear 2's comp: Mac */#define	ST_ENCODING_ULAW	3 /* U-law signed logs: US telephony, SPARC */#define ST_ENCODING_ALAW	4 /* A-law signed logs: non-US telephony */#define ST_ENCODING_ADPCM	5 /* Compressed PCM */#define ST_ENCODING_IMA_ADPCM	6 /* Compressed PCM */#define ST_ENCODING_GSM		7 /* GSM 6.10 33-byte frame lossy compression */#define	VOC_TERM	0#define	VOC_DATA	1#define	VOC_CONT	2#define	VOC_SILENCE	3#define	VOC_MARKER	4#define	VOC_TEXT	5#define	VOC_LOOP	6#define	VOC_LOOPEND	7#define VOC_EXTENDED    8#define VOC_DATA_16	9static int voc_check_header(SDL_RWops *src){    /* VOC magic header */    Uint8  signature[20];  /* "Creative Voice File\032" */    Uint16 datablockofs;    SDL_RWseek(src, 0, SEEK_SET);    if (SDL_RWread(src, signature, sizeof (signature), 1) != 1)        return(0);    if (memcmp(signature, "Creative Voice File\032", sizeof (signature)) != 0) {        SDL_SetError("Unrecognized file type (not VOC)");        return(0);    }        /* get the offset where the first datablock is located */    if (SDL_RWread(src, &datablockofs, sizeof (Uint16), 1) != 1)        return(0);    datablockofs = SDL_SwapLE16(datablockofs);    if (SDL_RWseek(src, datablockofs, SEEK_SET) != datablockofs)        return(0);    return(1);  /* success! */} /* voc_check_header *//* Read next block header, save info, leave position at start of data */static int voc_get_block(SDL_RWops *src, vs_t *v, SDL_AudioSpec *spec){    Uint8 bits24[3];    Uint8 uc, block;    Uint32 sblen;    Uint16 new_rate_short;    Uint32 new_rate_long;    Uint8 trash[6];    Uint16 period;    unsigned int i;    v->silent = 0;    while (v->rest == 0)    {        if (SDL_RWread(src, &block, sizeof (block), 1) != 1)            return 1;  /* assume that's the end of the file. */        if (block == VOC_TERM)            return 1;        if (SDL_RWread(src, bits24, sizeof (bits24), 1) != 1)            return 1;  /* assume that's the end of the file. */                /* Size is an 24-bit value. Ugh. */        sblen = ( (bits24[0]) | (bits24[1] << 8) | (bits24[2] << 16) );        switch(block)        {            case VOC_DATA:                if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)                    return 0;                /* When DATA block preceeded by an EXTENDED     */                /* block, the DATA blocks rate value is invalid */                if (!v->has_extended)                {                    if (uc == 0)                    {                        SDL_SetError("VOC Sample rate is zero?");                        return 0;                    }                    if ((v->rate != -1) && (uc != v->rate))                    {                        SDL_SetError("VOC sample rate codes differ");                        return 0;                    }                    v->rate = uc;                    spec->freq = (Uint16)(1000000.0/(256 - v->rate));                    v->channels = 1;                }                if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)                    return 0;                if (uc != 0)                {                    SDL_SetError("VOC decoder only interprets 8-bit data");                    return 0;                }                v->has_extended = 0;                v->rest = sblen - 2;                v->size = ST_SIZE_BYTE;                return 1;            case VOC_DATA_16:                if (SDL_RWread(src, &new_rate_long, sizeof (new_rate_long), 1) != 1)                    return 0;                new_rate_long = SDL_SwapLE32(new_rate_long);                if (new_rate_long == 0)                {                    SDL_SetError("VOC Sample rate is zero?");                    return 0;                }                if ((v->rate != -1) && (new_rate_long != v->rate))                {                    SDL_SetError("VOC sample rate codes differ");                    return 0;                }                v->rate = new_rate_long;                spec->freq = new_rate_long;                if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)                    return 0;                switch (uc)                {                    case 8:  v->size = ST_SIZE_BYTE; break;                    case 16: v->size = ST_SIZE_WORD; break;                    default:                        SDL_SetError("VOC with unknown data size");                        return 0;                }                if (SDL_RWread(src, &v->channels, sizeof (Uint8), 1) != 1)                    return 0;                if (SDL_RWread(src, trash, sizeof (Uint8), 6) != 6)                    return 0;                v->rest = sblen - 12;                return 1;            case VOC_CONT:                v->rest = sblen;                return 1;            case VOC_SILENCE:                if (SDL_RWread(src, &period, sizeof (period), 1) != 1)                    return 0;                period = SDL_SwapLE16(period);                if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)                    return 0;                if (uc == 0)                {                    SDL_SetError("VOC silence sample rate is zero");                    return 0;                }                /*                 * Some silence-packed files have gratuitously                 * different sample rate codes in silence.                 * Adjust period.                 */                if ((v->rate != -1) && (uc != v->rate))                    period = (Uint16)((period * (256 - uc))/(256 - v->rate));                else                    v->rate = uc;                v->rest = period;                v->silent = 1;                return 1;            case VOC_LOOP:            case VOC_LOOPEND:                for(i = 0; i < sblen; i++)   /* skip repeat loops. */                {                    if (SDL_RWread(src, trash, sizeof (Uint8), 1) != 1)                        return 0;                }                break;            case VOC_EXTENDED:                /* An Extended block is followed by a data block */                /* Set this byte so we know to use the rate      */                /* value from the extended block and not the     */                /* data block.                     */                v->has_extended = 1;                if (SDL_RWread(src, &new_rate_short, sizeof (new_rate_short), 1) != 1)                    return 0;                new_rate_short = SDL_SwapLE16(new_rate_short);                if (new_rate_short == 0)                {                   SDL_SetError("VOC sample rate is zero");                   return 0;                }                if ((v->rate != -1) && (new_rate_short != v->rate))                {                   SDL_SetError("VOC sample rate codes differ");                   return 0;                }                v->rate = new_rate_short;                if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)                    return 0;                if (uc != 0)                {                    SDL_SetError("VOC decoder only interprets 8-bit data");                    return 0;                }                if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)                    return 0;                if (uc)                    spec->channels = 2;  /* Stereo */                /* Needed number of channels before finishing                   compute for rate */                spec->freq = (256000000L/(65536L - v->rate))/spec->channels;                /* An extended block must be followed by a data */                /* block to be valid so loop back to top so it  */                /* can be grabed.                */                continue;            case VOC_MARKER:                if (SDL_RWread(src, trash, sizeof (Uint8), 2) != 2)                    return 0;                /* Falling! Falling! */            default:  /* text block or other krapola. */                for(i = 0; i < sblen; i++)                {                    if (SDL_RWread(src, &trash, sizeof (Uint8), 1) != 1)                        return 0;                }                if (block == VOC_TEXT)                    continue;    /* get next block */        }    }    return 1;}static int voc_read(SDL_RWops *src, vs_t *v, Uint8 *buf, SDL_AudioSpec *spec){    int done = 0;    Uint8 silence = 0x80;    if (v->rest == 0)    {        if (!voc_get_block(src, v, spec))            return 0;    }    if (v->rest == 0)        return 0;    if (v->silent)    {        if (v->size == ST_SIZE_WORD)            silence = 0x00;        /* Fill in silence */        memset(buf, silence, v->rest);        done = v->rest;        v->rest = 0;    }    else    {        done = SDL_RWread(src, buf, 1, v->rest);        v->rest -= done;        if (v->size == ST_SIZE_WORD)        {            #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)                Uint16 *samples = (Uint16 *)buf;                for (; v->rest > 0; v->rest -= 2)                {                    *samples = SDL_SwapLE16(*samples);                    samples++;                }            #endif            done >>= 1;        }    }    return done;} /* voc_read *//* don't call this directly; use Mix_LoadWAV_RW() for now. */SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, int freesrc,        SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len){    vs_t v;    int was_error = 1;    int samplesize;    Uint8 *fillptr;    void *ptr;    if ( (!src) || (!audio_buf) || (!audio_len) )   /* sanity checks. */        goto done;    if ( !voc_check_header(src) )        goto done;    v.rate = -1;    v.rest = 0;    v.has_extended = 0;    *audio_buf = NULL;    *audio_len = 0;    memset(spec, '\0', sizeof (SDL_AudioSpec));    if (!voc_get_block(src, &v, spec))        goto done;    if (v.rate == -1)    {        SDL_SetError("VOC data had no sound!");        goto done;    }    spec->format = ((v.size == ST_SIZE_WORD) ? AUDIO_S16 : AUDIO_U8);    if (spec->channels == 0)        spec->channels = v.channels;    *audio_len = v.rest;    *audio_buf = malloc(v.rest);    if (*audio_buf == NULL)        goto done;    fillptr = *audio_buf;    while (voc_read(src, &v, fillptr, spec) > 0)    {        if (!voc_get_block(src, &v, spec))            goto done;        *audio_len += v.rest;        ptr = realloc(*audio_buf, *audio_len);        if (ptr == NULL)        {            free(*audio_buf);            *audio_buf = NULL;            *audio_len = 0;            goto done;        }        *audio_buf = ptr;        fillptr = ((Uint8 *) ptr) + (*audio_len - v.rest);    }    spec->samples = (Uint16)(*audio_len / v.size);    was_error = 0;  /* success, baby! */    /* Don't return a buffer that isn't a multiple of samplesize */    samplesize = ((spec->format & 0xFF)/8)*spec->channels;    *audio_len &= ~(samplesize-1);done:    if (src)    {        if (freesrc)            SDL_RWclose(src);        else            SDL_RWseek(src, 0, SEEK_SET);    }    if ( was_error )        spec = NULL;    return(spec);} /* Mix_LoadVOC_RW *//* end of load_voc.c ... */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -