I might try and create an editor for when Sun and Moon release. Coding out the demo. Maybe the full game
It is unlikely that the function was too big - as in to much code. It would be more likely that you were using too much stack space. Local variables and sometimes parameters are stored on the the stack. The default stack on the 3ds with libctru is only 32k. So it is easy to use too much.To be honest it's the first time that I mess with homebrew development, so I don't have a clue about how to help you.
Anyways your fopen() workaround worked, but after implementing more things (without touching the fopen() call!) it started freezing again.
L+R+Down+B in this case doesn't even work, forcing me to reboot the console. But after a hour trying to discover what I did wrong, the function was too big (I think that this caused it)
Then I chopped it into 3 parts (read file, put into ram and parse) and set the first one to chaincall until end. This fixed my issue.
Yeah im re-writing my menu at the moment in a very similar formatHave a separate function that draws your menu, add a call to printf with "\x1b[2J" at the beginning to clear the screen.
Also, instead of drawing the menu every frame, just draw it when something has changed and it won't be all flickery.
It is unlikely that the function was too big - as in to much code. It would be more likely that you were using too much stack space. Local variables and sometimes parameters are stored on the the stack. The default stack on the 3ds with libctru is only 32k. So it is easy to use too much.
It is also possible to change the stack sizes for your project. Define a global u32 __stacksize__=64*1024; would change it to 64k. I have set it as high as 1 MB. Of course this does reduce the available heap size.Knowing this limit would have saved me A LOT of trouble when trying to debug a crash. I was allocating a 64k array and the program kept crashing. I allocated the 64k on heap and the crash solved and i filed it under: "well it now works but i don't know why"
Better late than never
maybe look at this? https://github.com/filfat/3DS_UIBtw guys I am making a menu base that hopfully can be easily used and updated
It'll be OO, and load information from text files to populate
Define a global u32 __stacksize__=64*1024; would change it to 64k.
extern u8 buffer_test[64*1024];
extern u32 buffer_test2[64*1024];
u8 buffer_test[64*1024];
u32 buffer_test2[64*1024];
are you sure? I mean I dont want to be "that guy" but this u8 is 1 byte and u32 is 4, so ..
main.h
Code:extern u8 buffer_test[64*1024]; extern u32 buffer_test2[64*1024];
main.c
Code:u8 buffer_test[64*1024]; u32 buffer_test2[64*1024];
compiled and reserved size for each: (from map file)
so buffer_test is 64k
but buffer_test2 is 64k*4 = 256k
ah well this screen was from devkitarm (libnds), same as map (ARM9 being int 32 bit). But still, i am curious now__stacksize__ is not an array of said size...
You are comparing two separate environments - nds and 3ds - completely different. plus you are comparing the definition of the stack (nds) with the definition of the size of the stack (3ds). In ctrulib __stacksize__ is a weakly define u32 that contains the size of the stack to create during initialization. The weak definition means if you create it in your code it will be used instead of the value in ctrulib. It needs to be defined at global scope and needs to use C naming not C++ or it will not match.ah well this screen was from devkitarm (libnds), same as map (ARM9 being int 32 bit). But still, i am curious now
You are comparing two separate environments - nds and 3ds - completely different. plus you are comparing the definition of the stack (nds) with the definition of the size of the stack (3ds). In ctrulib __stacksize__ is a weakly define u32 that contains the size of the stack to create during initialization. The weak definition means if you create it in your code it will be used instead of the value in ctrulib. It needs to be defined at global scope and needs to use C naming not C++ or it will not match.
.
For the nds the stack needs to be created at a fixed hardware address location with a static size
@---------------------------------------------------------------------------------
@ Protection Unit Setup added by Sasq
@---------------------------------------------------------------------------------
@ Disable cache
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ Instruction cache
mcr p15, 0, r0, c7, c6, 0 @ Data cache
@ Wait for write buffer to empty
mcr p15, 0, r0, c7, c10, 4
ldr r0, =__dtcm_start
orr r0,r0,#0x0a
mcr p15, 0, r0, c9, c1,0 @ DTCM base = __dtcm_start, size = 16 KB
mov r0,#0x20
mcr p15, 0, r0, c9, c1,1 @ ITCM base = 0 , size = 32 MB
Perhaps I should have been more clear that I meant libnds rather than just nds. As you said the base address is specified in the linker script which also places the stack relative to that location and size. The distinction did not seem necessary in the context of distinguishing between u32 vs a u32 array. Also the code you referenced does not do what you think it does - an easy mistake to make in your over-zealous attempt to prove me wrong. In any case I hope you found/proved what you needed.Of course I am aware of the differences between overriding with a __weak attribute, different data/code paths, the linker sections, the relocated code and the code sections. But still, as a weakly define i am seeing 64*4*1024 (u32) which is NOT 64k as stack. This made me double check this against a map file what would've been the final stack size. Now I didnt know ctrulib can override stack size like this (and I dont think I could really care for now), but if I ever see u32 __something__ [64*1024] I will know it will be a multiple of sizeof(u32),
edit: nope it was u32 __weak_symbol__ = 64*1024; I am wrong here.
Yeah no, you do know (nds) CP15's can move the base address/size (DTCM) ? And that is perfectly configurable through linker. Size must be fixed, but definitely you can move base address (c9, c1,0)
mpu_setup.s (google )
Code:@--------------------------------------------------------------------------------- @ Protection Unit Setup added by Sasq @--------------------------------------------------------------------------------- @ Disable cache mov r0, #0 mcr p15, 0, r0, c7, c5, 0 @ Instruction cache mcr p15, 0, r0, c7, c6, 0 @ Data cache @ Wait for write buffer to empty mcr p15, 0, r0, c7, c10, 4 ldr r0, =__dtcm_start orr r0,r0,#0x0a mcr p15, 0, r0, c9, c1,0 @ DTCM base = __dtcm_start, size = 16 KB mov r0,#0x20 mcr p15, 0, r0, c9, c1,1 @ ITCM base = 0 , size = 32 MB
So you mapped some memory address ranges. Weren't we talking about stack size and where it is located? I am not sure why you are asking questions if you already think you have all of the answers.Perhaps it is you who need to understand how to set up tcm base addresses through a co processor call.. Except nds has a protection unit https://books.google.cl/books?id=qbfi3tJJhPEC&pg=PA117&lpg=PA117&dq=c9+c1+0+arm&source=bl&ots=YB3jPtlCrg&sig=HTCCfA5gAOvd6KajPvXnmJXR2G4&hl=es&sa=X&redir_esc=y#v=onepage&q=c9 c1 0 arm&f=false
#ifndef AudioFX_H
#define AudioFX_H
#define channel_range 10 //usually only ~4 are needed, just for testing
#include <3ds.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class AudioFX{
public:
AudioFX();
void setChannel(int var1);
bool initSfx(const char* name);
void play();
int fullChns();
int getChannelRange();
private:
int channel[channel_range];
ndspWaveBuf waveBuf;
};
#endif
#include "AudioFX.h"
AudioFX::AudioFX(){
}
void AudioFX::setChannel(int var1){
for (int i=0; i<channel_range; i++){
ndspChnWaveBufClear(channel[i]);
channel[i]=var1+i;
}
}
bool AudioFX::initSfx(const char* name){
u32 sampleRate;
u32 dataSize;
u16 channels;
u16 bitsPerSample;
FILE* fp = fopen(name, "rb");
if(!fp){
//Could not open file
return 0;
}
char signature[4];
fread(signature, 1, 4, fp);
if( signature[0] != 'R' &&
signature[1] != 'I' &&
signature[2] != 'F' &&
signature[3] != 'F'){
//Wrong file format
fclose(fp);
return 0;
}
fseek(fp, 22, SEEK_SET);
fread(&channels, 2, 1, fp);
fseek(fp, 24, SEEK_SET);
fread(&sampleRate, 4, 1, fp);
fseek(fp, 34, SEEK_SET);
fread(&bitsPerSample, 2, 1, fp);
fseek(fp,46,SEEK_END);
dataSize = ftell(fp);
if(dataSize == 0 || (channels != 1 && channels != 2) ||
(bitsPerSample != 8 && bitsPerSample != 16))
{
//Corrupted file
fclose(fp);
return 0;
}
// Allocating and reading samples
u8* data = (u8*)linearAlloc(dataSize);
if(!data)
{
fclose(fp);
return 0;
}
fseek(fp, 44, SEEK_SET);
fread(data, 1, dataSize, fp);
fclose(fp);
// Find the right format
u16 ndspFormat;
if(bitsPerSample == 8)
{
ndspFormat = (channels == 1) ?
NDSP_FORMAT_MONO_PCM8 :
NDSP_FORMAT_STEREO_PCM8;
}
else
{
ndspFormat = (channels == 1) ?
NDSP_FORMAT_MONO_PCM16 :
NDSP_FORMAT_STEREO_PCM16;
}
for (int i=0; i<channel_range; i++){
ndspChnReset(channel[i]);
ndspChnSetInterp(channel[i], NDSP_INTERP_NONE);
ndspChnSetRate(channel[i], (float)sampleRate);
ndspChnSetFormat(channel[i], ndspFormat);
}
// Create wav buffer
memset(&waveBuf, 0, sizeof(waveBuf));
waveBuf.data_vaddr = (const void*)data;
waveBuf.nsamples = dataSize / (bitsPerSample >> 3);
waveBuf.looping = false; // Loop enabled
waveBuf.status = NDSP_WBUF_FREE;
DSP_FlushDataCache(data, dataSize);
return 1;
}
void AudioFX::play(){
for (int i=0; i<channel_range; i++){
if (!ndspChnIsPlaying(channel[i])){
ndspChnWaveBufClear(channel[i]);
ndspChnWaveBufAdd(channel[i], &waveBuf);
break;
}
}
}
int AudioFX::fullChns(){
int ret=0;
for (int i=0; i<channel_range; i++){
if (ndspChnIsPlaying(channel[i])){
ret+=1;
}
}
return ret;
}
int AudioFX::getChannelRange(){
return channel_range;
}
Why are you resetting all channels in initSfx?So I have a dsp related issue (probably not dsp's fault but mine). The problem is that if I play the sound effect frequently (around 3 sounds including background music) there starts to be a very annoying cracking noise. I don't know what's causing it, it's probably my code that handles the sfx because of my very lacking understanding of how dsp works.
Here are the source files for the sound effects:
AudioFX.h:
Code:#ifndef AudioFX_H #define AudioFX_H #define channel_range 10 //usually only ~4 are needed, just for testing #include <3ds.h> #include <stdio.h> #include <stdlib.h> #include <string.h> class AudioFX{ public: AudioFX(); void setChannel(int var1); bool initSfx(const char* name); void play(); int fullChns(); int getChannelRange(); private: int channel[channel_range]; ndspWaveBuf waveBuf; }; #endif
AudioFX.cpp:
Code:#include "AudioFX.h" AudioFX::AudioFX(){ } void AudioFX::setChannel(int var1){ for (int i=0; i<channel_range; i++){ ndspChnWaveBufClear(channel[i]); channel[i]=var1+i; } } bool AudioFX::initSfx(const char* name){ u32 sampleRate; u32 dataSize; u16 channels; u16 bitsPerSample; FILE* fp = fopen(name, "rb"); if(!fp){ //Could not open file return 0; } char signature[4]; fread(signature, 1, 4, fp); if( signature[0] != 'R' && signature[1] != 'I' && signature[2] != 'F' && signature[3] != 'F'){ //Wrong file format fclose(fp); return 0; } fseek(fp, 22, SEEK_SET); fread(&channels, 2, 1, fp); fseek(fp, 24, SEEK_SET); fread(&sampleRate, 4, 1, fp); fseek(fp, 34, SEEK_SET); fread(&bitsPerSample, 2, 1, fp); fseek(fp,46,SEEK_END); dataSize = ftell(fp); if(dataSize == 0 || (channels != 1 && channels != 2) || (bitsPerSample != 8 && bitsPerSample != 16)) { //Corrupted file fclose(fp); return 0; } // Allocating and reading samples u8* data = (u8*)linearAlloc(dataSize); if(!data) { fclose(fp); return 0; } fseek(fp, 44, SEEK_SET); fread(data, 1, dataSize, fp); fclose(fp); // Find the right format u16 ndspFormat; if(bitsPerSample == 8) { ndspFormat = (channels == 1) ? NDSP_FORMAT_MONO_PCM8 : NDSP_FORMAT_STEREO_PCM8; } else { ndspFormat = (channels == 1) ? NDSP_FORMAT_MONO_PCM16 : NDSP_FORMAT_STEREO_PCM16; } for (int i=0; i<channel_range; i++){ ndspChnReset(channel[i]); ndspChnSetInterp(channel[i], NDSP_INTERP_NONE); ndspChnSetRate(channel[i], (float)sampleRate); ndspChnSetFormat(channel[i], ndspFormat); } // Create wav buffer memset(&waveBuf, 0, sizeof(waveBuf)); waveBuf.data_vaddr = (const void*)data; waveBuf.nsamples = dataSize / (bitsPerSample >> 3); waveBuf.looping = false; // Loop enabled waveBuf.status = NDSP_WBUF_FREE; DSP_FlushDataCache(data, dataSize); return 1; } void AudioFX::play(){ for (int i=0; i<channel_range; i++){ if (!ndspChnIsPlaying(channel[i])){ ndspChnWaveBufClear(channel[i]); ndspChnWaveBufAdd(channel[i], &waveBuf); break; } } } int AudioFX::fullChns(){ int ret=0; for (int i=0; i<channel_range; i++){ if (ndspChnIsPlaying(channel[i])){ ret+=1; } } return ret; } int AudioFX::getChannelRange(){ return channel_range; }