forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Audio with sceIoRead() and sceAudioOutputPannedBlocking()

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
donlebon



Joined: 19 Sep 2006
Posts: 2

PostPosted: Tue Sep 19, 2006 5:50 am    Post subject: Audio with sceIoRead() and sceAudioOutputPannedBlocking() Reply with quote

I am planning an audio software for the psp but already stumbled doing my first steps. I read a lot of info and the well known tutorials to get started with audio. But without success.

I have problems playing uncompressed audio data that come from a raw-file (that is a wave-file without header, 16bit 44.1kHz, little-endian, mono in my case). I chose a raw-file just for testing purposes. The file works fine but I have those crackles coming from the file read or whatever.

I know, that this problem already occured in the past, e.g. in this thread http://forums.ps2dev.org/viewtopic.php?t=5089. But the solution shown there isn't a real solution to my problem I think. I am searching for an explanation of that phenomenon without doing all that stuff of MP3 decoding.

Please take a look at my source:

Code:

#include <pspkernel.h>
#include <pspdebug.h>
#include <pspaudio.h>
#include <pspdisplay.h>

#include <stdlib.h>
#include <limits.h>

/*
   This part of the code is more or less identical to the sdktest sample
*/

/* Define the module info section */
PSP_MODULE_INFO("AUDIOTEST", 0, 1, 1);
/* Define the main thread's attribute value (optional) */
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
/* Define printf, just to make typing easier */
#define printf   pspDebugScreenPrintf

/* Exit callback */
int exitCallback(int arg1, int arg2, void *common) {
   sceKernelExitGame();
   return 0;
}

/* Callback thread */
int callbackThread(SceSize args, void *argp) {
   int cbid;

   cbid = sceKernelCreateCallback("Exit Callback", exitCallback, NULL);
   sceKernelRegisterExitCallback(cbid);
   sceKernelSleepThreadCB();

   return 0;
}

/* Sets up the callback thread and returns its thread id */
int setupCallbacks(void) {
   int thid = 0;

   thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0);
   if (thid >= 0) {
      sceKernelStartThread(thid, 0, 0);
   }
   return thid;
}

/*
  Below this point is the interesting code in this sample
*/

typedef struct {
        short l, r;
} sample_t;


int main(void) {
   pspDebugScreenInit();
   setupCallbacks();   

   printf("Opening test file.\n");
   
   //opening the test-file
   int fd = sceIoOpen("ms0:/mono.raw", PSP_O_RDONLY, 0777);
   
   if(fd <= 0) {
        printf("Error opening file.");
      return -1;
   }
   
   printf("Opening Audio Channel...\n");
   
   //common multiple of 64 and 100
   int sampleBufferSize = 1600;
   
   int channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL,
                           PSP_AUDIO_SAMPLE_ALIGN(sampleBufferSize),
                           PSP_AUDIO_FORMAT_STEREO);
                           
   if(channel < 0){
      printf("Error opening Audio Channel.");
      sceIoClose(fd);   
      return -1;
   }
                           
                           
   sample_t sampleBuffer[sampleBufferSize];   
   char byteBuffer[sampleBufferSize*2]; //buffer for reading from file
   short sampleValue = 0;
   
   //read the first bytes
   int readBytes = sceIoRead(fd, byteBuffer, sampleBufferSize*2);
   //samples are 16bit
   int readSamples = readBytes/2;
   
   while(readSamples > 0){
   
      int i;
      //copy the bytes to the sampleBuffer and convert them to short
      for(i = 0; i < readSamples; ++i){
         //little endian conversion to short
         //wave/raw uses -32768 to 32767
         sampleValue = ((short) byteBuffer[2*i]) + (((short)byteBuffer[2*i+1]) << 8);
         sampleBuffer[i].l = sampleValue;
         sampleBuffer[i].r = sampleValue;      
      }
      
      sceAudioOutputPannedBlocking(channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, sampleBuffer);
      
      //reading the next samples
      readSamples = sceIoRead(fd, byteBuffer, sampleBufferSize*2) / 2;
   
   }
   
   sceAudioChRelease(channel);
   sceIoClose(fd);   
   
   printf("Reached Audio File End.\n");
   
   return 0;
}


The crackles occur at every loop (also when changing the buffer size). So when recording the audio, I can see a lot of samples obviously damaged at the start/end of every single loop, in the upper example every 1600 samples.

Studying the sources, I could not really imagine, how the solution in the thread I cited above fits to my needs. I also took a look at the PSPRadio-sources. But also that software is much more complex than this (simple?) problem. They do a lot of messaging stuff because they have to load the audio from the internet. Or did I oversee something?

I also tried the callback-function method from pspaudiolib.h. That didn't work either. I took a look into pspaudiolib.c, but no magic, just the way I'm trying to do it here? Or am I wrong?

Please help.
Back to top
View user's profile Send private message
dot_blank



Joined: 28 Sep 2005
Posts: 498
Location: Brasil

PostPosted: Tue Sep 19, 2006 2:00 pm    Post subject: Reply with quote

the psp handles 3200 samples for stereo
in your case you use mono thus 1600 samples
so you must give the audio buffer TWICE the amount
to properly play smoothly ...you output as stereo
but your input is mono ...so double your outputing
and you will remove crackles ...hope this helps

Code:
//common multiple of 64 and 100
   int sampleBufferSize = 3200;
   sample_t sampleBuffer[sampleBufferSize]; //now its correct
   char byteBuffer[sampleBufferSize];        //changed
