Add BGM Preview Functionality
Some code adapted from Themely. Thanks to ErmanSayin
This commit is contained in:
2
Makefile
2
Makefile
@@ -65,7 +65,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
|||||||
ASFLAGS := -g $(ARCH)
|
ASFLAGS := -g $(ARCH)
|
||||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
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
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
|||||||
52
include/music.h
Normal file
52
include/music.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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 <tremor/ivorbisfile.h>
|
||||||
|
#include <tremor/ivorbiscodec.h>
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -30,12 +30,14 @@
|
|||||||
#include "splashes.h"
|
#include "splashes.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
#include "music.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "instructions.h"
|
#include "instructions.h"
|
||||||
#include "pp2d/pp2d/pp2d.h"
|
#include "pp2d/pp2d/pp2d.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
|
audio_s * audio;
|
||||||
static bool homebrew = false;
|
static bool homebrew = false;
|
||||||
static bool installed_themes = false;
|
static bool installed_themes = false;
|
||||||
|
|
||||||
@@ -75,6 +77,7 @@ static void init_services(void)
|
|||||||
cfguInit();
|
cfguInit();
|
||||||
ptmuInit();
|
ptmuInit();
|
||||||
acInit();
|
acInit();
|
||||||
|
ndspInit();
|
||||||
APT_GetAppCpuTimeLimit(&old_time_limit);
|
APT_GetAppCpuTimeLimit(&old_time_limit);
|
||||||
APT_SetAppCpuTimeLimit(30);
|
APT_SetAppCpuTimeLimit(30);
|
||||||
httpcInit(0);
|
httpcInit(0);
|
||||||
@@ -95,6 +98,7 @@ static void exit_services(void)
|
|||||||
if (old_time_limit != UINT32_MAX) APT_SetAppCpuTimeLimit(old_time_limit);
|
if (old_time_limit != UINT32_MAX) APT_SetAppCpuTimeLimit(old_time_limit);
|
||||||
httpcExit();
|
httpcExit();
|
||||||
acExit();
|
acExit();
|
||||||
|
ndspExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_install_check(void)
|
static void stop_install_check(void)
|
||||||
@@ -362,7 +366,10 @@ int main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(qr_mode) take_picture();
|
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 {
|
else {
|
||||||
if(!iconLoadingThread_arg.run_thread)
|
if(!iconLoadingThread_arg.run_thread)
|
||||||
{
|
{
|
||||||
@@ -426,9 +433,16 @@ int main(void)
|
|||||||
{
|
{
|
||||||
toggle_preview:
|
toggle_preview:
|
||||||
if(!preview_mode)
|
if(!preview_mode)
|
||||||
|
{
|
||||||
preview_mode = load_preview(*current_list, &preview_offset);
|
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
|
else
|
||||||
|
{
|
||||||
preview_mode = false;
|
preview_mode = false;
|
||||||
|
audio->stop = true;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if(preview_mode && kDown & (KEY_B | KEY_TOUCH))
|
else if(preview_mode && kDown & (KEY_B | KEY_TOUCH))
|
||||||
|
|||||||
121
source/music.c
Normal file
121
source/music.c
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,9 @@ void printu(u16 *input)
|
|||||||
ssize_t buf_len = in_len + 1; // Plus 1 for proper null termination
|
ssize_t buf_len = in_len + 1; // Plus 1 for proper null termination
|
||||||
wchar_t *buf = calloc(buf_len, sizeof(wchar_t));
|
wchar_t *buf = calloc(buf_len, sizeof(wchar_t));
|
||||||
utf16_to_utf32((u32*)buf, input, buf_len);
|
utf16_to_utf32((u32*)buf, input, buf_len);
|
||||||
printf("%ls\n", buf);
|
char cbuf[0x106];
|
||||||
|
sprintf(cbuf, "%ls\n", buf);
|
||||||
|
DEBUG(cbuf);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user