Homebrew Homebrew Development

  • Thread starter Thread starter aliak11
  • Start date Start date
  • Views Views 1,475,785
  • Replies Replies 6,048
  • Likes Likes 54
Absolutely, I've done it plenty. That's not to say there isn't anything wrong with DSP implementation, but it's definitely not merely because of simultaneously channel usage.

MMhhh that sounds strange since the only "irregularity" could be that (since if i wait a bit till the first sound ends and ten try to play the next ones, it plays fine without any problem).

That's the used code, maybe you can find something strange in it:
Code:
void CtrAudio::SE_Play(std::string const& file, int volume, int /* pitch */) {
  
   // Select an available audio channel
   int i = 0;
   while (i < num_channels){
     if (!isPlayingCallback(i)) break;
     i++;
     if (i >= num_channels){
       Output::Warning("Cannot execute %s sound: audio-device is busy.\n",file.c_str());
       return;
     }
   }
  
   if (audiobuffers[i] != NULL){
     #ifndef USE_CACHE
     linearFree(audiobuffers[i]);
     audiobuffers[i] = NULL;
     #endif
     if (isDSP) free(dspSounds[i]);
   }
  
   // Init needed vars
   bool isStereo = false;
   int audiobuf_size;
   int codec;
   DecodedSound myFile;
  
   #ifdef USE_CACHE
   // Looking if the sound is in sounds cache
   int cacheIdx = lookCache(file.c_str());
   if (cacheIdx < 0){
   #endif
  
     // Searching for the file
     std::string const path = FileFinder::FindSound(file);
     if (path.empty()) {
       Output::Debug("Sound not found: %s", file.c_str());
       return;
     }
  
     // Opening and decoding the file
     int res = DecodeSound(path, &myFile);
     if (res < 0) return;
     #ifdef USE_CACHE
     else sprintf(soundtable[res],"%s",file.c_str());
     #endif
    
   #ifdef USE_CACHE
   }else myFile = decodedtable[cacheIdx];
   #endif
  
   // Processing sound info
   audiobuffers[i] = myFile.audiobuf;
   int samplerate = myFile.samplerate;
   audiobuf_size = myFile.audiobuf_size;
   if (isDSP) codec = NDSP_CHANNELS(isStereo + 1) | NDSP_ENCODING(myFile.format);
   else codec = SOUND_FORMAT(myFile.format);
   isStereo = myFile.isStereo;
  
   #ifndef NO_DEBUG
   Output::Debug("Playing sound %s:",file.c_str());
   Output::Debug("Samplerate: %i",samplerate);
   Output::Debug("Buffer Size: %i bytes",audiobuf_size);
   #endif
  
   // Playing the sound
   float vol = volume / 100.0;
   if (isStereo && (!isDSP)){
    
     // We need a second channel where to execute right audiochannel since csnd supports only mono sounds natively
     int z = i+1;
     while (z < num_channels){
       if (!isPlayingCallback(z+0x08)) break;
       z++;
       if (z >= num_channels){
         Output::Warning("Cannot execute %s sound: audio-device is busy.\n",file.c_str());
         return;
       }
     }
     #ifndef USE_CACHE
     if (audiobuffers[z] != NULL) linearFree(audiobuffers[z]);

     // To not waste CPU clocks, we use a single audiobuffer for both channels so we put just a stubbed audiobuffer on right channel
     audiobuffers[z] = (u8*)linearAlloc(1);
     #endif
    
     int chnbuf_size = audiobuf_size>>1;
     csndPlaySound(i+0x08, SOUND_LINEAR_INTERP | codec, samplerate, vol, -1.0, (u32*)audiobuffers[i], (u32*)audiobuffers[i], chnbuf_size); // Left
     csndPlaySound(z+0x08, SOUND_LINEAR_INTERP | codec, samplerate, vol, 1.0, (u32*)(audiobuffers[i] + chnbuf_size), (u32*)(audiobuffers[i] + chnbuf_size), chnbuf_size); // Right
    
   }else{
     if (isDSP){
       ndspChnReset(i+0x08);
       ndspChnWaveBufClear(i+0x08);
       ndspChnSetInterp(i+0x08, NDSP_INTERP_LINEAR);
       ndspChnSetRate(i+0x08, float(samplerate));
       ndspChnSetFormat(i+0x08, codec);
       dspSounds[i] = (ndspWaveBuf*)calloc(1,sizeof(ndspWaveBuf));
       createDspBlock(dspSounds[i], myFile.bytepersample, audiobuf_size, false, (u32*)audiobuffers[i]);
       ndspChnWaveBufAdd(i+0x08, dspSounds[i]);
     }else csndPlaySound(i+0x08, SOUND_LINEAR_INTERP | codec, samplerate, vol, 0.0, (u32*)audiobuffers[i], (u32*)audiobuffers[i], audiobuf_size);
   }
}

