Page 1 of 1

Loading and Playing Wav, problem in Wii

Posted: Wed Sep 29, 2010 12:08 pm
by the_marioga
Hi, see if you can help me, I need to load and play WAV files, but the load function and extracts the header and maybe shoot me a code dump to try, then see if you can lend a hand. (SDL serves me no) (Google Translate)

Dump code files:


Wavplayer.cpp

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "wavplayer.h"

#define IS_BIG_ENDIAN       1

#define MIN(a,b)  ((a) > (b) ? (b) : (a))
#define MAX(a,b)  ((a) < (b) ? (b) : (a))

#define GET3BYTES(p)    ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16))

#define SWAP16(x)\
    ((u16)((((x) & 0x00FF) << 8) | (((x) & 0xFF00) >> 8)))

#define SWAP32(x)\
    ((u32)((((x) & 0x000000FF) << 24) | (((x) & 0x0000FF00) << 8) | \
     (((x) & 0x00FF0000) >> 8) | (((x) & 0xFF000000) >> 24)))

typedef unsigned int        u32;  
typedef unsigned short int  u16; 

#if IS_BIG_ENDIAN
    #define SWAP_ED16(x)    SWAP16(x)
    #define SWAP_ED32(x)    SWAP32(x)
    #define SAMP_ENDIAN     (u16(2))
#else
    #define SWAP_ED16(x)    (x)
    #define SWAP_ED32(x)    (x)
    #define SAMP_ENDIAN     (u16(1))
#endif

void ReverseEndian(void* buffer, int byteWidth, int frames)
{
    switch (byteWidth)
    {
    case 2 :
        {
            u16* pusBuf  = (u16*)buffer;
            for (int i = 0; i < frames; i++) 
            {
                pusBuf[i] = SWAP16(pusBuf[i]);
            }
            break;
        }
    case 3 :
        {
            char* a = (char*)buffer;
            char c; 
            while(--frames >= 0)
            {
                c = a[0];
                a[0] = a[2];
                a[2] = c;
                a += 3;
            }
            break;
        }
    case 4 :
        {
            u32* puiBuf  = (u32*)buffer;
            for (int i = 0; i < frames; i++) 
            {
                puiBuf[i] = SWAP32(puiBuf[i]);
            }
            break;
        }
    default:
        break;
    }
}

int ReadFile( FILE* fd, void *buf, int n, int offset = 0)
{
    if (offset != 0) fseek(fd, offset, SEEK_CUR);
    int readlen = (int)fread(buf, 1, n, fd); 
    return readlen;
}

int CloseFile( FILE* fd)
{
    return fclose(fd); 
}

#define VERIFY_CHUNKID(fd, id, len) \
{   \
    char chunkID[(len)+1];  \
    ReadFile((fd), chunkID, (len));   chunkID[(len)] = char(0); \
    if ( strncmp(&chunkID[0], (id), (len)) )    \
    {   \
        return -1;  \
    }   \
}   
#define LOAD_2BYTES(fd, x)  \
{   \
    ReadFile((fd), &(x), 2);   \
    (x) = SWAP_ED16(x);   \
}
#define LOAD_4BYTES(fd, x)  \
{   \
    ReadFile((fd), &(x), 4);   \
    (x) = SWAP_ED32(x);   \
}

static int _load_pcmwavfmt(FILE* fd, PCMWAVFmt* pFmt)
{
    u32    chunkSize, samplesPerSec, bytesPerSec;
    u16  waveFmtType, channel, blockSize, bitsPerSample;

    VERIFY_CHUNKID(fd, "RIFF", 4);
    LOAD_4BYTES(fd, chunkSize);
    VERIFY_CHUNKID(fd, "WAVEfmt ", 8);
    LOAD_4BYTES(fd, chunkSize);
    LOAD_2BYTES(fd, waveFmtType);
    LOAD_2BYTES(fd, channel);
    LOAD_4BYTES(fd, samplesPerSec);
    LOAD_4BYTES(fd, bytesPerSec);
    LOAD_2BYTES(fd, blockSize);
    LOAD_2BYTES(fd, bitsPerSample);
    VERIFY_CHUNKID(fd, "data", 4);
    LOAD_4BYTES(fd, chunkSize);

    pFmt->sample_rate   = samplesPerSec;
    pFmt->sample_byte   = blockSize/channel;
    pFmt->sample_bit    = bitsPerSample;
    pFmt->sample_count  = chunkSize/blockSize;
    pFmt->sample_channel= channel;
    pFmt->sample_format = waveFmtType;
    return 0;
}

