CSND - playing sound data built into the binary

Discussion in '3DS - Homebrew Development and Emulators' started by mashers, Dec 17, 2015.

  1. mashers
    OP

    mashers Stubborn ape

    Member
    3,837
    5,155
    Jun 10, 2015
    Kongo Jungle
    The sound playing code in Gridlauncher loads a WAV file from the SD card and plays it. I now want to play sound data which has been included in the 3dsx binary itself but I can't get it working.

    My WAV file already has a .bin extension and it plays in Gridlauncher as a theme sound loaded from SD. I place this in the data directory, included its header, and tried to call cSndPlaySound() passing this buffer as the data parameter. The problem is that no sound actually plays.

    I'm wondering whether the compiler is doing something to the .bin (really .wav) file when it links it with the binary rather than including it as-is. Does anyone have any ideas about this?

    Thanks in advance!
     
  2. elhobbs

    elhobbs GBAtemp Advanced Fan

    Member
    806
    296
    Jul 28, 2008
    United States
    The sound data must be in the linear address range. You will need to copy the data there and pass that address to csnd instead.
     
  3. mashers
    OP

    mashers Stubborn ape

    Member
    3,837
    5,155
    Jun 10, 2015
    Kongo Jungle
    Thanks buddy! So would that involve mallocing some memory at runtime and then memcpying from the data included in the binary to the malloced space? (in the gym so can't experiment...)
     
  4. elhobbs

    elhobbs GBAtemp Advanced Fan

    Member
    806
    296
    Jul 28, 2008
    United States
    linearAlloc rather than malloc, but essentially yes.
     
  5. Pikasack

    Pikasack What is a title

    Member
    633
    203
    Apr 27, 2015
    Canada
    Awww man, nerd talk i can't be a part of... Which language should i start learning guys....
     
  6. BurningDesire

    BurningDesire GBAtemp Psycho!

    Member
    4,962
    5,811
    Jan 27, 2015
    United States
    Behind a screen reading news
    I would suggest C IMO since I guess it is more commonly used through the homebrew section. However, if you want to learn a noob friendly language I would start with @Rinnegatamante's lua for 3ds
     
  7. mashers
    OP

    mashers Stubborn ape

    Member
    3,837
    5,155
    Jun 10, 2015
    Kongo Jungle
    Thanks mate. In the end, it actually worked using the data included in the binary if I cast it explicitly as (void*). I didn't need to linearAlloc and memcpy in the end! Thank you anyway for your suggestions :)
     
  8. mashers
    OP

    mashers Stubborn ape

    Member
    3,837
    5,155
    Jun 10, 2015
    Kongo Jungle
    @elhobbs
    Actually, I have now switched to using your linearAlloc method. This works better as I can leave off the first 48 bytes to remove the playback pop. Here's the final solution:

    Code:
    void * loadSound(void * source, int size) {
        size -= 0x48;
        void * sound = linearAlloc(size);
        memcpy(sound, source+0x48, size);
        return sound;
    }
    
    void audioStop(int channel) {
        csndExecCmds(true);
        CSND_SetPlayState(channel, 0);
        csndExecCmds(true);
    }
    
    
    
    void audioPlay(void * audio, int channel, u32 size) {
        audioStop(channel);
        csndPlaySound(channel, SOUND_FORMAT_16BIT, 44100, 1, 0, audio, audio, size);
    }
    
    int main() {
        // ...
    
        //pipe_bin is the audio data included in the 3dsx
        //pipe_bin_size is the size of the data
        void * pipeSound = loadSound((void*)pipe_bin, pipe_bin_size);
    
        // ...
    
        // Yeah I should probably put the data and size into a struct to make this cleaner, but it's only a one off...
        audioPlay(pipeSound, 8, pipe_bin_size);
    
        // ...
    
        linearFree(pipeSound);
    }
    
     
  9. BurningDesire

    BurningDesire GBAtemp Psycho!

    Member
    4,962
    5,811
    Jan 27, 2015
    United States
    Behind a screen reading news
    Why does coding look so simple then when you do it your in hell :cry:
     
  10. mashers
    OP

    mashers Stubborn ape

    Member
    3,837
    5,155
    Jun 10, 2015
    Kongo Jungle
    Coding IS simple. It's the API that's hard. Once you know which API calls to make, working out the actual code is easy ;)
     
  11. BurningDesire

    BurningDesire GBAtemp Psycho!

    Member
    4,962
    5,811
    Jan 27, 2015
    United States
    Behind a screen reading news
    My main problem is learning what do to with the .h files and how to implement voids and how to make the code prettier. I can do stuff it just looks ugly as fuck. I started porting qben to mac with Glew and glfw for a learning experience. I don't understand .h files ;( or anything that isn't in the main haha
     
  12. MasterFeizz

    MasterFeizz GBAtemp Advanced Fan

    Member
    888
    827
    Oct 15, 2015
    United States
    Isn't qBen's code already platform independent?
     
  13. BurningDesire

    BurningDesire GBAtemp Psycho!

    Member
    4,962
    5,811
    Jan 27, 2015
    United States
    Behind a screen reading news
    idk. I wouldn't call it a port i guess as much as I would a remake. :D
     
  14. MasterFeizz

    MasterFeizz GBAtemp Advanced Fan

    Member
    888
    827
    Oct 15, 2015
    United States
    You only have to change the makefile to build it for mac
     
  15. BurningDesire

    BurningDesire GBAtemp Psycho!

    Member
    4,962
    5,811
    Jan 27, 2015
    United States
    Behind a screen reading news
    Oh. I want to challenge my self anyways.
     
  16. mashers
    OP

    mashers Stubborn ape

    Member
    3,837
    5,155
    Jun 10, 2015
    Kongo Jungle
    The header (.h) file is like an index. It tells other implementation (.c, .cpp, ...) files what is contained inside the implementation file which does along with the header. So if you define a function within a .c file and want other .c files to be able to access it, you add a definition for the function into its .h file :)
     
    BurningDesire likes this.
  17. MasterFeizz

    MasterFeizz GBAtemp Advanced Fan

    Member
    888
    827
    Oct 15, 2015
    United States
    A void is an empty data type and a void pointer is a generic pointer, so you don't implement voids, you implement functions.
     
    BurningDesire likes this.
  18. mashers
    OP

    mashers Stubborn ape

    Member
    3,837
    5,155
    Jun 10, 2015
    Kongo Jungle
    I think he meant functions when he wrote voids.

    @BurningDesire
    The 'void' before a function declaration means the function doesn't return anything. You can put any other datatype here to specify what type of data the function returns. For example:

    Code:
    void func1() {
        //Do something
        //Return nothing
    }
    
    int func2() {
        int r = 42;
        return r;
    }
    
    char * func3() {
        char * r = "Hello world";
        return r;
    }
    
    bool func4() {
        bool r = true;
        return r;
    }
    
     
    BurningDesire likes this.
  19. TheCruel

    TheCruel Developer

    Banned
    1,351
    2,884
    Dec 6, 2013
    United States
    If you parse the 3dsx header, you can find the RomFS offset, then you can play a sort of banner audio provided by the 3dsx files. Can just tell devs to use some sort of standard filename like "banner.wav" and you can fallback on a "banner.wav" in the game dir if there is no RomFS present. Just an idea, since you're implementing audio.
     
  20. mashers
    OP

    mashers Stubborn ape

    Member
    3,837
    5,155
    Jun 10, 2015
    Kongo Jungle
    Thanks, but that's not really relevant to the situation I'm in. I'm just including audio files in the 3dsx to be played by the software so they don't have to be bundled as external files.