 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
donlebon
Joined: 19 Sep 2006 Posts: 2
|
Posted: Tue Sep 19, 2006 5:50 am Post subject: Audio with sceIoRead() and sceAudioOutputPannedBlocking() |
|
|
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 |
|
 |
dot_blank

Joined: 28 Sep 2005 Posts: 498 Location: Brasil
|
Posted: Tue Sep 19, 2006 2:00 pm Post subject: |
|
|
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 |
|
 |
donlebon
Joined: 19 Sep 2006 Posts: 2
|
Posted: Thu Sep 21, 2006 3:54 am Post subject: |
|
|
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 |
|
 |
|
|
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
|