void* LoadPCMWav(const char* file, PCMWAVFmt* pFmt) {
    FILE* fd;
    if (!(fd = fopen(file, "rb"))) {
        return NULL;
    }
    if (_load_pcmwavfmt(fd,pFmt)) {
        CloseFile(fd);
        return NULL;
    }
    //check the wavefile length
    int iLen;
    if ((fseek(fd, 0, SEEK_END)!=0) || ((iLen = ftell(fd))<0) || (fseek(fd, 44L, SEEK_SET)!=0) ) {
        CloseFile(fd);
        return NULL;
    }
    iLen -= 44;

    int wavlen = pFmt->sample_byte*pFmt->sample_count*pFmt->sample_channel;
    if (iLen != wavlen)
    {
        CloseFile(fd);
        return NULL;
    }
    u32 stFrame = (pFmt->start != PCMClock(-1)) ? PCMClock2Frame(pFmt->start, pFmt->sample_rate) : 0;
    u32 enFrame = (pFmt->end   != PCMClock(-1)) ? PCMClock2Frame(pFmt->end  , pFmt->sample_rate) : pFmt->sample_count;
    enFrame = MIN(enFrame, pFmt->sample_count);
    stFrame = MIN(stFrame, enFrame);
    u32 npad = enFrame - stFrame; 
    if ( npad <= 0 )
    {
        CloseFile(fd);
        return NULL;
    }
    int vecSize = pFmt->sample_byte*pFmt->sample_channel;
    int offset = stFrame * vecSize;
    void* pWav = (void*)memalign(128, npad*vecSize);

    u32 readlen = ReadFile(fd, pWav, npad*vecSize, offset);
    if (readlen != npad*vecSize)
    {
        CloseFile(fd);
        free(pWav);
        return NULL;
    }
    if (pFmt->sample_format != SAMP_ENDIAN)
    {
        ReverseEndian(pWav, pFmt->sample_byte, pFmt->sample_count*pFmt->sample_channel);
    } 
    pFmt->sample_format = SAMP_ENDIAN;
    pFmt->sample_count  = npad;
    return pWav;
}
Wavplayer.h

Code: Select all

#ifndef _PCMWAVFILE_H
#define _PCMWAVFILE_H

typedef unsigned long long	PCMClock;

typedef struct _PCMWAVFmt {
    unsigned int    sample_rate;    /* Sample frequency                 */
    unsigned short  sample_byte;    /* number of bytes per sample       */
    unsigned short  sample_bit;     /* number of valid bits per sample  */
    unsigned int    sample_count;   /* number of samples                */
    unsigned short  sample_channel; /* number of channels per sample    */
    unsigned short  sample_format;  /* little-endian(1), big-endian(2)  */
    PCMClock start, end;            /* start/end time in 100ns          */
}PCMWAVFmt;

#define PCMClock2Frame(clock, samprate) \
    ((unsigned int)(PCMClock(samprate)*(clock)/PCMClock(10000000)))

#define Frame2PCMClock(frame, samprate) \
        (PCMClock(frame)*PCMClock(10000000)/PCMClock(samprate))

#if defined(__LANGUAGE_C_PLUS_PLUS)||defined(__cplusplus)||defined(c_plusplus)
extern "C" {
#endif

void* LoadPCMWav(const char* file, PCMWAVFmt* pFmt);

#if defined(__LANGUAGE_C_PLUS_PLUS)||defined(__cplusplus)||defined(c_plusplus)
}
#endif
#endif // _PCMWAVFILE_H
Luego lo uso asi:

Code: Select all

	PCMWAVFmt* pFmt;
int wavPlay(const char* file) {
	void *buf = LoadPCMWav(file, pFmt);
	if (buf) {
		ASND_SetVoice(ASND_GetFirstUnusedVoice(), VOICE_STEREO_16BIT, 8000,0, buf, sizeof(buf), 255, 255, NULL);
	} else {
		return 0;
	}
	return 1;
}

Re: Loading and Playing Wav, problem in Wii

