Homebrew Homebrew Development

D

Deleted User

Guest
Maybe the hint is for @B_E_P_I_S_M_A_N

In my code usually I use only a channel with two buffer, filling a buffer with new samples while the other is playing and then adding it to the channel queue.

I don't need to stop the channel since there are samples to play.
Actually, looking back, I'm getting a bytePerSample value of 0, which can't be right. This is probably why the DSP_FlushDataCache call is failing. I'll look into this.

And yes, the sound file is started and stopped from the main thread, and the higher-priority thread updates it. The channel is not being explicitly stopped while streaming, though (i.e. ndspChnWaveBufClear()).
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,030
Country
United States
Actually, looking back, I'm getting a bytePerSample value of 0, which can't be right. This is probably why the DSP_FlushDataCache call is failing. I'll look into this.

And yes, the sound file is started and stopped from the main thread, and the higher-priority thread updates it. The channel is not being explicitly stopped while streaming, though (i.e. ndspChnWaveBufClear()).
Start/stop we're just examples of commands that do not take effect immediately and need to be processed by the ndsp thread. The problem I was trying to identify as that some commands won't be initiated until the calling thread releases control due to the cooperative multi-tasking nature of the 3ds thread execution.
Sorry if I confused the issue. I was not trying to imply multiple channels were needed to stream music/sounds.
 
D

Deleted User

Guest
Start/stop we're just examples of commands that do not take effect immediately and need to be processed by the ndsp thread. The problem I was trying to identify as that some commands won't be initiated until the calling thread releases control due to the cooperative multi-tasking nature of the 3ds thread execution.
Sorry if I confused the issue. I was not trying to imply multiple channels were needed to stream music/sounds.
Oh, no, I'm only using one channel to stream music. Sorry if I caused any confusion.

Anyways, I was able to get the audio feeding thread to work; however, the choppiness was still there, so now I'm heading in the other direction and trying to load the entire file into memory. I realize that the audio buffer to be flushed must be linear-allocated.

Anyways, I load the entire audio section into memory like so:
Code:
   typedef struct {
      ...
      char **chunkData;
      char *data;
   } wavFile;

   ...

    // get chunk data
   wav->chunkData = calloc( ceil(wav->fileSize / wav->chunkSize), wav->chunkSize);
   fseek(fp, 44, SEEK_SET);
   fread(wav->chunkData, wav->chunkSize, ceil(wav->fileSize / wav->chunkSize), fp);

...then I allocate memory for the main buffer, and set it equal to the first chunk in memory...
Code:
    wav->data = (char*)linearAlloc(wav->chunkSize);
    wav->data = wav->chunkData[0];

...then I try to flush the buffer as usual...
Code:
    ndspWaveBuf *wbuf;
  
   stopWav(channel);
   ndspChnReset(channel);
   ndspChnSetRate(channel, wav->rate);
   ndspChnInitParams(channel);
   ndspChnSetFormat(channel, NDSP_CHANNELS(wav->channels) | NDSP_ENCODING(wav->encoding));
  
   wbuf = calloc(1, sizeof(ndspWaveBuf));
  
   wbuf->data_vaddr = wav->data;
   wbuf->nsamples = wav->chunkNSamples;
   wbuf->looping = (wav->chunkSize < wav->size) ? false : loop;
  
   Result ret = DSP_FlushDataCache((u32*)wav->data, wav->chunkSize);
   ndspChnWaveBufAdd(channel, wbuf);

However, doing this results in DSP_FlushDataCache failing. Am I supposed to do something with the chunk data before unloading it onto the main buffer? Because AFAIK, fread() just dumps the file data without any alterations, so i don't see why this wouldn't work.
 
Last edited by ,

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,030
Country
United States
Oh, no, I'm only using one channel to stream music. Sorry if I caused any confusion.

Anyways, I was able to get the audio feeding thread to work; however, the choppiness was still there, so now I'm heading in the other direction and trying to load the entire file into memory. I realize that the audio buffer to be flushed must be linear-allocated.

