diff --git a/Makefile b/Makefile
index 51f31ad..60c5239 100644
--- a/Makefile
+++ b/Makefile
@@ -65,7 +65,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
-LIBS := -larchive -ljansson -lcitro3d -lctrud -lm -lz
+LIBS := -lvorbisidec -logg -larchive -ljansson -lcitro3d -lctrud -lm -lz
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
diff --git a/include/music.h b/include/music.h
new file mode 100644
index 0000000..077bbf7
--- /dev/null
+++ b/include/music.h
@@ -0,0 +1,52 @@
+/*
+* This file is part of Anemone3DS
+* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+*
+* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
+* * Requiring preservation of specified reasonable legal notices or
+* author attributions in that material or in the Appropriate Legal
+* Notices displayed by works containing it.
+* * Prohibiting misrepresentation of the origin of that material,
+* or requiring that modified versions of such material be marked in
+* reasonable ways as different from the original version.
+*/
+
+#ifndef MUSIC_H
+#define MUSIC_H
+
+#include "common.h"
+#include "fs.h"
+#include "unicode.h"
+
+#include
+#include
+
+#define BUF_TO_READ 40960 // How much data should be buffered at a time
+
+typedef struct {
+ char *filename;
+ OggVorbis_File vf;
+ ndspWaveBuf wave_buf[2];
+ float mix[12];
+ u8 buf_pos;
+ long data_read;
+ volatile bool stop;
+} audio_s;
+
+Result load_audio(u16 *, audio_s *);
+Result play_audio(audio_s *);
+
+#endif
\ No newline at end of file
diff --git a/source/main.c b/source/main.c
index 53283e3..3bc3327 100644
--- a/source/main.c
+++ b/source/main.c
@@ -30,12 +30,14 @@
#include "splashes.h"
#include "draw.h"
#include "camera.h"
+#include "music.h"
#include "remote.h"
#include "instructions.h"
#include "pp2d/pp2d/pp2d.h"
#include
bool quit = false;
+audio_s * audio;
static bool homebrew = false;
static bool installed_themes = false;
@@ -75,6 +77,7 @@ static void init_services(void)
cfguInit();
ptmuInit();
acInit();
+ ndspInit();
APT_GetAppCpuTimeLimit(&old_time_limit);
APT_SetAppCpuTimeLimit(30);
httpcInit(0);
@@ -95,6 +98,7 @@ static void exit_services(void)
if (old_time_limit != UINT32_MAX) APT_SetAppCpuTimeLimit(old_time_limit);
httpcExit();
acExit();
+ ndspExit();
}
static void stop_install_check(void)
@@ -362,7 +366,10 @@ int main(void)
}
if(qr_mode) take_picture();
- else if(preview_mode) draw_preview(TEXTURE_PREVIEW, preview_offset);
+ else if(preview_mode)
+ {
+ draw_preview(TEXTURE_PREVIEW, preview_offset);
+ }
else {
if(!iconLoadingThread_arg.run_thread)
{
@@ -426,9 +433,16 @@ int main(void)
{
toggle_preview:
if(!preview_mode)
+ {
preview_mode = load_preview(*current_list, &preview_offset);
+ audio = calloc(sizeof(audio_s), 1);
+ load_audio(current_list->entries[current_list->selected_entry].path, audio);
+ }
else
+ {
preview_mode = false;
+ audio->stop = true;
+ }
continue;
}
else if(preview_mode && kDown & (KEY_B | KEY_TOUCH))
diff --git a/source/music.c b/source/music.c
new file mode 100644
index 0000000..2c92e1a
--- /dev/null
+++ b/source/music.c
@@ -0,0 +1,121 @@
+/*
+* This file is part of Anemone3DS
+* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+*
+* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
+* * Requiring preservation of specified reasonable legal notices or
+* author attributions in that material or in the Appropriate Legal
+* Notices displayed by works containing it.
+* * Prohibiting misrepresentation of the origin of that material,
+* or requiring that modified versions of such material be marked in
+* reasonable ways as different from the original version.
+*/
+
+#include "music.h"
+
+// Play a given audio struct
+Result play_audio(audio_s *audio)
+{
+ long size = audio->wave_buf[audio->buf_pos].nsamples * 4 - audio->data_read;
+ char size_info[50] = {0};
+ sprintf(size_info, "Audio Size: %ld\n", size);
+ DEBUG(size_info);
+ if (audio->wave_buf[audio->buf_pos].status == NDSP_WBUF_DONE) // only run if the current selected buffer has already finished playing
+ {
+ size_t read = ov_read(&audio->vf, (char*)audio->wave_buf[audio->buf_pos].data_vaddr + audio->data_read, size, NULL); // read 1 vorbis packet into wave buffer
+
+ if (read <= 0) // EoF or error
+ {
+ ov_clear(&audio->vf);
+ if (read == 0) // EoF
+ {
+ ov_open(fopen(audio->filename, "rb"), &audio->vf, NULL, 0); // Reopen file. Don't need to reinit channel stuff since it's all the same as before
+ } else // Error :(
+ {
+ char error[100] = {0};
+ sprintf(error, "Vorbis play error: %d\n", read);
+ DEBUG(error);
+ ndspChnReset(0);
+ return MAKERESULT(RL_FATAL, RS_INVALIDARG, RM_APPLICATION, RD_NO_DATA);
+ }
+ } else
+ {
+ audio->data_read += read;
+ if (read == size) {
+ audio->data_read = 0;
+ ndspChnWaveBufAdd(0, &audio->wave_buf[audio->buf_pos]); // Add buffer to ndsp
+ audio->buf_pos = 1 - audio->buf_pos; // switch to other buffer to load and prepare it while the current one is playing
+ }
+ }
+ }
+ return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_APPLICATION, RD_SUCCESS);
+}
+
+void thread_audio(void* data) {
+ audio_s *audio = (audio_s*)data;
+ DEBUG(audio->filename);
+ while(!audio->stop) {
+ play_audio(audio);
+ }
+ free(audio);
+}
+
+// Initialize the audio struct
+Result load_audio(u16 *entry_path, audio_s *audio)
+{
+ u16 path[0x106] = {0};
+ strucat(path, entry_path);
+ struacat(path, "/bgm.ogg");
+
+ ssize_t len = strulen(path, 0x106);
+ char *cpath = calloc(sizeof(char), len*sizeof(u16));
+ utf16_to_utf8((u8*)cpath, path, len*sizeof(u16));
+ audio->filename = cpath;
+
+ audio->mix[0] = audio->mix[1] = 1.0f; // Determines volume for the 12 (?) different outputs. See http://smealum.github.io/ctrulib/channel_8h.html#a30eb26f1972cc3ec28370263796c0444
+
+ ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
+ ndspChnSetRate(0, 44100);
+ ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16); // Tremor outputs ogg files in 16 bit PCM stereo
+ ndspChnSetMix(0, audio->mix); // See mix comment above
+
+ FILE *file = fopen(cpath, "rb");
+ if(file != NULL)
+ {
+ int e = ov_open(file, &audio->vf, NULL, 0);
+ if (e < 0)
+ {
+ char error[50];
+ sprintf(error, "Vorbis: %d\n", e);
+ DEBUG(error);
+ return MAKERESULT(RL_FATAL, RS_INVALIDARG, RM_APPLICATION, RD_NO_DATA);
+ }
+
+ vorbis_info *vi = ov_info(&audio->vf, -1);
+ ndspChnSetRate(0, vi->rate);// Set sample rate to what's read from the ogg file
+
+ audio->wave_buf[0].nsamples = audio->wave_buf[1].nsamples = vi->rate / 4; // 4 bytes per sample, samples = rate (bytes) / 4
+ audio->wave_buf[0].status = audio->wave_buf[1].status = NDSP_WBUF_DONE; // Used in play to stop from writing to current buffer
+ audio->wave_buf[0].data_vaddr = linearAlloc(BUF_TO_READ); // Most vorbis packets should only be 4 KB at most (?) Possibly dangerous assumption
+ audio->wave_buf[1].data_vaddr = linearAlloc(BUF_TO_READ);
+ DEBUG("Success!");
+ threadCreate(thread_audio, audio, 0x1000, 0x3F, 1, true);
+ return MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_APPLICATION, RD_SUCCESS);
+ } else {
+ DEBUG("File not found!\n");
+ return MAKERESULT(RL_FATAL, RS_NOTFOUND, RM_APPLICATION, RD_NOT_FOUND);
+ }
+}
\ No newline at end of file
diff --git a/source/unicode.c b/source/unicode.c
index d8da99c..cdbe897 100644
--- a/source/unicode.c
+++ b/source/unicode.c
@@ -48,7 +48,9 @@ void printu(u16 *input)
ssize_t buf_len = in_len + 1; // Plus 1 for proper null termination
wchar_t *buf = calloc(buf_len, sizeof(wchar_t));
utf16_to_utf32((u32*)buf, input, buf_len);
- printf("%ls\n", buf);
+ char cbuf[0x106];
+ sprintf(cbuf, "%ls\n", buf);
+ DEBUG(cbuf);
free(buf);
}