Posted: Wed Sep 29, 2010 3:48 pm
by Izhido
Hola! Mira... me temo que, en realidad, no entendimos bien tu duda. Google Translate, con toda la buena intención que tuvieron de ofrecer un servicio de traducción decente, a veces no logra bien su cometido. Creo que necesitaremos que reformules la pregunta (en inglés, por favor - no habemos muchos aquí que hablen español) a ver si logramos entender que ocurre con tu código. De acuerdo?
-----------------------------------------------------
Hello! Look.. I'm afraid we actually didn't understand your question. With Google Translate, well, as much as they tried to offer a decent translation services, it sometimes doesn't make the cut. I think we need you to reformulate your question (English please - very few of us speak Spanish in here) so we can get an idea of what might be wrong with your code. Deal?

Re: Loading and Playing Wav, problem in Wii

Posted: Wed Sep 29, 2010 7:41 pm
by the_marioga
I need to load and play .wav files, without SDL or SDL_mixer, i have compiled this sources(first post), but when i test in my wii, it returns me a Code Dump, These functions are bad? (first post) What should I do to load and play wav correctly?

Thanks

Re: Loading and Playing Wav, problem in Wii

Posted: Thu Sep 30, 2010 9:56 am
by Eke
You should first learn how pointer are working in C.

here, pFmt is NOT allocated, it will crash as soon as a function try to access the memory address returned by the pointer (NULL by default).

here is a more correct code:

Code: Select all

   PCMWAVFmt pFmt;
int wavPlay(const char* file) {
   void *buf = LoadPCMWav(file, &pFmt);
   if (buf) {
      ASND_SetVoice(ASND_GetFirstUnusedVoice(), VOICE_STEREO_16BIT, 8000,0, buf, sizeof(buf), 255, 255, NULL);
   } else {
      return 0;
   }
   return 1;
}
However, this is only if you can assume the WAV file you are trying to play is indeed always Stereo 16 bit @ 8kHZ.
It's safer to use the pFmt structure to get that parameters, it should have been filled by the LoadPCMWav function, providing this has been done correctly:

Re: Loading and Playing Wav, problem in Wii

Posted: Thu Sep 30, 2010 4:47 pm
by the_marioga
I patched and works thaks a lot for help me

Re: Loading and Playing Wav, problem in Wii

Posted: Fri Oct 01, 2010 1:13 pm
by the_marioga
Sorry, i try to play and not hear anything, LoadPCMWav return me a NULL in this part of the source:

Code: Select all

    u32 stFrame = (pFmt->start != PCMClock(-1)) ? PCMClock2Frame(pFmt->start, pFmt->sample_rate) : 0;
    u32 enFrame = (pFmt->end   != PCMClock(-1)) ? PCMClock2Frame(pFmt->end  , pFmt->sample_rate) : pFmt->sample_count;
    enFrame = MIN(enFrame, pFmt->sample_count);
    stFrame = MIN(stFrame, enFrame);
    u32 npad = enFrame - stFrame; 
    if ( npad <= 0 )
    {
        CloseFile(fd);
        return NULL; //This is the NULL
    }
npad value is 0

Re: Loading and Playing Wav, problem in Wii

Posted: Sat Oct 02, 2010 6:04 pm
by Eke
At a first glance, that seems normal, pFmt.start and pFmt.end are never initialized and they would hold zero by default, hence the result is 0.
You probably need to initialize these fields to -1 before calling LoadPCMWav, in order to get the whole sound length.

I'd advise you to first learn how to use the functions you are calling, seems like you copy-pasted some code from another application but without really understanding what it does and how it works.

Re: Loading and Playing Wav, problem in Wii

Posted: Mon Oct 18, 2010 9:51 pm
by the_marioga
now i use

Code: Select all

int wavPlayer(const char* file) {	
	pFmt.start=-1;
	pFmt.end=-1;
   void *buf = LoadPCMWav(file, &pFmt);
   s32 voice = ASND_GetFirstUnusedVoice();
   if (buf) {
      if (ASND_SetVoice(voice, VOICE_STEREO_16BIT, pFmt.sample_rate,0, buf, pFmt.sample_channel * pFmt.sample_count * pFmt.sample_byte, 255, 255, NULL) == SND_OK) {
		ASND_PauseVoice(voice, 0);
	  } else {
		return 0;
	  }
   } else {
      return 0;
   }
   return 1;
}
but i not hear nothing, why?