Where:

Code:
isPlayingCallback = ndspChnIsPlaying;
     clearCallback = ndspChnWaveBufClear;
 
Not sure, but one problem is that you using "i + 0x8" for ndsp channels. The functions expect values 0-23. The internal array is a buf[24] so it likely crashes with channel value > 23. Though I doubt that's your problem since that would only crash if you use were using more than like a dozen channels at the same time with this code, and you're probably only using a few.

If I had to guess, it's perhaps the fact that the ndsp audio loop is run in another thread and you are using ndspChnIsPlaying to find an open channel. If you run this function twice in a row, it may not yield time to the other thread to give it time to process the queue and play a sound to occupy it. So then you're messing up the first buffer on your second call. Try hardcoding a couple different channels or something to test, or at least do a couple printf to see if it is indeed trying to play them on the same channel.
 
Last edited by TheCruel,
Not sure, but one problem is that you using "i + 0x8" for ndsp channels. The functions expect values 0-23. The internal array is a buf[24] so it likely crashes with channel value > 23. Though I doubt that's your problem since that would only crash if you use were using more than like a dozen channels at the same time with this code, and you're probably only using a few.

If I had to guess, it's perhaps the fact that the ndsp audio loop is run in another thread and you are using ndspChnIsPlaying to find an open channel. If you run this function twice in a row, it may not yield time to the other thread to give it time to process the queue and play a sound to occupy it. So then you're messing up the first buffer on your second call. Try hardcoding a couple different channels or something to test, or at least do a couple printf to see if it is indeed trying to play them on the same channel.

It looks like it crashes at the third sound that tries to get played with channels taken in this order: (first sound 0x08, second sound 0x09, third sound 0x08).
 
Not only, it can also open notifications and dump them (text + MPO image).
Also, can you tell me what's wrong with this code?

*path*/main.c: In function 'main':
*path*/main.c:27:24: error: 'Test' undeclared (first use in this function)
NEWS_AddNotification(Test, 1, Test, 4, NULL, 0, NULL);
^
*path*/main.c:27:24: note: each undeclared identifier is reported only once for each function it appears in
make[1]: *** [main.o] Error 1
make: *** [build] Error 2
#include <3ds.h>
#include <3ds/services/news.h>
#include <stdio.h>


int main(int argc, char **argv)
{
//Initialize gfx (note: not needed if you're using SF2Dlib)
gfxInitDefault();

newsInit();

while (aptMainLoop())
{

u32 kDown = hidKeysDown();

if (kDown & KEY_START) break; // break in order to return to hbmenu

// Flush and swap framebuffers, this is needed for rendering these will not be needed when using SF2D lib
gfxFlushBuffers();
gfxSwapBuffers();

//Wait for VBlank, this is needed for rendering these will not be needed when using SF2D lib
gspWaitForVBlank();

NEWS_AddNotification(Test, 1, Test, 4, NULL, 0, NULL);

newsExit();
}
gfxExit();
return 0;
}
 
Also, can you tell me what's wrong with this code?

*path*/main.c: In function 'main':
*path*/main.c:27:24: error: 'Test' undeclared (first use in this function)
NEWS_AddNotification(Test, 1, Test, 4, NULL, 0, NULL);
^
*path*/main.c:27:24: note: each undeclared identifier is reported only once for each function it appears in
make[1]: *** [main.o] Error 1
make: *** [build] Error 2
#include <3ds.h>
#include <3ds/services/news.h>
#include <stdio.h>