//read the first bytes
   int readBytes = sceIoRead(fd, byteBuffer, sampleBufferSize);  //changed
   //samples are 32bit
   int readSamples = readBytes;  //changed


ill leave you to continue changes ...but i think you see what i mean :)
_________________
10011011 00101010 11010111 10001001 10111010
Back to top
View user's profile Send private message
donlebon



Joined: 19 Sep 2006
Posts: 2

PostPosted: Thu Sep 21, 2006 3:54 am    Post subject: Reply with quote

Thanks dot_blank for your answer. Your suggestion unfortunately isn't the solution to the problem. My code was allright according to sample buffer size etc. because

Code:
sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL,
                           PSP_AUDIO_SAMPLE_ALIGN(sampleBufferSize),
                           PSP_AUDIO_FORMAT_STEREO);


will reserve the memory needed for STEREO samples.

But now I found the solution, I think that is very important to everyone:
The crackles will disappear when allocating the sample-buffer within the HEAP memory instead of the STACK! So take new or malloc() to build the buffer.

Another issue I found after solving that prob, was a noise that came from a wrong computation (my fault). I had to change the byteBuffer from char* to unsigned char*. Then the conversion to short works right.

Here the working (!yeah!) code:


Code:
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspaudio.h>
#include <pspdisplay.h>

#include <stdlib.h>
#include <limits.h>

/*
   This part of the code is more or less identical to the sdktest sample
*/

/* Define the module info section */
PSP_MODULE_INFO("AUDIOTEST", 0, 1, 1);
/* Define the main thread's attribute value (optional) */
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
/* Define printf, just to make typing easier */
#define printf   pspDebugScreenPrintf

/* Exit callback */
int exitCallback(int arg1, int arg2, void *common) {
   sceKernelExitGame();
   return 0;
}

/* Callback thread */
int callbackThread(SceSize args, void *argp) {
   int cbid;

   cbid = sceKernelCreateCallback("Exit Callback", exitCallback, NULL);
   sceKernelRegisterExitCallback(cbid);
   sceKernelSleepThreadCB();

   return 0;
}

/* Sets up the callback thread and returns its thread id */
int setupCallbacks(void) {
   int thid = 0;

   thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0);
   if (thid >= 0) {
      sceKernelStartThread(thid, 0, 0);
   }
   return thid;
}

/*
  Below this point is the interesting code in this sample
*/

typedef struct {
        short l, r;
} sample_t;


int main(void) {
   pspDebugScreenInit();
   setupCallbacks();   

   printf("Opening test file.\n");
   
   //opening the test-file
   int fd = sceIoOpen("ms0:/mono.raw", PSP_O_RDONLY, 0777);
   
   if(fd <= 0) {
        printf("Error opening file.");
      return -1;
   }
   
   printf("Opening Audio Channel...\n");
   
   //number of Stereo Samples to be allocated by the channel
   int sampleBufferSize = 1024;
   
   //opening the channel in stereo mode
   int channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL,
                     sampleBufferSize,
                     PSP_AUDIO_FORMAT_STEREO);
                           
   if(channel < 0){
      printf("Error opening Audio Channel.");
      sceIoClose(fd);   
      return -1;
   }
                           
   //allocating buffers on the HEAP (!!!) -> using the Stack would result in crackles!
   //if you don't like C++, take malloc() here                     
   sample_t* sampleBuffer = new sample_t[sampleBufferSize];
   
   //Using this buffer to read from the file, it is important to take unsigned char.
   //because we are doing mono, we need only twice the size of the sampleBufferSize
   //if we were reading stereo samples from the raw-file, we should take four times
   //the sampleBufferSize
   unsigned char* byteBuffer = new unsigned char[sampleBufferSize*2];
   
   //helper variable
   short sampleValue = 0;
   
   //read the first bytes
   int readBytes = sceIoRead(fd, byteBuffer, sampleBufferSize*2);
   //samples are 16bit
   int readSamples = readBytes/2;
   
   while(readSamples > 0){
   
      int i;
      //copy the bytes to the sampleBuffer and convert them to short
      for(i = 0; i < readSamples; ++i){
         //little endian conversion to short
         //wave/raw uses -32768 to 32767
         sampleValue = ((short) byteBuffer[2*i]) + (((short)byteBuffer[2*i+1]) << 8);
      
       //here we are going to stereo by just copying the value to both channels
         sampleBuffer[i].l = sampleValue;
         sampleBuffer[i].r = sampleValue;       
      }
    
     //if there are less samples than the buffer is expecting
     //fill the rest of the buffer with silence (will occur on the last cycle)
     for(i = readSamples; i < sampleBufferSize; ++i){
       sampleBuffer[i].l = 0;
         sampleBuffer[i].r = 0;
     }
       
      sceAudioOutputPannedBlocking(channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, sampleBuffer);
       
      //reading the next samples
      readSamples = sceIoRead(fd, byteBuffer, sampleBufferSize*2) / 2;
   
   }
   
   //avoid a click when releasing the channel by turning volume down before
   sceAudioChangeChannelVolume(channel, 0, 0);
   
   //close the channel
   sceAudioChRelease(channel);
 
   //close the file
   sceIoClose(fd);
   
   //delete the buffers
   delete [] sampleBuffer;
   delete [] byteBuffer;
   
   printf("Reached Audio File End.\n");
   
   return 0;
}


So the work can go on! Keep your eyes open, we will come with a very cool audio homebrew in a few months, hopefully.

Greetz
Don
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group