Random Kernel Panic during Sound Playback

Post Reply
tomastr21
Posts: 1
Joined: Sun Nov 10, 2024 5:23 pm

Random Kernel Panic during Sound Playback

Post by tomastr21 » Mon Nov 18, 2024 11:46 pm

So, i was trying to get sounds working on my 3DS, and it did. But for some reason, it will randomly crash during playback (Prefetch Abort (Kernel Panic)), sometimes it doesnt crash, but other times it does, to wich i dont understand what caused this... i tried find the issue, but no success... can anyone look into it (my code is messy sorry):

audio.cpp

Code: Select all

#include "audio.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
// ----------------------- MUSIC VARIABLES -------------------------------
ndspWaveBuf s_musicWaveBufs[3];
int16_t* s_musicAudioBuffer = nullptr;
volatile bool s_musicQuit = false;

// ----------------------- MUSIC VARIABLES -------------------------------
const char *opusStrError(int error)
{
    switch(error) {
        case OP_FALSE:
            return "OP_FALSE: A request did not succeed.";
        case OP_HOLE:
            return "OP_HOLE: There was a hole in the page sequence numbers.";
        case OP_EREAD:
            return "OP_EREAD: An underlying read, seek or tell operation "
                   "failed.";
        case OP_EFAULT:
            return "OP_EFAULT: A NULL pointer was passed where none was "
                   "expected, or an internal library error was encountered.";
        case OP_EIMPL:
            return "OP_EIMPL: The stream used a feature which is not "
                   "implemented.";
        case OP_EINVAL:
            return "OP_EINVAL: One or more parameters to a function were "
                   "invalid.";
        case OP_ENOTFORMAT:
            return "OP_ENOTFORMAT: This is not a valid Ogg Opus stream.";
        case OP_EBADHEADER:
            return "OP_EBADHEADER: A required header packet was not properly "
                   "formatted.";
        case OP_EVERSION:
            return "OP_EVERSION: The ID header contained an unrecognised "
                   "version number.";
        case OP_EBADPACKET:
            return "OP_EBADPACKET: An audio packet failed to decode properly.";
        case OP_EBADLINK:
            return "OP_EBADLINK: We failed to find data we had seen before or "
                   "the stream was sufficiently corrupt that seeking is "
                   "impossible.";
        case OP_ENOSEEK:
            return "OP_ENOSEEK: An operation that requires seeking was "
                   "requested on an unseekable stream.";
        case OP_EBADTIMESTAMP:
            return "OP_EBADTIMESTAMP: The first or last granule position of a "
                   "link failed basic validity checks.";
        default:
            return "Unknown error.";
    }
}

bool Audio::MusicInit()
{
    // Setup NDSP
    ndspChnReset(0);
    ndspSetOutputMode(NDSP_OUTPUT_STEREO);
    ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE);
    ndspChnSetRate(0, SAMPLE_RATE);
    ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);

// Allocate audio buffer
const size_t bufferSize = WAVEBUF_SIZE * ARRAY_SIZE(s_musicWaveBufs);
s_musicAudioBuffer = (int16_t *)linearAlloc(bufferSize);
if(!s_musicAudioBuffer) {
    printf("Failed to allocate audio buffer\n");
    return false;
}

// Setup waveBufs for NDSP
memset(&s_musicWaveBufs, 0, sizeof(s_musicWaveBufs));
int16_t *buffer = s_musicAudioBuffer;

for(size_t i = 0; i < ARRAY_SIZE(s_musicWaveBufs); ++i) {
    s_musicWaveBufs[i].data_vaddr = buffer;
    s_musicWaveBufs[i].status     = NDSP_WBUF_DONE;

    buffer += WAVEBUF_SIZE / sizeof(buffer[0]);
}

return true;

}

void Audio::MusicExit()
{
    ndspChnReset(0);
    linearFree(s_musicAudioBuffer);
}