int main(int argc, char **argv)
{
//Initialize gfx (note: not needed if you're using SF2Dlib)
gfxInitDefault();

newsInit();

while (aptMainLoop())
{

u32 kDown = hidKeysDown();

if (kDown & KEY_START) break; // break in order to return to hbmenu

// Flush and swap framebuffers, this is needed for rendering these will not be needed when using SF2D lib
gfxFlushBuffers();
gfxSwapBuffers();

//Wait for VBlank, this is needed for rendering these will not be needed when using SF2D lib
gspWaitForVBlank();

NEWS_AddNotification(Test, 1, Test, 4, NULL, 0, NULL);

newsExit();
}
gfxExit();
return 0;
}

There are many things wrong with the code. Like rinnegatamante said, you haven't declared nor defined Test, which needs to be a utf-16 string. Second you are calling newExit() inside a while loop, and you are also calling NEWS_AddNotification inside that loop which will "flood" your inbox. Lastly you are not using hidScanInput() so you will never be able to get out of that loop, since START will never be pressed
 
I don't think there are any tutorials, but it has relatively simple instructions set: https://github.com/fincs/picasso/blob/master/Manual.md
I have written a few shaders but am no expert, if you need help for a specific shader I can give you better information.

That could be really wonderful, i need a specific shader that should execute a texture operation called HARD_LIGHT since executing it with CPU results in a massive framedrop.

You can find much more information about how this work (and also you can ask directly to Ghabry which will probably help you a lot compared to what i can do <.< ) here: https://github.com/Rinnegatamante/easyrpg-player-3ds/issues/11
(It should be used with sf2dlib. I'll obviously add a custom function in sf2dlib to change shaderprogram on the fly cause the shader needs to be used only in certain circumstances)
 
That could be really wonderful, i need a specific shader that should execute a texture operation called HARD_LIGHT since executing it with CPU results in a massive framedrop.

You can find much more information about how this work (and also you can ask directly to Ghabry which will probably help you a lot compared to what i can do <.< ) here: https://github.com/Rinnegatamante/easyrpg-player-3ds/issues/11
(It should be used with sf2dlib. I'll obviously add a custom function in sf2dlib to change shaderprogram on the fly cause the shader needs to be used only in certain circumstances)

I just looked into it, you don't need a special shader since the HARD_LIGHT operand seams to be just a simple blending operation. The simplest way to achieve what you need is to replace the toneblit function with a simple GPU rendered function that configures the diffuse color and texture blending function, that way the texture and color will blend giving you the same effect.

Edit: I may have confused you, take a look at this function in ctrulib: GPU_SetTexEnv
 
Last edited by MasterFeizz,
I just looked into it, you don't need a special shader since the HARD_LIGHT operand seams to be just a simple blending operation. The simplest way to achieve what you need is to replace the toneblit function with a simple GPU rendered function that configures the diffuse color and texture blending function, that way the texture and color will blend giving you the same effect.

Are you sure this will perform the same effect of HARD_LIGHT?
I cannot see a proper cominefunc for this:

Code:
GPU_COMBINEFUNC {
  GPU_REPLACE = 0x00,
  GPU_MODULATE = 0x01,
  GPU_ADD = 0x02,
  GPU_ADD_SIGNED = 0x03,
  GPU_INTERPOLATE = 0x04,
  GPU_SUBTRACT = 0x05,
  GPU_DOT3_RGB = 0x06,
  GPU_MULTIPLY_ADD = 0x08,
  GPU_ADD_MULTIPLY = 0x09
}
 
Last edited by Rinnegatamante,
Are you sure this will perform the same effect of HARD_LIGHT?
I cannot see a proper cominefunc for this:

Code:
GPU_COMBINEFUNC {
  GPU_REPLACE = 0x00,
  GPU_MODULATE = 0x01,
  GPU_ADD = 0x02,
  GPU_ADD_SIGNED = 0x03,
  GPU_INTERPOLATE = 0x04,
  GPU_SUBTRACT = 0x05,
  GPU_DOT3_RGB = 0x06,
  GPU_MULTIPLY_ADD = 0x08,
  GPU_ADD_MULTIPLY = 0x09
}
Modulate will multiply the 2, should give the same effect I believe
 
It's part of the fixed fragment shading pipeline of the PICA200

Edit: It won't look exactly the same, but in cases like this you have to compromise
I specifically meant the hard_light operation. I have used modulate and interpolate ops myself and they work nicely.
 

Site & Scene News

Popular threads in this forum