Issue with streaming music and using SDFileSystem

It seems that streaming music and saving/loading data using SDFilesystem interfere with each other:
The music starts streaming but as soon as something is loaded/saved to the SD card the loading of the music file stops and the part that already has been loaded is repeated…

Test program (basicly this is the SDCardFileIO with 2 extra lines of code to stream music):
bitburnr.snd
main.cpp

#pragma GCC diagnostic ignored "-Wwrite-strings"

#include "Pokitto.h"
#ifdef POK_SIM
#include "io.h"
#else
#include "SDFileSystem.h"
#endif

Pokitto::Core mygame;

FILE *filep = NULL;
const int32_t blockSize = 1000;
const int32_t totalFileSize = 200000;
char bufferOrg[blockSize];
char buffer[blockSize];
int32_t len = 0;
//uint32_t start_us = 0;
//uint32_t stop_us = 0;
uint32_t start_ms = 0;
uint32_t stop_ms = 0;

int main () {
    mygame.sound.playMusicStream("music/bitburnr.SND");
    mygame.begin();
    mygame.sound.playMusicStream();
    mygame.display.persistence = true;

    mygame.display.println("Testing...");

    while (mygame.isRunning()) {
        if (mygame.update()) {
            mygame.update();
            break;
         }
    }

    // *** Test SDFileSystem

    mygame.display.println("*SDFS*");

    #ifdef POK_SIM
    char* filePathAndNamePFFS = "sdtest/200KB.txt";
    char* filePathAndNameSDFS = "sdtest/200KB.txt";
    char* dirNameSDFS = "sdtest";

    mkdir(dirNameSDFS);
    #else
    SDFileSystem sd(/*MOSI*/P0_9, /*MISO*/P0_8, /*SCK*/P0_6, /*CS*/P0_7, /*Mountpoint*/"sd");
    char* filePathAndNamePFFS = "sdtest/200KB.txt";
    char* filePathAndNameSDFS = "/sd/sdtest/200KB.txt";
    char* dirNameSDFS = "/sd/sdtest";

    mkdir(dirNameSDFS, 0777);
    #endif

    // Write to a directory in SD.
    filep = fopen(filePathAndNameSDFS, "wb");
    if(filep == NULL) {
        mygame.display.println("Could not open file for write!"); goto draw_loop;
    }

    // Init buffer
    for(int32_t i=0;i<blockSize; i++) bufferOrg[i] = (char)i;

    // Create 1MB file
    start_ms = mygame.getTime();
    for(int32_t i=0; i<totalFileSize; i+=blockSize) {
        // read the block into the buffer:
        len = fwrite (bufferOrg , sizeof(char), blockSize, filep);
        if( len != blockSize ) {mygame.display.println("Could not write!"); goto draw_loop;}
   }
    fclose(filep);
    stop_ms = mygame.getTime();
    mygame.display.print("Wrote:");
    if( stop_ms-start_ms > 0 )
        mygame.display.print( totalFileSize/(stop_ms-start_ms) ); // b/ms == kb/s
    else
        mygame.display.print( 0 ); // b/ms == kb/s
    mygame.display.println(" kb/s");

    // Open file
    filep = NULL;
    filep = fopen(filePathAndNameSDFS, "rb");
     if(filep == NULL) {
        mygame.display.println("Could not open file for read"); goto draw_loop;
    }

    // Read from SD
    start_ms = mygame.getTime();

    for(int32_t i=0;; i+=blockSize) {
        // read the block into the buffer:
        len = fread (buffer, sizeof(char), blockSize, filep);
        if (len != blockSize) break;
    }
    stop_ms = mygame.getTime();
    fclose(filep);

    // Check the result
    for(int32_t i=0;i<blockSize; i++)
        if(buffer[i] != bufferOrg[i]) {mygame.display.println("Invalid data!"); goto draw_loop;}

    mygame.display.print("Read:");
    if( stop_ms-start_ms > 0 )
        mygame.display.print( totalFileSize/(stop_ms-start_ms) ); // b/ms == kb/s
    else
        mygame.display.print( 0 ); // b/ms == kb/s
    mygame.display.println(" kb/s");

draw_loop:
    while (mygame.isRunning()) {
        if (mygame.update()) {
         }
    }
}

My_settings.h

#ifndef MY_SETTINGS_H
#define MY_SETTINGS_H

