Are you talking about streaming play?Just a random idea, make sure you're loading a small OGG file because you're loading it all into memory at once.
Should I try it?
Are you talking about streaming play?Just a random idea, make sure you're loading a small OGG file because you're loading it all into memory at once.
Also make sure you run the dsp dump utility on hardware. You will need to copy the file from hardware to the sd card folder for Citra - make sure you use the same path.Just a random idea, make sure you're loading a small OGG file because you're loading it all into memory at once.
here is some code that will work with small ogg files. the main issue was that waveBuf was going out of scope - it needs to be valid the entire time it is being used. also, you need to set the channel volume or you wont hear anything.I tried it on 3DS but it ended with an error "an exception occurred".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <tremor/ivorbiscodec.h>
#include <tremor/ivorbisfile.h>
#include <3ds.h>
#define MUSIC_CHANNEL 1
#define BUFFER_SIZE 4096
#define STACKSIZE (4 * 1024)
typedef struct {
float rate;
u32 channels;
u32 encoding;
u32 nsamples;
u32 size;
u8* data;
bool loop;
int audiochannel;
float mix[12];
ndspInterpType interp;
OggVorbis_File ovf;
} Music;
Music music;
ndspWaveBuf waveBuf;
void load() {
memset(&music, 0, sizeof(music));
music.mix[0] = 1.0f;
music.mix[1] = 1.0f;
FILE * file = fopen("example.ogg", "rb");
if (file == 0) {
printf("no file\n");
while (1);
}
if (ov_open(file, &music.ovf, NULL, 0) < 0) {
printf("ogg vorbis file error\n");
while (1);
}
vorbis_info * vorbisInfo = ov_info(&music.ovf, -1);
if (vorbisInfo == NULL) {
printf("could not retrieve ogg audio stream information\n");
while (1);
}
music.rate = (float)vorbisInfo->rate;
music.channels = (u32)vorbisInfo->channels;
music.encoding = NDSP_ENCODING_PCM16;
music.nsamples = (u32)ov_pcm_total(&music.ovf, -1);
music.size = music.nsamples * music.channels * 2;
music.audiochannel = 0;
music.interp = NDSP_INTERP_NONE;
music.loop = false;
if (linearSpaceFree() < music.size) {
printf("not enough linear memory available %ld\n", music.size);
}
music.data = (u8 *)linearAlloc(music.size);
if (music.data == 0) {
printf("null\n");
while (1);
}
printf("rate:%f\n", music.rate);
printf("channels:%ld\n", music.channels);
printf("encoding:%ld\n", music.encoding);
printf("nsamples:%ld\n", music.nsamples);
printf("size:%ld\n", music.size);
int offset = 0;
int eof = 0;
int currentSection;
while (!eof) {
long ret = ov_read(&music.ovf, &music.data[offset], 4096, ¤tSection);
if (ret == 0) {
eof = 1;
}
else if (ret < 0) {
ov_clear(&music.ovf);
linearFree(music.data);
printf("error in the ogg vorbis stream\n");
while (1);
}
else {
offset += ret;
}
//printf("%ld %d\n", ret, currentSection);
}
printf("done\n");
//linearFree(&music.ovf);
ov_clear(&music.ovf);
fclose(file);
}
int play() {
if (music.audiochannel == -1) {
printf("No available audio channel\n");
return -1;
}
printf("music: %p\n,", music.data);
ndspChnWaveBufClear(music.audiochannel);
ndspChnReset(music.audiochannel);
ndspChnInitParams(music.audiochannel);
ndspChnSetMix(music.audiochannel, music.mix);
ndspChnSetInterp(music.audiochannel, music.interp);
ndspChnSetRate(music.audiochannel, music.rate);
ndspChnSetFormat(music.audiochannel, NDSP_CHANNELS(music.channels) | NDSP_ENCODING(music.encoding));
memset(&waveBuf, 0, sizeof(ndspWaveBuf));
waveBuf.data_vaddr = music.data;
waveBuf.nsamples = music.nsamples;
waveBuf.looping = music.loop;
waveBuf.status = NDSP_WBUF_FREE;
DSP_FlushDataCache(music.data, music.size);
ndspChnWaveBufAdd(music.audiochannel, &waveBuf);
// while (1);
return 0;
}
int main(int argc, char **argv) {
gfxInitDefault();
consoleInit(GFX_TOP, 0);
ndspInit();
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
ndspSetOutputCount(1);
load();
play();
while (aptMainLoop()) {
hidScanInput();
u32 keys = hidKeysDown();
if (keys & KEY_START)
break;
gfxFlushBuffers();
gfxSwapBuffers();
gspWaitForVBlank();
}
ndspChnWaveBufClear(music.audiochannel);
ndspExit();
gfxExit();
return 0;
}
I'm really thankful to you! I will refer to your code.here is some code that will work with small ogg files. the main issue was that waveBuf was going out of scope - it needs to be valid the entire time it is being used. also, you need to set the channel volume or you wont hear anything.
Code:#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <tremor/ivorbiscodec.h> #include <tremor/ivorbisfile.h> #include <3ds.h> #define MUSIC_CHANNEL 1 #define BUFFER_SIZE 4096 #define STACKSIZE (4 * 1024) typedef struct { float rate; u32 channels; u32 encoding; u32 nsamples; u32 size; u8* data; bool loop; int audiochannel; float mix[12]; ndspInterpType interp; OggVorbis_File ovf; } Music; Music music; ndspWaveBuf waveBuf; void load() { memset(&music, 0, sizeof(music)); music.mix[0] = 1.0f; music.mix[1] = 1.0f; FILE * file = fopen("example.ogg", "rb"); if (file == 0) { printf("no file\n"); while (1); } if (ov_open(file, &music.ovf, NULL, 0) < 0) { printf("ogg vorbis file error\n"); while (1); } vorbis_info * vorbisInfo = ov_info(&music.ovf, -1); if (vorbisInfo == NULL) { printf("could not retrieve ogg audio stream information\n"); while (1); } music.rate = (float)vorbisInfo->rate; music.channels = (u32)vorbisInfo->channels; music.encoding = NDSP_ENCODING_PCM16; music.nsamples = (u32)ov_pcm_total(&music.ovf, -1); music.size = music.nsamples * music.channels * 2; music.audiochannel = 0; music.interp = NDSP_INTERP_NONE; music.loop = false; if (linearSpaceFree() < music.size) { printf("not enough linear memory available %ld\n", music.size); } music.data = (u8 *)linearAlloc(music.size); if (music.data == 0) { printf("null\n"); while (1); } printf("rate:%f\n", music.rate); printf("channels:%ld\n", music.channels); printf("encoding:%ld\n", music.encoding); printf("nsamples:%ld\n", music.nsamples); printf("size:%ld\n", music.size); int offset = 0; int eof = 0; int currentSection; while (!eof) { long ret = ov_read(&music.ovf, &music.data[offset], 4096, ¤tSection); if (ret == 0) { eof = 1; } else if (ret < 0) { ov_clear(&music.ovf); linearFree(music.data); printf("error in the ogg vorbis stream\n"); while (1); } else { offset += ret; } //printf("%ld %d\n", ret, currentSection); } printf("done\n"); //linearFree(&music.ovf); ov_clear(&music.ovf); fclose(file); } int play() { if (music.audiochannel == -1) { printf("No available audio channel\n"); return -1; } printf("music: %p\n,", music.data); ndspChnWaveBufClear(music.audiochannel); ndspChnReset(music.audiochannel); ndspChnInitParams(music.audiochannel); ndspChnSetMix(music.audiochannel, music.mix); ndspChnSetInterp(music.audiochannel, music.interp); ndspChnSetRate(music.audiochannel, music.rate); ndspChnSetFormat(music.audiochannel, NDSP_CHANNELS(music.channels) | NDSP_ENCODING(music.encoding)); memset(&waveBuf, 0, sizeof(ndspWaveBuf)); waveBuf.data_vaddr = music.data; waveBuf.nsamples = music.nsamples; waveBuf.looping = music.loop; waveBuf.status = NDSP_WBUF_FREE; DSP_FlushDataCache(music.data, music.size); ndspChnWaveBufAdd(music.audiochannel, &waveBuf); // while (1); return 0; } int main(int argc, char **argv) { gfxInitDefault(); consoleInit(GFX_TOP, 0); ndspInit(); ndspSetOutputMode(NDSP_OUTPUT_STEREO); ndspSetOutputCount(1); load(); play(); while (aptMainLoop()) { hidScanInput(); u32 keys = hidKeysDown(); if (keys & KEY_START) break; gfxFlushBuffers(); gfxSwapBuffers(); gspWaitForVBlank(); } ndspChnWaveBufClear(music.audiochannel); ndspExit(); gfxExit(); return 0; }
Pretty sure not doing that will leave resources in memory which is bad.Can I just call exit(0) to exit my CIA homebrew, or do I actually have to clean up everything? (sdmcExit(), fsExit(), romfsExit(), etc.)
You need to exit everything you initialize yourself.Pretty sure not doing that will leave resources in memory which is bad.
No, the system releases the entire memory regions used by malloc and linearAlloc back to the system when your program ends.Do I also need to free any memory allocated with malloc, or can the 3ds free it itself after the program is closed?
No, the system releases the entire memory regions used by malloc and linearAlloc back to the system when your program ends.
You could look at the source for FBI and see how it does it.How can I search for all instaled titles and store their title IDs in a list?
I'm playing and learning with the DevKit's examples, but didn't find anything related.
Help
That's what I'm doing, I'm starting with 3DSident's "Installed title count", to have an idea of how it works first.You could look at the source for FBI and see how it does it.
https://github.com/Steveice10/FBI/blob/master/source/ui/section/task/listtitles.cThat's what I'm doing, I'm starting with 3DSident's "Installed title count", to have an idea of how it works first.
It's really the hard way, I don't know what they're doing, I'm just trying to follow along haha
I can't even find where the method(s) for listing the titles are in fbi source.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <tremor/ivorbiscodec.h>
#include <tremor/ivorbisfile.h>
#include <3ds.h>
#define BUFF_SIZE 8 * 4096
typedef struct {
float rate;
u32 channels;
u32 encoding;
u32 nsamples;
u32 size;
char* data1;
char* data2;
bool loop;
int audiochannel;
float mix[12];
ndspInterpType interp;
OggVorbis_File ovf;
} Music;
Music music;
ndspWaveBuf waveBuf[2];
uint64_t fillVorbisBuffer(OggVorbis_File ovf, char* buffer) {
uint64_t samplesRead = 0;
int samplesToRead = BUFF_SIZE;
while (samplesToRead > 0) {
static int current_section;
int samplesJustRead =
ov_read(&ovf,
buffer,
samplesToRead > 4096 ? 4096 : samplesToRead,
¤t_section);
if (samplesJustRead < 0)
return samplesJustRead;
else if (samplesJustRead == 0){
break;
}
samplesRead += samplesJustRead;
samplesToRead -= samplesJustRead;
buffer += samplesJustRead;
}
return samplesRead / sizeof(int16_t);
}
int load() {
memset(&music, 0, sizeof(music));
music.mix[0] = 1.0f;
music.mix[1] = 1.0f;
FILE * file = fopen("example.ogg", "rb");
if (file == 0) {
printf("no file\n");
while (1);
}
if (ov_open(file, &music.ovf, NULL, 0) < 0) {
printf("ogg vorbis file error\n");
while (1);
}
vorbis_info * vorbisInfo = ov_info(&music.ovf, -1);
if (vorbisInfo == NULL) {
printf("could not retrieve ogg audio stream information\n");
while (1);
}
music.rate = (float)vorbisInfo->rate;
music.channels = (u32)vorbisInfo->channels;
music.encoding = NDSP_ENCODING_PCM16;
music.nsamples = (u32)ov_pcm_total(&music.ovf, -1);
music.size = music.nsamples * music.channels * 2;
music.audiochannel = 0;
music.interp = NDSP_INTERP_NONE;
music.loop = false;
if (linearSpaceFree() < music.size) {
printf("not enough linear memory available %ld\n", music.size);
}
music.data1 = (char *)linearAlloc(BUFF_SIZE * sizeof(int16_t));
music.data2 = (char *)linearAlloc(BUFF_SIZE * sizeof(int16_t));
printf("rate:%f\n", music.rate);
printf("channels:%ld\n", music.channels);
printf("encoding:%ld\n", music.encoding);
printf("nsamples:%ld\n", music.nsamples);
printf("size:%ld\n", music.size);
//fclose(file);
if (music.audiochannel == -1) {
printf("No available audio channel\n");
return -1;
}
ndspChnWaveBufClear(music.audiochannel);
ndspChnReset(music.audiochannel);
ndspChnInitParams(music.audiochannel);
ndspChnSetMix(music.audiochannel, music.mix);
ndspChnSetInterp(music.audiochannel, music.interp);
ndspChnSetRate(music.audiochannel, music.rate);
ndspChnSetFormat(music.audiochannel, NDSP_CHANNELS(music.channels) | NDSP_ENCODING(music.encoding));
memset(&waveBuf, 0, sizeof(ndspWaveBuf));
waveBuf[0].data_vaddr = &music.data1[0];
waveBuf[0].nsamples = fillVorbisBuffer(music.ovf, &music.data1[0]) / music.channels;
waveBuf[0].looping = music.loop;
waveBuf[1].data_vaddr = &music.data2[0];
waveBuf[1].nsamples = fillVorbisBuffer(music.ovf, &music.data1[0]) / music.channels;
waveBuf[1].looping = music.loop;
return 0;
}
int main(int argc, char **argv) {
gfxInitDefault();
consoleInit(GFX_TOP, 0);
ndspInit();
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
ndspSetOutputCount(1);
load();
ndspChnWaveBufAdd(0, &waveBuf[0]);
ndspChnWaveBufAdd(0, &waveBuf[1]);
while (aptMainLoop()) {
hidScanInput();
u32 keys = hidKeysDown();
if (keys & KEY_START)
break;
if (waveBuf[0].status == NDSP_WBUF_DONE){
size_t read = fillVorbisBuffer(music.ovf, &music.data1[0]);
if (read <= 0){
continue;
}
else if (read < BUFF_SIZE)
waveBuf[0].nsamples = read / music.channels;
ndspChnWaveBufAdd(music.audiochannel, &waveBuf[0]);
}
if (waveBuf[1].status == NDSP_WBUF_DONE){
size_t read = fillVorbisBuffer(music.ovf, &music.data2[0]);
if (read <= 0){
continue;
}
else if (read < BUFF_SIZE)
waveBuf[1].nsamples = read / music.channels;
ndspChnWaveBufAdd(music.audiochannel, &waveBuf[1]);
}
DSP_FlushDataCache(music.data1, BUFF_SIZE * sizeof(int16_t));
DSP_FlushDataCache(music.data2, BUFF_SIZE * sizeof(int16_t));
//printf("%d:%d\n", waveBuf[0].status, waveBuf[1].status);
gfxFlushBuffers();
gfxSwapBuffers();
gspWaitForVBlank();
}
ndspChnWaveBufClear(music.audiochannel);
ndspExit();
gfxExit();
return 0;
}