Probleme bei der Initialisierungsreihenfolge von globalen Objekten



  • Hallo Leutz, wie der Titel schon verlauten lässt habe ich womöglich ein Probleme mit der Initialisierungsreihenfolge von Objekten bzw mit der Boot Prozedur der PS2.

    Das Problem ist das der Audio Stream nicht triggert weil ein Semaphore hängt.
    Hier ist mal die komplette Audiostream.h

    #ifndef AUDIOSTREAM_H
    #define AUDIOSTREAM_H
    #ifdef __cplusplus
    #include <cstdlib>
    #else
    #include <stdlib.h>
    #endif
    
    #include <stdio.h>
    #include <kernel.h>
    #include <tamtypes.h>
    #include <cstdlib> // für free
    #include <cstdint>  // Für uint8_t, uint32_t
    #include <cstddef>  // Für NULL
    #include <cstring>  // Für memcpy
    
    #define STACK_SIZE (32 * 1024)
    
    // 1. WICHTIG: Konstante definieren, damit sie überall bekannt ist
    #define AUDIO_BLOCK_SAMPLES 256
    #define AUDIO_SAMPLE_RATE_EXACT 48000.0f
    #define AUDIO_SAMPLE_RATE (int)(AUDIO_SAMPLE_RATE_EXACT)
    #define MAX_AUDIO_MEMORY 6144
    #define NUM_MASKS (((MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2) + 31) / 32)
    
    // 2. Forward Declarations
    class AudioStream;
    class AudioConnection;
    
    typedef struct audio_block_struct
    {
        uint8_t  ref_count;
        uint16_t memory_pool_index;
        float    data[AUDIO_BLOCK_SAMPLES];
    } audio_block_t;
    
    class AudioConnection
    {
    public:
        AudioConnection();
        AudioConnection(AudioStream &source, AudioStream &destination)
            : AudioConnection()
        {
            connect(source,destination);
        }
        AudioConnection(AudioStream &source, unsigned char sourceOutput,
                        AudioStream &destination, unsigned char destinationInput)
            : AudioConnection()
        {
            connect(source,sourceOutput, destination,destinationInput);
        }
        friend class AudioStream;
        ~AudioConnection();
        int disconnect(void);
        int connect(void);
        int connect(AudioStream &source, AudioStream &destination)
        {
            return connect(source,0,destination,0);
        };
        int connect(AudioStream &source, unsigned char sourceOutput,
                    AudioStream &destination, unsigned char destinationInput);
    
    protected:
        AudioStream* src;
        AudioStream* dst;
        unsigned char src_index;
        unsigned char dest_index;
        AudioConnection *next_dest;
        bool isConnected;
    };
    
    class AudioStream
    {
    public:
        AudioStream(unsigned char ninput, audio_block_t **iqueue) :
            num_inputs(ninput), inputQueue(iqueue)
        {
            active = false;
            destination_list = NULL;
            for (int i=0; i < num_inputs; i++)
            {
                inputQueue[i] = NULL;
            }
            // add to a simple list, for update_all
            // TODO: replace with a proper data flow analysis in update_all
            if (first_update == NULL)
            {
                first_update = this;
            }
            else
            {
                AudioStream *p;
                for (p=first_update; p->next_update; p = p->next_update) ;
                p->next_update = this;
            }
            next_update = NULL;
            numConnections = 0;
        }
    
        static void initialize_memory(audio_block_t *data, unsigned int num);
        static void AudioNoInterrupts()
        {
            update_exceptions++;
        }
        static void AudioInterrupts()
        {
            if (update_exceptions > 0) update_exceptions--;
        }
    
    protected:
        bool active;
        friend class AudioConnection;
        static audio_block_t * allocate(void);
        static void release(audio_block_t * block);
        void transmit(audio_block_t *block, unsigned char index = 0);
        audio_block_t * receiveReadOnly(unsigned int index = 0);
        audio_block_t * receiveWritable(unsigned int index = 0);
        static bool update_setup(void);
        static void update_stop(void);
        static void update_all(void)
        {
                printf("DEBUG: update_all check! audioSemaID ist: %d (Adresse: %p)\n", audioSemaID, (void*)&audioSemaID);
            if(audioSemaID == -1 )return;
            SignalSema(audioSemaID);
        }
        uint8_t num_inputs;
        uint32_t numConnections;
        friend void software_isr(void* arg);
        friend u64 tick_cb(s32 id, u64 scheduled, u64 actual, void* arg, void* pc_val);
    
    private:
        static AudioConnection* unused;
        audio_block_t **inputQueue;
        static AudioStream *first_update;
        AudioStream *next_update;
        AudioConnection *destination_list;
        virtual void update(void) = 0;
        static audio_block_t *memory_pool;
        static uint32_t memory_pool_available_mask[NUM_MASKS];
        static uint16_t memory_pool_first_mask;
        // Statistiken (optional)
        static uint16_t memory_used;
        static uint16_t memory_used_max;
        static volatile s32 audioSemaID;
        static bool update_scheduled;
        static u64 s_audio_ticks;
        static volatile uint32_t update_exceptions;
    };
    
    #define AudioMemory(num) ({ \
    	static audio_block_t data[num]; \
    	AudioStream::initialize_memory(data, num); \
    })
    
    
    #endif
    

    AudioOutput:

    #ifndef AUDIOOUTPUTSTREAM_H
    #define AUDIOOUTPUTSTREAM_H
    #ifdef __cplusplus
    #include <cstdlib>
    #else
    #include <stdlib.h>
    #endif
    #include <cstdint>
    #include "AudioStream.h"
    
    #define CHUNK_SIZE 2048              // Bytes pro audsrv_play_audio Aufruf
    #define RING_BUFFER_BLOCKS 8
    
    class AudioOutputStream  : public AudioStream
    {
    public:
        AudioOutputStream(void) : AudioStream(2, inputQueueArray)
        {
            begin();
        }
        void begin(void);
        virtual void update(void);
        friend class AudioInputStream;
    
    protected:
        static bool update_responsibility;
        friend int fillbuffer(void *arg);
    
    private:
        static volatile int write_idx;
        static volatile int read_idx;
        static volatile int blocks_available;
        audio_block_t *inputQueueArray[2];
    };
    
    #endif // AUDIOOUTPUTSTREAM_H
    
    
    int fillbuffer(void *arg)
    {
    
    /*
        u32 sec, usec;
        TimerBusClock2USec(GetTimerSystemTime(), &sec, &usec);
        u32 now =  usec;
        time_callback = now - last_time_callback;
        last_time_callback = now;
    */
        if(AudioOutputStream::update_responsibility)
        {
            AudioStream::update_all();
            AudioStream::update_all();
        }
    
        // Wir brauchen 2048 Bytes, also genau 2 Audio-Blöcke (2 x 1024 Bytes)
        if (AudioOutputStream::blocks_available >= 2)
        {
            // Zeiger auf den aktuellen Startblock
            // (Da wir immer um 2 erhöhen, sind die nächsten 2048 Bytes garantiert am Stück im RAM)
            char *src_ptr = (char*)&ring_buffer[AudioOutputStream::read_idx * AUDIO_BLOCK_SAMPLES * 2];
    
            // Ein einziger Aufruf für die vollen 2048 Bytes
            int played = audsrv_play_audio(src_ptr, CHUNK_SIZE);
    
            // audsrv_play_audio gibt die Anzahl der verarbeiteten Bytes zurück
            if (played > 0)
            {
                // Lese-Index um 2 Blöcke weiterschieben
                AudioOutputStream::read_idx = (AudioOutputStream::read_idx + 2) % RING_BUFFER_BLOCKS;
    
                DI();
                AudioOutputStream::blocks_available -= 2;
                EI();
            }
        }
        else
        {
            audsrv_play_audio(silence, CHUNK_SIZE);
        }
    
        return 0;
    }
    
    
    void AudioOutputStream::begin()
    {
        update_responsibility = update_setup();//this booting the IOP
        int ret;
        int err;
        printf("#Lade audsrv\n");
        #ifdef _DTL_T10000
         int modul_ret;
    
        ret = SifLoadModule("host:irx/libsd.irx", 0, NULL);
    	printf("LIBSD loadmodule %d\n", ret);
    
        ret = SifLoadStartModule("host:irx/audsrv.irx", 0, NULL, &modul_ret);
        printf("AUDSRV SifLoad_ret: %d Modul_ret: %d\n", ret, modul_ret);
    
        #else
        ret = SifLoadModule("rom0:LIBSD", 0, NULL);
        printf("libsd loadmodule %d\n", ret);
    
        ret = SifLoadModule("host:audsrv.irx", 0, NULL);
        printf("audsrv loadmodule %d\n", ret);
            #endif // _DTL_T10000
    
        ret = audsrv_init();
        if (ret != 0)
        {
            printf("failed to initialize audsrv\n");
            printf("audsrv returned error string: %s\n", audsrv_get_error_string());
            return;
        }
        struct audsrv_fmt_t format;
        format.bits = 16;
        format.freq = AUDIO_SAMPLE_RATE;
        format.channels = 2;
        err = audsrv_set_format(&format);
        printf("set format returned %d\n", err);
        printf("audsrv returned error string: %s\n", audsrv_get_error_string());
    
        audsrv_set_volume(MAX_VOLUME);
    
        err = audsrv_on_fillbuf(CHUNK_SIZE, fillbuffer, NULL);
        if (err != AUDSRV_ERR_NOERROR)
        {
            printf("audsrv_on_fillbuf failed with err=%d\n", err);
        }
    }
    
    void AudioOutputStream::update()
    {
    /*
        u32 sec, usec;
        TimerBusClock2USec(GetTimerSystemTime(), &sec, &usec);
        u32 now =  usec;
        printf("Intervall update: %d\n",now - last_time_update);
        last_time_update = now;
        printf("Intervall callback: %d\n", time_callback);
    
    */
    printf("AudioOutputStream::update()\n");
    
        // 1. Check auf Buffer Overflow (optional, aber empfohlen)
        if (blocks_available >= RING_BUFFER_BLOCKS) return;
    

    In der main.cpp instanziiere ich globale Objecte.
    AudioSynthWaveformSine sine1;
    //AudioInputStream audioIn;
    AudioOutputStream audioOut;
    Audio_fftr FFT;

    AudioConnection patchCord0(sine1, 0, audioOut, 0);
    AudioConnection patchCord1(sine1, 0, audioOut, 1);
    AudioConnection patchCord2(sine1, 0, FFT, 0);

    und in der main Funktion kommt irwann erst
    AudioMemory(32);
    das widerum feuert void AudioStream::initialize_memory(audio_block_t *data, unsigned int num)

    #include "AudioStream.h"
    #include <timer.h>
    #include <stdio.h>
    #include "IOP_BOOT.h"
    
    audio_block_t * AudioStream::memory_pool;
    uint32_t AudioStream::memory_pool_available_mask[NUM_MASKS];
    uint16_t AudioStream::memory_pool_first_mask;
    
    bool AudioStream::update_scheduled = false;
    uint16_t AudioStream::memory_used = 0;
    uint16_t AudioStream::memory_used_max = 0;
    AudioConnection* AudioStream::unused = NULL;
    AudioStream * AudioStream::first_update = NULL;
    static u8 threadStack[STACK_SIZE] __attribute__((aligned(16)));
    volatile s32 AudioStream::audioSemaID = -1;
    u64 AudioStream::s_audio_ticks = 0;
    volatile uint32_t AudioStream::update_exceptions = 0;
    
    
    void software_isr(void* arg)
    {
        while(1)
        {
            // 1. Der Thread wartet IMMER auf den Timer
            WaitSema(AudioStream::audioSemaID);
            // 2. Nur wenn keine Sperre vorliegt, wird gerechnet
            if (AudioStream::update_exceptions == 0)
            {
                AudioStream *p;
                for (p = AudioStream::first_update; p; p = p->next_update)
                {
                    if (p->active) p->update();
                }
            }
            EE_SYNC();
    
        }
    }
    
    // Die Signatur entspricht exakt deinem typedef
    u64 tick_cb(s32 id, u64 scheduled, u64 actual, void* arg, void* pc_val)
    {
        // Signal an die Semaphore
        iSignalSema(AudioStream::audioSemaID);
        // WICHTIG: Damit es ein Intervall bleibt, geben wir den nächsten
        // Zeitpunkt basierend auf der GEPLANTEN Zeit zurück.
        // Das verhindert, dass sich kleine Verzögerungen aufsummieren (Drift).
        return AudioStream::s_audio_ticks;
    }
    
    void AudioStream::initialize_memory(audio_block_t *data, unsigned int num)
    {
        unsigned int i;
        unsigned int maxnum = MAX_AUDIO_MEMORY / AUDIO_BLOCK_SAMPLES / 2;
        if (num > maxnum) num = maxnum;
    
        // --- START CRITICAL SECTION ---
        DI();
        memory_pool = data;
        memory_pool_first_mask = 0;
        for (i=0; i < NUM_MASKS; i++)
        {
            memory_pool_available_mask[i] = 0;
        }
        for (i=0; i < num; i++)
        {
            memory_pool_available_mask[i >> 5] |= (1 << (i & 0x1F));
        }
        for (i=0; i < num; i++)
        {
            data[i].memory_pool_index = i;
        }
        EI();
        // --- END CRITICAL SECTION ---
    
        // Ab hier sind Interrupts wieder an. Kernel-Calls sind jetzt sicher!
    
        ee_sema_t audioSema;
        memset(&audioSema, 0, sizeof(audioSema));
        audioSema.init_count = 0;
        audioSema.max_count = 3;
        audioSema.option = 0;
        audioSemaID = CreateSema(&audioSema);
        printf("DEBUG: Frisch erstellt! audioSemaID ist jetzt: %d (Adresse: %p)\n", audioSemaID, (void*)&audioSemaID);
        fflush(stdout);
    
        ee_thread_t threadParam;
        memset(&threadParam, 0, sizeof(threadParam));
        threadParam.func = (void*)software_isr;
        threadParam.stack = threadStack;
        threadParam.stack_size = STACK_SIZE;
        threadParam.gp_reg = &_gp; // Global Pointer der EE
        threadParam.initial_priority = 10; // Hohe Priorität als Main 16
        s32 threadID = CreateThread(&threadParam);
        StartThread(threadID, NULL);
    
        printf("::initialize_memory %d\n", update_scheduled);
    
        if (update_scheduled == false)
        {
            update_setup();
            float usec = 1e6 * AUDIO_BLOCK_SAMPLES / AUDIO_SAMPLE_RATE_EXACT;
            s_audio_ticks = USec2TimerBusClock(usec);
            s32 id = AllocTimerCounter();
            SetTimerHandler(id,  s_audio_ticks, tick_cb, &s_audio_ticks);
            StartTimerCounter(id);
        }
    }
    

    Die Sache ist nun das zuerst die globalen Objekte erstellt werden, das widerum feuert
    void AudioOutputStream::begin()
    {
    update_responsibility = update_setup();//this booting the IOP

    damit hällt AudioOutputStream die update_responsibility
    fillbuffer feuert ab jetzt AudioStream::update_all();

    und hier geht es nicht weiter '

    static void update_all(void)
        {
                //printf("DEBUG: update_all check! audioSemaID ist: %d (Adresse: %p)\n", audioSemaID, (void*)&audioSemaID);
            if(audioSemaID == -1 )return;
            SignalSema(audioSemaID);
        }
    

    if(audioSemaID == -1 ) wird nie true bzw false im dem Fall.
    initialize_memory wird aufgerufen wenn auch etwas später
    weil ich sehe ja diese Ausgabe:
    ee_sema_t audioSema;
    memset(&audioSema, 0, sizeof(audioSema));
    audioSema.init_count = 0;
    audioSema.max_count = 3;
    audioSema.option = 0;
    audioSemaID = CreateSema(&audioSema);
    printf("DEBUG: Frisch erstellt! audioSemaID ist jetzt: %d (Adresse: %p)\n", audioSemaID, (void*)&audioSemaID);
    fflush(stdout);

    Die einzige logische Idee, die ich habe ist, es gibt zwei instanzen von audioSemaID
    Leider kann ich die Speicheradressen nicht ausgeben
    soballt printf in static void update_all(void) feuert wird das print in
    initialize_memory verschluckt.

    Das Passiert weil die Ausgaben über den IOP laufen und wenn man da in eienr Schleife zu oft Ausgaben macht, geht das ein oder ander unter.
    Vorallem wenn man mit zwei Threads auf dem EE ausgaben machnen will. Das ist ein Nerviges Problem bei der Playstation 2.

    Ich habe noch einen älteren Code wo ich noch keine Bildausgabe habe, da funktioert das audio. Das erklärt aber nicht weshalb audioSemaID nie > -1 wird.


Anmelden zum Antworten