static bool FillMusicBuffer(OggOpusFile* opusFile_, ndspWaveBuf* waveBuf_)
{
    #ifdef DEBUG
    // Setup timer for performance stats
    TickCounter timer;
    osTickCounterStart(&timer);
    #endif  // DEBUG

// Decode samples until our waveBuf is full
int totalSamples = 0;
while(totalSamples < SAMPLES_PER_BUF) {
    int16_t *buffer = waveBuf_->data_pcm16 + (totalSamples *
        CHANNELS_PER_SAMPLE);
    const size_t bufferSize = (SAMPLES_PER_BUF - totalSamples) *
        CHANNELS_PER_SAMPLE;

    // Decode bufferSize samples from opusFile_ into buffer,
    // storing the number of samples that were decoded (or error)
    const int samples = op_read_stereo(opusFile_, buffer, bufferSize);
    if(samples <= 0) {
        if(samples == 0) break;  // No error here

        printf("op_read_stereo: error %d (%s)", samples,
               opusStrError(samples));
        break;
    }
    
    totalSamples += samples;
}

// If no samples were read in the last decode cycle, we're done
if(totalSamples == 0) {
    printf("Playback complete, press Start to exit\n");
    return false;
}

// Pass samples to NDSP
waveBuf_->nsamples = totalSamples;
ndspChnWaveBufAdd(0, waveBuf_);
DSP_FlushDataCache(waveBuf_->data_pcm16,
    totalSamples * CHANNELS_PER_SAMPLE * sizeof(int16_t));

#ifdef DEBUG
// Print timing info
osTickCounterUpdate(&timer);
printf("fillBuffer %lfms in %lfms\n", totalSamples * 1000.0 / SAMPLE_RATE,
       osTickCounterRead(&timer));
#endif  // DEBUG

return true;
}

void Audio::GeneralAudioCallback(void* const nul_)
{

(void)nul_;  // Unused

if(s_musicQuit)
{
    return;
}
  

LightEvent_Signal(&s_musicEvent);

}

void Audio::MusicAudioThread(void *const opusFile_)
{
    OggOpusFile *const opusFile = (OggOpusFile *)opusFile_;

while(!s_musicQuit) {  // Whilst the quit flag is unset,
                  // search our waveBufs and fill any that aren't currently
                  // queued for playback (i.e, those that are 'done')
    for(size_t i = 0; i < ARRAY_SIZE(s_musicWaveBufs); ++i) {
        if(s_musicWaveBufs[i].status != NDSP_WBUF_DONE) {
            continue;
        }
        
        if(!FillMusicBuffer(opusFile, &s_musicWaveBufs[i]) || s_musicQuit) {   // Playback complete
            return;
        }
    }

    // Wait for a signal that we're needed again before continuing,
    // so that we can yield to other things that want to run
    // (Note that the 3DS uses cooperative threading)
    LightEvent_Wait(&s_musicEvent);
}
}

void Audio::SetMusicQuit(bool quit)
{
    s_musicQuit = quit;
    LightEvent_Signal(&s_musicEvent);
}

audio.h

Code: Select all

#ifndef AUDIO_H
#define AUDIO_H

#include <3ds.h>
#include <opusfile.h>

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))

static const int SAMPLE_RATE = 48000;            // Opus is fixed at 48kHz
static const int SAMPLES_PER_BUF = SAMPLE_RATE * 120 / 1000;  // 120ms buffer
static const int CHANNELS_PER_SAMPLE = 2;  

static const int THREAD_AFFINITY = -1;           // Execute thread on any core
static const int THREAD_STACK_SZ = 32 * 1024; 

static const size_t WAVEBUF_SIZE = SAMPLES_PER_BUF * CHANNELS_PER_SAMPLE
    * sizeof(int16_t); 

static LightEvent s_musicEvent;

namespace Audio {
    bool MusicInit();
    void MusicExit();
    void GeneralAudioCallback(void* const nul_);
    void MusicAudioThread(void *const opusFile_);
    void SetMusicQuit(bool quit);
};

#endif

const char *opusStrError(int error);

main.cpp

Code: Select all

#include <cstdio>
#include <3ds.h>
#include <citro3d.h>
#include <citro2d.h>
#include "render.h"
#include "example_cube.h"  // Vertex data for a cube
#include "audio.h"

static const char *EX_AUDIO_PATH = "romfs:/music/sample.opus"; 