#define PROJ_HIRES 0            //1 = high resolution (220x176) , 0 = low resolution fast mode (110x88)
#define PROJ_ENABLE_SOUND       1       // 0 = all sound functions disabled
#define PROJ_STREAMING_MUSIC    1       // 1 = enable streaming music from SD card
#define PROJ_AUD_FREQ           11025
#define PROJ_STREAM_TO_DAC      1       // 1 use DAC for stream, 0 = use PWM for stream
#define PROJ_GBSOUND            0       // 1 = use Gamebuino-compatible sound interrupt
#define PROJ_ENABLE_SYNTH       0       // 1 = use Rboy-compatible sound interrupt
#define PROJ_USE_PWM            0       // 0 = Use only DAC for output

#endif

What if you stop streaming and restart it after you have done file operations?

I have tried this in my original code:
Just before I load the high scores I put a mygame.sound.pauseMusicStream() and after the loading I put a mygame.sound.playMusicStream();
To me it seems that after reading from a file, the buffer for music streaming is no longer being updated but the playing continues so you keep on hearing the same piece of the song…

I meant that you reload the music file

I have no idea how to do this but I even get the problem if I do the reading from a file before starting the streaming of the music. My original main looks like this:

int main () {

    SDFileSystem sd(/*MOSI*/P0_9, /*MISO*/P0_8,	/*SCK*/P0_6, /*CS*/P0_7, /*Mountpoint*/"sd", NC, SDFileSystem::SWITCH_NONE,	25000000);
    
    std::memset(highScoreTable, 0, sizeof(highScoreTable));
    loadSuccess = loadAllHighScores();
    mygame.sound.playMusicStream("music/bitburnr.SND");
    mygame.begin();
    mygame.sound.playMusicStream(); // without parameters function triggers playback to begin
    mygame.display.setFont(font3x5);
    mygame.display.loadRGBPalette(paletteLinez);

    if (loadSuccess!=0){ //HighScore Table could not be loaded, replace by standard Highscore Table
    for (int i = 0; i < 5; ++i)
	{
		for (int k = 0; k < 3; ++k)
			highScoreTable[i].name[k] = ('B' + i);

        highScoreTable[i].highScore = 5 - i;
    }
    }
  
    while (mygame.isRunning()) {
        if (mygame.update()) {

                switch(gameState){
                    case GameState::TitleScreen: showTitleScreen(); break;
                    case GameState::Menu: showMenu(); break;
                    case GameState::GamePlay: playGame(); break;
                    case GameState::HighScoreTable: showHighScoreTable(highlightIndex); break;
                    case GameState::NewHighScore: showNewHighScore(); break;
                    case GameState::GameOver: showGameOver(); break;
                }
        }
    }
    return 0;
}

The highscores are now loaded before the start of the streaming and before begin(). Now no music is being played…

1 Like

This is easy to solve. As soon as I have a moment to spare I’ll take care of it (add SDFileSystem to the streaming function)

2 Likes

That is basically the same case as in my SDCardFileIO example program: first read wit SDFS and then with PFFS (streaming). Are you calling pokInitSD() before initializing streaming?

1 Like

I did try it with pokInitSD() but this doesn’t make a difference because when initialising streaming, pokInitSD() is called automatically via int Sound::playMusicStream(char* filename, uint8_t options).
However when you said this is basically the same case as in your SDCardFileIO example program, I remembered that I had problems with 1 SD card so I tried my other SD card and for this card it works… Very strange…
However it does not work perfectly, as for this second SD card, every music that is streamed has a ticking sound…
So to summarize:

  • I have 1 micro SD card (2Gb), which I obtained from @jonne, that does not like the combination of both filesystems (so whenever SDFilesystem is being used, PFFS does not work)
  • I have another one which is a micro SD HC card (16 Gb) which does work for both filesystems but which does not stream the music perfectly…
1 Like

Rim having an issue with my video streaming, basically the buttons don’t work at all. Polling the pins works, I think it’s just the interrup method. Could this be related?

Link to code please

Did you check this thread?

2 Likes

That did the trick. It seems it works fine if
SDFileSystem sd(/MOSI/P0_9, /MISO/P0_8, /SCK/P0_6, /CS/P0_7, /Mountpoint/“sd”);
is placed in the main() function.

No idea about the music streaming though.

1 Like