Anyways, I load the entire audio section into memory like so:
Code:
   typedef struct {
      ...
      char **chunkData;
      char *data;
   } wavFile;

   ...

    // get chunk data
   wav->chunkData = calloc( ceil(wav->fileSize / wav->chunkSize), wav->chunkSize);
   fseek(fp, 44, SEEK_SET);
   fread(wav->chunkData, wav->chunkSize, ceil(wav->fileSize / wav->chunkSize), fp);

...then I allocate memory for the main buffer, and set it equal to the first chunk in memory...
Code:
    wav->data = (char*)linearAlloc(wav->chunkSize);
    wav->data = wav->chunkData[0];

...then I try to flush the buffer as usual...
Code:
    ndspWaveBuf *wbuf;
 
   stopWav(channel);
   ndspChnReset(channel);
   ndspChnSetRate(channel, wav->rate);
   ndspChnInitParams(channel);
   ndspChnSetFormat(channel, NDSP_CHANNELS(wav->channels) | NDSP_ENCODING(wav->encoding));
 
   wbuf = calloc(1, sizeof(ndspWaveBuf));
 
   wbuf->data_vaddr = wav->data;
   wbuf->nsamples = wav->chunkNSamples;
   wbuf->looping = (wav->chunkSize < wav->size) ? false : loop;
 
   Result ret = DSP_FlushDataCache((u32*)wav->data, wav->chunkSize);
   ndspChnWaveBufAdd(channel, wbuf);

However, doing this results in DSP_FlushDataCache failing. Am I supposed to do something with the chunk data before unloading it onto the main buffer? Because AFAIK, fread() just dumps the file data without any alterations, so i don't see why this wouldn't work.
There are many problems here. Allocating the wrong size buffers and overwriting pointers to name a couple. Calloc does not create multiple buffers. It just multiplies size and count to get the full size and returns a single pointer to a linear region of memory for the full size - rather than an array of pointers.
 
D

Deleted User

Guest
There are many problems here. Allocating the wrong size buffers and overwriting pointers to name a couple. Calloc does not create multiple buffers. It just multiplies size and count to get the full size and returns a single pointer to a linear region of memory for the full size - rather than an array of pointers.
Yeah, I realized. I opted instead to use malloc() to allocate an array of char pointers, like so...
Code:
wav->chunkData = malloc(sizeof(char*) * ceil(wav->fileSize / wav->chunkSize));
   for (int i = 0; i < ceil(wav->fileSize / wav->chunkSize); i++) {
       wav->chunkData[i] = malloc(wav->chunkSize);
   }

...then I read each chunk into memory like this...
Code:
fseek(fp, 44, SEEK_SET);
   for (int i = 0; i < (int)ceil(wav->fileSize / wav->chunkSize); i++) {
       fread(wav->chunkData[i], wav->chunkSize, 1, fp);
   }

...then, for the initial buffer, I set it to the first element in the array. I replaced the pointer override with just some basic memcpy() usage...
Code:
memcpy(wav->data, wav->chunkData[0], wav->chunkSize);

...then, during the audio buffer feeding loop, I read the next chunk into memory like so:
Code:
               stream->chunkIndex++;
               memset(stream->nextData, 0, chunkSize);
               memcpy(stream->nextData, wav->chunkData[stream->chunkIndex], chunkSize);
...then flush as usual.

There's a problem however; while the initial buffer flush seems to work just fine, subsequent flushes in the audio buffer feeding loop seem to fail with a result code of 0xe0e01bf5:
Code:
Module:
  OS (6)
Description:
  Invalid address (1013)
Summary:
  Invalid argument (7)
Level:
  Usage (28)

...so it seems that I'm passing an invalid address, which is odd, considering the buffer seemed to work fine when I was reading directly from the file. The fact that the initial flush works seems to indicate that the actual audio data is fine (I've tried passing copying other chunks other than the initial one into memory, and they seem to work fine). I tried inserting memset() to see if that would fix anything; it didn't. Is this another case of memory mismanagement? Or is it something else? Am I still allocating the wrong-sized buffers?
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,030
Country
United States
Yeah, I realized. I opted instead to use malloc() to allocate an array of char pointers, like so...
Code:
wav->chunkData = malloc(sizeof(char*) * ceil(wav->fileSize / wav->chunkSize));
   for (int i = 0; i < ceil(wav->fileSize / wav->chunkSize); i++) {
       wav->chunkData[i] = malloc(wav->chunkSize);
   }