int main()
{


// Initialize graphics and console for debug output
gfxInitDefault();
//consoleInit(GFX_BOTTOM, nullptr);
ndspInit();
osSetSpeedupEnable(true);
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
LightEvent_Init(&s_musicEvent, RESET_ONESHOT);
// Create the render target for the top screen (3D)
C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
C3D_RenderTarget* target_bottom = C3D_RenderTargetCreate(240, 320, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetOutput(target_bottom, GFX_BOTTOM, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);

Result rc = romfsInit();
if (rc)
	printf("romfsInit: %08lX\n", rc);
    else
    printf("romfsInit: OK\n");
// Initialize the Render system
   
Render::Init();


int error = 0;
OggOpusFile *opusFile = op_open_file(EX_AUDIO_PATH, &error);
if(error)
{
    return EXIT_FAILURE;
}

if(!Audio::MusicInit())
{
    printf("Audio::MusicInit failed\n");
    C3D_Fini();
    gfxExit();
    ndspExit();
    romfsExit();
    return EXIT_FAILURE;
}

ndspSetCallback(Audio::GeneralAudioCallback, opusFile);

int32_t priority = 0x30;
svcGetThreadPriority(&priority, CUR_THREAD_HANDLE);
priority -= 1;
priority = priority < 0x18 ? 0x18 : priority;
priority = priority > 0x3F ? 0x3F : priority;

const Thread threadID = threadCreate(Audio::MusicAudioThread, opusFile, THREAD_STACK_SZ, priority, THREAD_AFFINITY, false);

printf("Press START to exit.\n");
float rotade = 0.0f;
bool disable_toogle_cube = false;
   

// Ensure the integer stays persistent (no revert to 0)


printf("Vertex size count: %d\n", vbo_buffer_data_count[2]);


Render::LoadTexture("kitten.t3x", 1);
Render::LoadTexture("title_test.t3x", 2);
s64 memUsed, memFree;






// Main loop
while (aptMainLoop())
{

    hidScanInput();

    // Exit on START button press
    if (hidKeysDown() & KEY_START)
        break;

    if (hidKeysDown() & KEY_A && !disable_toogle_cube)
    {
        disable_toogle_cube = true;
    }
    else if(hidKeysDown() & KEY_A && disable_toogle_cube)
    {
        disable_toogle_cube = false;
    }

    size_t linear_memory_used = osGetMemRegionUsed(MemRegion::MEMREGION_ALL);
    size_t linear_memory_free = osGetMemRegionFree(MemRegion::MEMREGION_ALL);

    // Convert bytes to MB
    float used_mb = linear_memory_used / (1024.0f * 1024.0f);
    float free_mb = linear_memory_free / (1024.0f * 1024.0f);
    /*
    printf("\x1b[2;1HCPU:     %6.2f%%\x1b[K", C3D_GetProcessingTime()*6.0f);
	printf("\x1b[3;1HGPU:     %6.2f%%\x1b[K", C3D_GetDrawingTime()*6.0f);
	printf("\x1b[4;1HCmdBuf:  %6.2f%%\x1b[K", C3D_GetCmdBufUsage()*100.0f);
    Get the ram usage*/
    //printf("\x1b[5;1HRAM Used:      %.2f MB\x1b[K", used_mb);
    //printf("\x1b[6;1HRAM Free:      %.2f MB\x1b[K", free_mb);
    

    // Begin rendering the frame
    C3D_FrameBegin(C3D_FRAME_SYNCDRAW);

        //C2D_TargetClear(render_target_2d, C2D_Color32(0xFF, 0xD8, 0xB0, 0x68));
        
        // Start the 2D scene on the bottom screen
       
        rotade += 0.01f;
        // Clear the 3D screen and start drawing
        C3D_RenderTargetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
        C3D_FrameDrawOn(target);
        Render::SetBottomViewport(false);
if(!disable_toogle_cube)
                    Render::AddMeshInstance(2,0,0,0, -2, 0.5f, 0.5f, 0.5f, 0, rotade, 0);
                     Render::AddCubeInstance(0,sinf(rotade) , sinf(rotade * 2), -2, 0.5f, -rotade, -rotade);
        Render::AddCubeInstance(0,sinf(-rotade), sinf(-rotade * 2), -2, 0.5f, rotade, -rotade);
       
//Render::AddSpriteInstance(1, 20.0f, 20.0f, 1.0f, 1.0f); // Render all queued instances (cubes) Render::Render(); C3D_RenderTargetClear(target_bottom, C3D_CLEAR_ALL, CLEAR_COLOR, 0); C3D_FrameDrawOn(target_bottom); Render::SetBottomViewport(true); //C3D_DepthTest(false, GPU_GREATER, GPU_WRITE_ALL); // Render::AddQuadInstance(2, 0, 0, -2.1f, sinf(rotade) + 3, 1, 0, 0, 0); Render::AddMeshInstance(2,1, 0, -0.5f, -2, 0.3, 0.3, 0.3, rotade, 0,0); Render::Render(); //C3D_DepthTest(true, GPU_GREATER, GPU_WRITE_ALL); C3D_FrameEnd(0); } Audio::SetMusicQuit(true); LightEvent_Signal(&s_musicEvent); threadJoin(threadID, UINT64_MAX); threadFree(threadID); // Cleanup printf("Quitting..."); Render::Exit(); C3D_Fini(); Audio::MusicExit(); ndspExit(); op_free(opusFile); gfxExit(); romfsExit(); return 0; }

Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests