2017-12-02 16:09:38 +01:00
/*
* This file is part of Anemone3DS
2020-12-24 23:38:58 +00:00
* Copyright ( C ) 2016 - 2020 Contributors in CONTRIBUTORS . md
2017-12-02 16:09:38 +01:00
*
* 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 "loading.h"
# include "fs.h"
# include "unicode.h"
2018-05-10 07:40:28 -04:00
# include "music.h"
2017-12-07 16:46:53 +01:00
# include "draw.h"
2024-04-24 20:32:54 +02:00
# include "conversion.h"
2024-05-12 14:24:43 -04:00
# include "ui_strings.h"
2017-12-02 16:09:38 +01:00
2018-07-22 21:22:23 +03:00
# include <png.h>
2024-05-10 23:43:47 +02:00
void copy_texture_data ( C3D_Tex * texture , const u16 * src , const Entry_Icon_s * current_icon )
2017-12-09 04:25:49 +01:00
{
2024-05-10 23:43:47 +02:00
// pointer to rgb565, offset by the number of rows and columns specified by current_icon
// (reminder that this is z order curve storage)
u16 * dest = ( ( u16 * ) texture - > data ) + ( current_icon - > y * texture - > width ) + ( current_icon - > x * 8 ) ;
2018-07-22 21:22:23 +03:00
for ( int j = 0 ; j < 48 ; j + = 8 )
{
2024-05-10 23:43:47 +02:00
memcpy ( dest , src , 48 * 8 * sizeof ( u16 ) ) ;
src + = 48 * 8 ;
dest + = texture - > width * 8 ;
2018-07-22 21:22:23 +03:00
}
2024-05-10 23:43:47 +02:00
GSPGPU_InvalidateDataCache ( texture - > data , texture - > size ) ;
2018-07-22 21:22:23 +03:00
}
2024-05-10 23:43:47 +02:00
void parse_smdh ( Icon_s * icon , Entry_s * entry , const u16 * fallback_name )
2018-07-22 21:22:23 +03:00
{
if ( icon = = NULL )
2017-12-02 16:09:38 +01:00
{
memcpy ( entry - > name , fallback_name , 0x80 ) ;
2024-05-10 23:43:47 +02:00
utf8_to_utf16 ( entry - > desc , ( u8 * ) " No description " , 0x100 ) ;
utf8_to_utf16 ( entry - > author , ( u8 * ) " Unknown author " , 0x80 ) ;
2018-07-22 21:22:23 +03:00
entry - > placeholder_color = C2D_Color32 ( rand ( ) % 255 , rand ( ) % 255 , rand ( ) % 255 , 255 ) ;
2017-12-02 16:09:38 +01:00
return ;
}
2020-12-24 16:58:06 -05:00
2024-05-10 23:43:47 +02:00
memcpy ( entry - > name , icon - > name , 0x40 * sizeof ( u16 ) ) ;
memcpy ( entry - > desc , icon - > desc , 0x80 * sizeof ( u16 ) ) ;
memcpy ( entry - > author , icon - > author , 0x40 * sizeof ( u16 ) ) ;
entry - > placeholder_color = 0 ;
2018-04-04 22:04:45 +02:00
}
2017-12-02 16:09:38 +01:00
2024-05-10 23:43:47 +02:00
static Icon_s * load_entry_icon ( const Entry_s * entry )
2017-12-02 16:09:38 +01:00
{
2024-05-10 23:43:47 +02:00
char * info_buffer = NULL ;
u32 size = load_data ( " /info.smdh " , entry , & info_buffer ) ;
if ( size ! = sizeof ( Icon_s ) )
2017-12-02 16:09:38 +01:00
{
2024-05-10 23:43:47 +02:00
free ( info_buffer ) ;
return NULL ;
2017-12-02 16:09:38 +01:00
}
2024-05-10 23:43:47 +02:00
return ( Icon_s * ) info_buffer ;
2017-12-02 16:09:38 +01:00
}
2017-12-31 05:01:31 +01:00
void load_icons_first ( Entry_List_s * list , bool silent )
2017-12-28 21:30:23 +01:00
{
2017-12-31 05:01:31 +01:00
if ( list = = NULL | | list - > entries = = NULL ) return ;
2017-12-28 21:30:23 +01:00
2017-12-31 05:01:31 +01:00
if ( ! silent )
draw_install ( INSTALL_LOADING_ICONS ) ;
2017-12-28 21:30:23 +01:00
2017-12-31 05:01:31 +01:00
int starti = 0 , endi = 0 ;
2017-12-28 21:30:23 +01:00
2024-05-10 23:43:47 +02:00
if ( list - > entries_count < = list - > entries_loaded * ICONS_OFFSET_AMOUNT )
2017-12-28 21:30:23 +01:00
{
2017-12-31 05:01:31 +01:00
DEBUG ( " small load \n " ) ;
// if the list is one that doesnt need swapping, load everything at once
endi = list - > entries_count ;
2017-12-28 21:30:23 +01:00
}
2017-12-31 05:01:31 +01:00
else
2017-12-28 21:30:23 +01:00
{
2017-12-31 05:01:31 +01:00
DEBUG ( " extended load \n " ) ;
// otherwise, load around to prepare for swapping
2024-05-10 23:43:47 +02:00
starti = list - > scroll - list - > entries_loaded * ICONS_VISIBLE ;
endi = starti + list - > entries_loaded * ICONS_OFFSET_AMOUNT ;
2017-12-28 21:30:23 +01:00
}
2024-05-10 23:43:47 +02:00
for ( int entry_i = starti , icon_i = 0 ; entry_i < endi ; + + entry_i , + + icon_i )
2017-12-28 21:30:23 +01:00
{
2018-05-11 15:53:38 +02:00
if ( ! silent )
2024-05-10 23:43:47 +02:00
draw_loading_bar ( icon_i , endi - starti , INSTALL_LOADING_ICONS ) ;
2018-05-11 15:53:38 +02:00
2024-05-10 23:43:47 +02:00
int offset = entry_i ;
2017-12-31 05:01:31 +01:00
if ( offset < 0 )
offset + = list - > entries_count ;
if ( offset > = list - > entries_count )
offset - = list - > entries_count ;
2017-12-28 21:30:23 +01:00
2024-05-10 23:43:47 +02:00
Entry_s * const current_entry = & list - > entries [ offset ] ;
Icon_s * const smdh = load_entry_icon ( current_entry ) ;
if ( smdh ! = NULL )
{
if ( current_entry - > placeholder_color = = 0 )
parse_smdh ( smdh , current_entry , current_entry - > path + strlen ( list - > loading_path ) ) ;
copy_texture_data ( & list - > icons_texture , smdh - > big_icon , & list - > icons_info [ icon_i ] ) ;
free ( smdh ) ;
}
2017-12-28 21:30:23 +01:00
}
}
2024-05-10 23:43:47 +02:00
static void reverse ( Entry_Icon_s a [ ] , int sz ) {
2017-12-28 21:30:23 +01:00
int i , j ;
2024-05-10 23:43:47 +02:00
Entry_Icon_s tmp ;
2017-12-28 21:30:23 +01:00
for ( i = 0 , j = sz ; i < j ; i + + , j - - ) {
2024-05-10 23:43:47 +02:00
memcpy ( & tmp , & a [ i ] , sizeof ( Entry_Icon_s ) ) ;
memcpy ( & a [ i ] , & a [ j ] , sizeof ( Entry_Icon_s ) ) ;
memcpy ( & a [ j ] , & tmp , sizeof ( Entry_Icon_s ) ) ;
2017-12-28 21:30:23 +01:00
}
}
2024-05-10 23:43:47 +02:00
static void rotate ( Entry_Icon_s array [ ] , int size , int amt ) {
2017-12-28 21:30:23 +01:00
if ( amt < 0 )
amt = size + amt ;
reverse ( array , size - amt - 1 ) ;
reverse ( array + size - amt , amt - 1 ) ;
reverse ( array , size - 1 ) ;
}
2017-12-31 05:01:31 +01:00
void handle_scrolling ( Entry_List_s * list )
{
// Scroll the menu up or down if the selected theme is out of its bounds
//----------------------------------------------------------------
2018-04-01 02:31:46 +02:00
if ( list - > entries_count > list - > entries_loaded )
2017-12-31 05:01:31 +01:00
{
2024-06-12 11:04:52 -04:00
int change = 0 ;
if ( list - > entries_count > list - > entries_loaded * 2 & & list - > previous_scroll < list - > entries_loaded & & list - > selected_entry > = list - > entries_count - list - > entries_loaded )
{
list - > scroll = list - > entries_count - list - > entries_loaded ;
}
else if ( list - > entries_count > list - > entries_loaded * 2 & & list - > selected_entry < list - > entries_loaded & & list - > previous_selected > = list - > entries_count - list - > entries_loaded )
{
list - > scroll = 0 ;
}
else if ( list - > selected_entry = = list - > previous_selected + 1 & & list - > selected_entry = = list - > scroll + list - > entries_loaded )
{
change = 1 ;
}
else if ( list - > selected_entry = = list - > previous_selected - 1 & & list - > selected_entry = = list - > scroll - 1 )
{
change = - 1 ;
}
else if ( list - > selected_entry = = list - > previous_selected + list - > entries_loaded )
{
change = list - > entries_loaded ;
}
else if ( list - > selected_entry = = list - > previous_selected - list - > entries_loaded )
{
change = - list - > entries_loaded ;
}
else if ( list - > selected_entry > = list - > scroll + list - > entries_loaded | | list - > selected_entry < list - > scroll )
2017-12-31 05:01:31 +01:00
{
2024-06-12 11:04:52 -04:00
change = list - > selected_entry - list - > scroll ;
2017-12-31 05:01:31 +01:00
}
2024-06-12 11:04:52 -04:00
list - > scroll + = change ;
if ( list - > scroll < 0 )
list - > scroll = 0 ;
else if ( list - > scroll > list - > entries_count - list - > entries_loaded )
list - > scroll = list - > entries_count - list - > entries_loaded ;
if ( ! change )
list - > previous_selected = list - > selected_entry ;
else
list - > previous_selected + = change ;
2017-12-31 05:01:31 +01:00
}
//----------------------------------------------------------------
}
2018-07-22 21:22:23 +03:00
static bool load_icons ( Entry_List_s * current_list , Handle mutex )
2017-12-28 21:30:23 +01:00
{
if ( current_list = = NULL | | current_list - > entries = = NULL )
2018-07-22 21:22:23 +03:00
return false ;
2017-12-28 21:30:23 +01:00
2017-12-31 05:01:31 +01:00
handle_scrolling ( current_list ) ;
2024-05-10 23:43:47 +02:00
if ( current_list - > entries_count < = current_list - > entries_loaded * ICONS_OFFSET_AMOUNT | | current_list - > previous_scroll = = current_list - > scroll )
2018-07-22 21:22:23 +03:00
return false ; // return if the list is one that doesnt need swapping, or if nothing changed
2017-12-28 21:30:23 +01:00
# define SIGN(x) (x > 0 ? 1 : ((x < 0) ? -1 : 0))
int delta = current_list - > scroll - current_list - > previous_scroll ;
2024-05-10 23:43:47 +02:00
if ( abs ( delta ) > = current_list - > entries_count - current_list - > entries_loaded * ( ICONS_OFFSET_AMOUNT - 1 ) )
2017-12-28 21:30:23 +01:00
delta = - SIGN ( delta ) * ( current_list - > entries_count - abs ( delta ) ) ;
int starti = current_list - > scroll ;
int endi = starti + abs ( delta ) ;
if ( delta < 0 )
{
endi - = abs ( delta ) + 1 ;
starti + = abs ( delta ) - 1 ;
}
int ctr = 0 ;
2024-05-10 23:43:47 +02:00
Entry_s * * const entries = calloc ( abs ( delta ) , sizeof ( Entry_s * ) ) ;
int * const indexes = calloc ( abs ( delta ) , sizeof ( int ) ) ;
2018-07-22 21:22:23 +03:00
bool released = false ;
2017-12-28 21:30:23 +01:00
2024-05-10 23:43:47 +02:00
Entry_Icon_s * const icons = current_list - > icons_info ;
2017-12-28 21:30:23 +01:00
for ( int i = starti ; i ! = endi ; i + + , ctr + + )
{
2018-07-22 21:22:23 +03:00
int index = 0 ;
2017-12-28 21:30:23 +01:00
int offset = i ;
2024-05-10 23:43:47 +02:00
rotate ( icons , ICONS_OFFSET_AMOUNT * current_list - > entries_loaded , - SIGN ( delta ) ) ;
2017-12-28 21:30:23 +01:00
if ( delta > 0 )
{
2024-05-10 23:43:47 +02:00
index = current_list - > entries_loaded * ICONS_OFFSET_AMOUNT - delta + i - starti ;
offset + = current_list - > entries_loaded * ICONS_UNDER - delta ;
2017-12-28 21:30:23 +01:00
}
else
{
2018-07-22 21:22:23 +03:00
index = 0 - delta - 1 + i - starti ;
2024-05-10 23:43:47 +02:00
offset - = current_list - > entries_loaded * ICONS_VISIBLE ;
2017-12-28 21:30:23 +01:00
i - = 2 ; //i-- twice to counter the i++, needed only for this case
}
if ( offset < 0 )
offset + = current_list - > entries_count ;
if ( offset > = current_list - > entries_count )
offset - = current_list - > entries_count ;
entries [ ctr ] = & current_list - > entries [ offset ] ;
2018-07-22 21:22:23 +03:00
indexes [ ctr ] = index ;
2017-12-28 21:30:23 +01:00
}
# undef SIGN
2024-05-10 23:43:47 +02:00
if ( abs ( delta ) < = current_list - > entries_loaded )
2018-04-01 02:31:46 +02:00
{
2018-07-22 21:22:23 +03:00
svcReleaseMutex ( mutex ) ;
released = true ;
}
svcSleepThread ( 1e7 ) ;
starti = 0 ;
endi = abs ( delta ) ;
for ( int i = starti ; i < endi ; i + + )
{
2024-05-10 23:43:47 +02:00
Entry_s * const current_entry = entries [ i ] ;
const int index = indexes [ i ] ;
const Entry_Icon_s * const current_icon = & icons [ index ] ;
2018-07-22 21:22:23 +03:00
2024-05-10 23:43:47 +02:00
Icon_s * const smdh = load_entry_icon ( current_entry ) ;
if ( smdh ! = NULL )
2020-12-24 18:27:48 -05:00
{
2024-05-10 23:43:47 +02:00
if ( current_entry - > placeholder_color = = 0 )
parse_smdh ( smdh , current_entry , current_entry - > path + strlen ( current_list - > loading_path ) ) ;
copy_texture_data ( & current_list - > icons_texture , smdh - > big_icon , current_icon ) ;
free ( smdh ) ;
2020-12-24 18:27:48 -05:00
}
2018-07-22 21:22:23 +03:00
if ( ! released & & i > endi / 2 )
{
svcReleaseMutex ( mutex ) ;
released = true ;
}
2018-04-01 02:31:46 +02:00
}
2017-12-31 05:01:31 +01:00
free ( entries ) ;
2018-07-22 21:22:23 +03:00
free ( indexes ) ;
2017-12-31 05:01:31 +01:00
current_list - > previous_scroll = current_list - > scroll ;
2018-07-22 21:22:23 +03:00
return released ;
2017-12-28 21:30:23 +01:00
}
void load_icons_thread ( void * void_arg )
{
Thread_Arg_s * arg = ( Thread_Arg_s * ) void_arg ;
2018-07-22 21:22:23 +03:00
Handle mutex = * ( Handle * ) arg - > thread_arg [ 1 ] ;
2024-05-10 23:43:47 +02:00
do {
2018-07-22 21:22:23 +03:00
svcWaitSynchronization ( mutex , U64_MAX ) ;
2024-05-10 23:43:47 +02:00
Entry_List_s * const current_list = * ( Entry_List_s * * volatile ) arg - > thread_arg [ 0 ] ;
const bool released = load_icons ( current_list , mutex ) ;
2018-07-22 21:22:23 +03:00
if ( ! released )
svcReleaseMutex ( mutex ) ;
2024-05-10 23:43:47 +02:00
} while ( arg - > run_thread ) ;
2017-12-28 21:30:23 +01:00
}
2017-12-02 16:09:38 +01:00
2024-05-12 14:24:43 -04:00
bool load_preview_from_buffer ( char * row_pointers , u32 size , C2D_Image * preview_image , int * preview_offset , int height )
2018-07-22 21:22:23 +03:00
{
2024-04-24 20:32:54 +02:00
int width = ( uint32_t ) ( ( size / 4 ) / height ) ;
2024-06-04 16:34:20 -04:00
float tex_height = height > 512.0f ? 1024.0f : 512.0f ;
2018-07-22 21:22:23 +03:00
free_preview ( * preview_image ) ;
2024-05-10 23:43:47 +02:00
C3D_Tex * tex = malloc ( sizeof ( C3D_Tex ) ) ;
2018-07-22 21:22:23 +03:00
preview_image - > tex = tex ;
Tex3DS_SubTexture * subt3x = malloc ( sizeof ( Tex3DS_SubTexture ) ) ;
subt3x - > width = width ;
subt3x - > height = height ;
subt3x - > left = 0.0f ;
subt3x - > top = 1.0f ;
subt3x - > right = width / 512.0f ;
2024-06-02 20:51:39 -04:00
subt3x - > bottom = 1.0 - ( height / tex_height ) ;
2018-07-22 21:22:23 +03:00
preview_image - > subtex = subt3x ;
2024-06-02 20:51:39 -04:00
C3D_TexInit ( preview_image - > tex , 512 , tex_height , GPU_RGBA8 ) ;
2018-07-22 21:22:23 +03:00
memset ( preview_image - > tex - > data , 0 , preview_image - > tex - > size ) ;
for ( int j = 0 ; j < height ; j + + ) {
2024-04-24 20:32:54 +02:00
png_bytep row = ( png_bytep ) ( row_pointers + ( width * 4 * j ) ) ;
2018-07-22 21:22:23 +03:00
for ( int i = 0 ; i < width ; i + + ) {
png_bytep px = & ( row [ i * 4 ] ) ;
u32 dst = ( ( ( ( j > > 3 ) * ( 512 > > 3 ) + ( i > > 3 ) ) < < 6 ) + ( ( i & 1 ) | ( ( j & 1 ) < < 1 ) | ( ( i & 2 ) < < 1 ) | ( ( j & 2 ) < < 2 ) | ( ( i & 4 ) < < 2 ) | ( ( j & 4 ) < < 3 ) ) ) * 4 ;
memcpy ( preview_image - > tex - > data + dst , px , sizeof ( u32 ) ) ;
}
}
2024-04-24 20:32:54 +02:00
* preview_offset = ( width - TOP_SCREEN_WIDTH ) / 2 ;
2018-07-22 21:22:23 +03:00
return true ;
}
2017-12-28 21:30:23 +01:00
static u16 previous_path_preview [ 0x106 ] = { 0 } ;
2024-05-10 23:43:47 +02:00
bool load_preview ( const Entry_List_s * list , C2D_Image * preview_image , int * preview_offset )
2017-12-02 16:09:38 +01:00
{
2024-05-10 23:43:47 +02:00
if ( list - > entries = = NULL ) return false ;
2017-12-02 16:09:38 +01:00
2024-05-10 23:43:47 +02:00
const Entry_s * entry = & list - > entries [ list - > selected_entry ] ;
2017-12-02 16:09:38 +01:00
2024-05-10 23:43:47 +02:00
if ( ! memcmp ( & previous_path_preview , & entry - > path , 0x106 * sizeof ( u16 ) ) ) return true ;
2017-12-02 16:09:38 +01:00
2024-05-10 23:43:47 +02:00
char * preview_buffer = NULL ;
u32 size = load_data ( " /preview.png " , entry , & preview_buffer ) ;
2024-05-12 14:24:43 -04:00
u32 height = 480 ;
2017-12-02 16:09:38 +01:00
2024-04-24 20:32:54 +02:00
if ( size )
{
2024-05-12 14:24:43 -04:00
if ( ! ( size = png_to_abgr ( & preview_buffer , size , & height ) ) )
2024-04-24 20:32:54 +02:00
{
return false ;
}
}
else
2017-12-02 16:09:38 +01:00
{
free ( preview_buffer ) ;
2024-04-24 20:32:54 +02:00
const int top_size = TOP_SCREEN_WIDTH * SCREEN_HEIGHT * SCREEN_COLOR_DEPTH ;
const int out_size = top_size * 2 ;
char * rgba_buffer = malloc ( out_size ) ;
memset ( rgba_buffer , 0 , out_size ) ;
bool found_splash = false ;
// try to assembly a preview from the splash screens
size = load_data ( " /splash.bin " , entry , & preview_buffer ) ;
if ( size )
{
found_splash = true ;
bin_to_abgr ( & preview_buffer , size ) ;
memcpy ( rgba_buffer , preview_buffer , top_size ) ;
free ( preview_buffer ) ;
}
size = load_data ( " /splashbottom.bin " , entry , & preview_buffer ) ;
if ( size )
{
found_splash = true ;
bin_to_abgr ( & preview_buffer , size ) ;
const int buffer_width = TOP_SCREEN_WIDTH * SCREEN_COLOR_DEPTH ;
const int bottom_buffer_width = BOTTOM_SCREEN_WIDTH * SCREEN_COLOR_DEPTH ;
const int bottom_centered_offset = ( TOP_SCREEN_WIDTH - BOTTOM_SCREEN_WIDTH ) / 2 ;
// Store the bottom splash screen under the top splash and centered
for ( int i = 0 ; i < SCREEN_HEIGHT ; + + i )
memcpy (
rgba_buffer + top_size + ( buffer_width * i ) + ( bottom_centered_offset * SCREEN_COLOR_DEPTH ) ,
preview_buffer + ( bottom_buffer_width * i ) ,
bottom_buffer_width
) ;
free ( preview_buffer ) ;
}
if ( ! found_splash )
{
free ( rgba_buffer ) ;
2024-05-12 14:24:43 -04:00
throw_error ( language . loading . no_preview , ERROR_LEVEL_WARNING ) ;
2024-04-24 20:32:54 +02:00
return false ;
}
size = out_size ;
preview_buffer = rgba_buffer ;
2017-12-02 16:09:38 +01:00
}
2024-05-12 14:24:43 -04:00
bool ret = load_preview_from_buffer ( preview_buffer , size , preview_image , preview_offset , height ) ;
2018-07-22 21:22:23 +03:00
free ( preview_buffer ) ;
2017-12-02 16:09:38 +01:00
2018-07-22 21:22:23 +03:00
if ( ret )
2017-12-02 16:09:38 +01:00
{
2017-12-15 20:37:29 +01:00
// mark the new preview as loaded for optimisation
2024-05-10 23:43:47 +02:00
memcpy ( & previous_path_preview , & entry - > path , 0x106 * sizeof ( u16 ) ) ;
2017-12-15 20:37:29 +01:00
}
2017-12-02 16:09:38 +01:00
return ret ;
}
2018-05-10 07:40:28 -04:00
2018-07-22 21:22:23 +03:00
void free_preview ( C2D_Image preview )
{
if ( preview . tex )
C3D_TexDelete ( preview . tex ) ;
free ( preview . tex ) ;
2024-05-10 23:43:47 +02:00
free ( ( Tex3DS_SubTexture * ) preview . subtex ) ;
2018-07-22 21:22:23 +03:00
}
2018-05-10 07:40:28 -04:00
// Initialize the audio struct
2024-05-10 23:43:47 +02:00
Result load_audio ( const Entry_s * entry , audio_s * audio )
2024-06-04 17:17:16 -04:00
{
audio - > music_size = load_data ( " /bgm.bcstm " , entry , & audio - > music_buf ) ;
if ( audio - > music_size = = 0 ) {
free ( audio ) ;
DEBUG ( " <load_audio> File not found! \n " ) ;
return MAKERESULT ( RL_FATAL , RS_NOTFOUND , RM_APPLICATION , RD_NOT_FOUND ) ;
}
audio - > cursor = 0 ;
audio - > last_time = 0 ;
audio - > current_block = 0 ;
audio - > stop = false ;
audio - > active_channels = 0 ;
return MAKERESULT ( RL_SUCCESS , RS_SUCCESS , RM_APPLICATION , RD_SUCCESS ) ;
}
Result load_audio_ogg ( const Entry_s * entry , audio_ogg_s * audio )
2018-05-10 07:40:28 -04:00
{
audio - > filesize = load_data ( " /bgm.ogg " , entry , & audio - > filebuf ) ;
2018-05-10 12:33:55 -04:00
if ( audio - > filesize = = 0 ) {
free ( audio ) ;
2018-07-22 21:22:23 +03:00
DEBUG ( " <load_audio> File not found! \n " ) ;
2018-05-10 12:33:55 -04:00
return MAKERESULT ( RL_FATAL , RS_NOTFOUND , RM_APPLICATION , RD_NOT_FOUND ) ;
}
2018-05-10 07:40:28 -04:00
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
2018-07-22 21:22:23 +03:00
2018-05-10 07:40:28 -04:00
ndspChnSetInterp ( 0 , NDSP_INTERP_LINEAR ) ;
2018-05-10 13:53:51 +02:00
ndspChnSetMix ( 0 , audio - > mix ) ; // See mix comment above
2018-05-10 07:40:28 -04:00
2024-05-10 23:43:47 +02:00
FILE * file = fmemopen ( audio - > filebuf , audio - > filesize , " rb " ) ;
2018-07-22 21:22:23 +03:00
DEBUG ( " <load_audio> Filesize: %ld \n " , audio - > filesize ) ;
2018-05-10 07:40:28 -04:00
if ( file ! = NULL )
{
int e = ov_open ( file , & audio - > vf , NULL , 0 ) ;
if ( e < 0 )
{
2018-07-22 21:22:23 +03:00
DEBUG ( " <load_audio> Vorbis: %d \n " , e ) ;
2018-05-13 09:02:55 -04:00
free ( audio - > filebuf ) ;
free ( audio ) ;
fclose ( file ) ;
2018-05-10 07:40:28 -04:00
return MAKERESULT ( RL_FATAL , RS_INVALIDARG , RM_APPLICATION , RD_NO_DATA ) ;
}
2024-05-10 23:43:47 +02:00
vorbis_info * vi = ov_info ( & audio - > vf , - 1 ) ;
2018-05-10 07:40:28 -04:00
ndspChnSetRate ( 0 , vi - > rate ) ; // Set sample rate to what's read from the ogg file
2018-05-13 09:02:55 -04:00
if ( vi - > channels = = 2 ) {
2018-07-22 21:22:23 +03:00
DEBUG ( " <load_audio> Using stereo \n " ) ;
2018-05-13 09:02:55 -04:00
ndspChnSetFormat ( 0 , NDSP_FORMAT_STEREO_PCM16 ) ; // 2 channels == Stereo
} else {
2018-07-22 21:22:23 +03:00
DEBUG ( " <load_audio> Invalid number of channels \n " ) ;
2018-05-13 09:02:55 -04:00
free ( audio - > filebuf ) ;
free ( audio ) ;
fclose ( file ) ;
return MAKERESULT ( RL_FATAL , RS_INVALIDARG , RM_APPLICATION , RD_NO_DATA ) ;
}
2018-05-10 07:40:28 -04:00
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 ) ;
2018-07-22 21:22:23 +03:00
DEBUG ( " <load_audio> Success! \n " ) ;
2018-05-10 07:40:28 -04:00
return MAKERESULT ( RL_SUCCESS , RS_SUCCESS , RM_APPLICATION , RD_SUCCESS ) ;
} else {
2018-05-10 13:53:51 +02:00
free ( audio - > filebuf ) ;
free ( audio ) ;
2018-07-22 21:22:23 +03:00
DEBUG ( " <load_audio> fmemopen failed! \n " ) ;
2018-05-10 07:40:28 -04:00
return MAKERESULT ( RL_FATAL , RS_NOTFOUND , RM_APPLICATION , RD_NOT_FOUND ) ;
}
2024-06-04 17:17:16 -04:00
}