...then I read each chunk into memory like this...
Code:
fseek(fp, 44, SEEK_SET);
   for (int i = 0; i < (int)ceil(wav->fileSize / wav->chunkSize); i++) {
       fread(wav->chunkData[i], wav->chunkSize, 1, fp);
   }

...then, for the initial buffer, I set it to the first element in the array. I replaced the pointer override with just some basic memcpy() usage...
Code:
memcpy(wav->data, wav->chunkData[0], wav->chunkSize);

...then, during the audio buffer feeding loop, I read the next chunk into memory like so:
Code:
               stream->chunkIndex++;
               memset(stream->nextData, 0, chunkSize);
               memcpy(stream->nextData, wav->chunkData[stream->chunkIndex], chunkSize);
...then flush as usual.

There's a problem however; while the initial buffer flush seems to work just fine, subsequent flushes in the audio buffer feeding loop seem to fail with a result code of 0xe0e01bf5:
Code:
Module:
  OS (6)
Description:
  Invalid address (1013)
Summary:
  Invalid argument (7)
Level:
  Usage (28)

...so it seems that I'm passing an invalid address, which is odd, considering the buffer seemed to work fine when I was reading directly from the file. The fact that the initial flush works seems to indicate that the actual audio data is fine (I've tried passing copying other chunks other than the initial one into memory, and they seem to work fine). I tried inserting memset() to see if that would fix anything; it didn't. Is this another case of memory mismanagement? Or is it something else? Am I still allocating the wrong-sized buffers?
It is hard to tell without seeing the full source.
Not that this is the problem, but calling ceil on the result of integer division does not do what you are thinking it does.
 
D

Deleted User

Guest
It is hard to tell without seeing the full source.
Not that this is the problem, but calling ceil on the result of integer division does not do what you are thinking it does.
Ah, sorry for taking so long to respond. I hadn't realized I had gotten a reply on this thread, for whatever reason.

Anyways, here's the source: https://github.com/BEPISMAN2/sound-thing/tree/chunk-audio-feeding

And yes, I just got what you meant on ceil(). That would be getting the ceiling value of an already-truncated integer, right?
 

spinal_cord

Knows his stuff
Member
Joined
Jul 21, 2007
Messages
3,224
Trophies
1
Age
43
Location
somewhere
Website
spinalcode.co.uk
XP
3,366
Country
Can someone please tell me what aptGetStatus() has changed to in later devkitpro versions?
I'm trying to update the following code, but as usual, there doesn't seem to be ANY documentation ANYWHERE on thse changes...
Code:
    APT_AppStatus status;

    while((status=aptGetStatus()) != APP_RUNNING) {
        // Close Lid
        if(status == APP_PREPARE_SLEEPMODE)
        {
            Pause();
            aptSignalReadyForSleep();
            aptWaitStatusEvent();
            Resume();
        }
        // Home Button
        if(status == APP_SUSPENDING)
        {
            Pause();
            aptReturnToMenu();
            Resume();
        }
       
        if(aptGetStatus() == APP_EXITING)
        {

            Pause(); // exit audio safely..

            quit_thyself=1;
            break;
        }

    }

Thanks.
 

nop90

Well-Known Member
Member
Joined
Jan 11, 2014
Messages
1,556
Trophies
0
Location
Rome
XP
3,036
Country
Italy
Can someone please tell me what aptGetStatus() has changed to in later devkitpro versions?
I'm trying to update the following code, but as usual, there doesn't seem to be ANY documentation ANYWHERE on thse changes...
Code:
    APT_AppStatus status;

    while((status=aptGetStatus()) != APP_RUNNING) {
        // Close Lid
        if(status == APP_PREPARE_SLEEPMODE)
        {
            Pause();
            aptSignalReadyForSleep();
            aptWaitStatusEvent();
            Resume();
        }
        // Home Button
        if(status == APP_SUSPENDING)
        {
            Pause();
            aptReturnToMenu();
            Resume();
        }
     
        if(aptGetStatus() == APP_EXITING)
        {

            Pause(); // exit audio safely..

            quit_thyself=1;
            break;
        }

    }

Thanks.

apt status events are now handled inside aptMainLoop(), so you can now simply use a

Code:
while (aptMainLoop()) {
 // your main loop here
}

this works fine for 3dsx executable. For programs released in CIA format you need to handle the home button and lid close.

For this look here.
 

spinal_cord

Knows his stuff
Member
Joined
Jul 21, 2007
Messages
3,224
Trophies
1
Age
43
Location
somewhere
Website
spinalcode.co.uk
XP
3,366
Country
apt status events are now handled inside aptMainLoop(), so you can now simply use a

Code:
while (aptMainLoop()) {
 // your main loop here
}

this works fine for 3dsx executable. For programs released in CIA format you need to handle the home button and lid close.

For this look here.

Thanks, for now though, I'll just leave it out until I can get everything else working....

On that note, does anyone want to have a look at my latest frodo attempt? So far its up and running, but any attempt to reset the emulated console crashes. citra throws me into an unmapped read32 error loop.

http://socoder.net/uploads/124/BreadBox_21_08_17.zip

The issue appears to be caused by TheCPU->AsyncReset() -- called from void C64::Reset(void) in C64.cpp

For the record, it worked fine in whatever older version of devkitpro I had back in 2016. The TheCPU->AsyncReset() function has not changed at all.
 
Last edited by spinal_cord,

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,030
Country
United States
Can anyone tell me what 'unmapped read32' means in citra? it's the only clue I have as to why my frodo port is crashing.
This can happen when reading a null pointer or when passing a main memory pointer to the sound or gpu hard which expects memory from "linear". a invalid/corrupt/uninitialize pointer could do this too. Essentially you are attempting to read from a memory range that is not accessible. You have a 4gb address range but far less actual memory.
 

nop90

Well-Known Member
Member
Joined
Jan 11, 2014
Messages
1,556
Trophies
0
Location
Rome
XP
3,036
Country
Italy
It can happen with a stack overflow too.
With big arrays defined in a function this may happen since the stack is only 32k by defaulr.

I have often this problem. It happens for example with libmad and libtremor, bit it doesn't happen with rhe same libs to other people.

I'm trying to understand if it depends on my windows compiling emviroment
 

spinal_cord

Knows his stuff
Member
Joined
Jul 21, 2007
Messages
3,224
Trophies
1
Age
43
Location
somewhere
Website
spinalcode.co.uk
XP
3,366
Country

nop90

Well-Known Member
Member
Joined
Jan 11, 2014
Messages
1,556
Trophies
0
Location
Rome
XP
3,036
Country
Italy
The stack size is defined weak. So you can override it in your source and set it to a larger value - say 1MB.
u32 __stacksize__ = 1* 1024 * 1024;
https://github.com/smealum/ctrulib/blob/master/libctru/source/system/stack_adjust.s
Yes, but if you use 1M for stack you havr less ram for you code, and I'm always in short of it in my game ports.

--------------------- MERGED ---------------------------

I haven't figured out exactly what is causing this yet. It appears to be something to do with the emulated floppy drive, but other than that, I'm lost. Fisrt I need to find out what the problem is before I start fixing it.
Try tracing the free memory. If the emulated floppy try to allocate 1.44M of space, probably you are consuming all the RAM left. Chech if malloc returns NULL too. Some program can omitt this assuming to run with system with a lot of phisical ram (and maybe vram)
 

elhobbs

Well-Known Member
Member
Joined
Jul 28, 2008
Messages
1,044
Trophies
1
XP
3,030
Country
United States
Yes, but if you use 1M for stack you havr less ram for you code, and I'm always in short of it in my game ports.
Yes, it is a trade off. It is an easy way to see if it is the issue though.
Does this really impact code size? I thought it just used main memory for the stack - maybe that is what you meant though?
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • No one is chatting at the moment.
    SylverReZ @ SylverReZ: https://www.youtube.com/watch?v=uLN9qrJ8ESs