See desc for more.
- Add WAV playback back with 10 MiB as max limit. - Some more Screenshot Menu checks.
This commit is contained in:
parent
78d0dad604
commit
64977911e6
22 changed files with 450 additions and 161 deletions
|
|
@ -49,4 +49,5 @@ To build Universal-Updater from source, you will need to setup devkitARM with li
|
|||
- [dlbeer](https://github.com/dlbeer) - Original developer of [quirc](https://github.com/dlbeer/quirc)
|
||||
- [FlagBrew](https://github.com/FlagBrew): Original QR Code Scanner code
|
||||
- [Icons8](https://icons8.com/): Icon Designer
|
||||
- [lvandeve](https://github.com/lvandeve): For [LodePNG](https://github.com/lvandeve/lodepng)
|
||||
- [PabloMK7](https://github.com/mariohackandglitch): Download Code Improvements
|
||||
|
|
@ -7,8 +7,11 @@ sprites/checked.png
|
|||
sprites/delete.png
|
||||
sprites/download.png
|
||||
sprites/info.png
|
||||
sprites/keyboard.png
|
||||
sprites/list.png
|
||||
sprites/noIcon.png
|
||||
sprites/qr_code.png
|
||||
sprites/screenshot.png
|
||||
sprites/search.png
|
||||
sprites/settings.png
|
||||
sprites/shortcut.png
|
||||
|
|
|
|||
BIN
assets/gfx/sprites/keyboard.png
Normal file
BIN
assets/gfx/sprites/keyboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 441 B |
BIN
assets/gfx/sprites/list.png
Normal file
BIN
assets/gfx/sprites/list.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 187 B |
Binary file not shown.
|
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 377 B |
BIN
assets/gfx/sprites/screenshot.png
Normal file
BIN
assets/gfx/sprites/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 459 B |
|
|
@ -67,16 +67,10 @@ public:
|
|||
|
||||
void drawThread();
|
||||
void captureThread();
|
||||
void handler(std::vector<u8>& out);
|
||||
void handler(std::string &result);
|
||||
bool done() const { return this->finished; };
|
||||
bool cancelled() const { return this->cancel; };
|
||||
bool Mode() const { return this->mode; };
|
||||
void Info(bool v) { this->displayInfo = v; };
|
||||
|
||||
int selectedStore = 0, sPos = 0;
|
||||
std::vector<StoreList> stores = { };
|
||||
bool FromList = false;
|
||||
uint8_t timeout = 30;
|
||||
void List(bool v) { this->displayList = v; };
|
||||
private:
|
||||
void buffToImage();
|
||||
void finish();
|
||||
|
|
@ -90,9 +84,10 @@ private:
|
|||
std::atomic<bool> finished = false;
|
||||
bool capturing = false;
|
||||
bool cancel = false;
|
||||
bool mode = true; // True -> Camera, False -> URL.
|
||||
bool displayInfo = false;
|
||||
|
||||
bool displayList = false;
|
||||
int selectedStore = 0, sPos = 0;
|
||||
std::vector<StoreList> stores = { };
|
||||
std::vector<u8> out;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ private:
|
|||
std::vector<std::string> dwnldList, dwnldSizes;
|
||||
|
||||
bool initialized = false, fetchDown = false, showMarks = false, showSettings = false,
|
||||
ascending = false, updateFilter = false, screenshotFetch = false;
|
||||
ascending = false, updateFilter = false, screenshotFetch = false, canDisplay = false;
|
||||
|
||||
int storeMode = 0, marks = 0, markIndex = 0, sPage = 0, lMode = 0, sSelection = 0,
|
||||
lastMode = 0, smallDelay = 0, sPos = 0, screenshotIndex = 0, sSize = 0, zoom = 0;
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ namespace StoreUtils {
|
|||
void DrawCredits();
|
||||
|
||||
/* Screenshot menu. */
|
||||
void DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom);
|
||||
void ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &storeMode, const int screenshotSize, int &zoom);
|
||||
void DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom, const bool canDisplay);
|
||||
void ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &storeMode, const int screenshotSize, int &zoom, bool &canDisplay);
|
||||
|
||||
/* Settings. */
|
||||
void DrawSettings(int page, int selection, int sPos);
|
||||
|
|
|
|||
47
include/utils/sound.hpp
Normal file
47
include/utils/sound.hpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* This file is part of Universal-Updater
|
||||
* Copyright (C) 2019-2020 Universal-Team
|
||||
*
|
||||
* 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 _UNIVERSAL_UPDATER_SOUND_HPP
|
||||
#define _UNIVERSAL_UPDATER_SOUND_HPP
|
||||
|
||||
#include <3ds.h>
|
||||
#include <string>
|
||||
|
||||
class Sound {
|
||||
public:
|
||||
Sound(const std::string &path, const int channel = 1, const bool toloop = true);
|
||||
~Sound();
|
||||
void play();
|
||||
void stop();
|
||||
private:
|
||||
u32 dataSize;
|
||||
bool good = true;
|
||||
ndspWaveBuf waveBuf;
|
||||
u8 *data = nullptr;
|
||||
int chnl;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
"AUTO_UPDATE_UU": "Auto-update Universal-Updater",
|
||||
"AUTO_UPDATE_UU_DESC": "When enabled, Universal-Updater will check for updates every time it's opened.",
|
||||
"AVAILABLE_DOWNLOADS": "Available Downloads",
|
||||
"AVAILABLE_UNISTORES": "Available UniStores",
|
||||
"BOOT_TITLE": "Would you like to boot this title?",
|
||||
"CATEGORY": "Category",
|
||||
"CHANGE_3DSX_PATH": "Change 3DSX path",
|
||||
|
|
@ -57,8 +56,8 @@
|
|||
"ENTRIES": "Entries",
|
||||
"EXECUTE_ENTRY": "Would you like to execute this entry?",
|
||||
"EXIT_APP": "Exit Universal-Updater",
|
||||
"FETCHING_AVAILABLE_UNISTORES": "Fetching available UniStores...",
|
||||
"FETCHING_METADATA": "Fetching old metadata...",
|
||||
"FETCHING_RECOMMENDED_UNISTORES": "Fetching recommended UniStores...",
|
||||
"FILE_EXTRACTED": "file extracted.",
|
||||
"FILE_SLASH": "Seems like a '/' is included, which is not supported.\nPlease change 'file' to filename only.",
|
||||
"FILES_EXTRACTED": "files extracted.",
|
||||
|
|
@ -84,8 +83,10 @@
|
|||
"NO_LICENSE": "No License",
|
||||
"NO_SCREENSHOTS_AVAILABLE": "No Screenshots available",
|
||||
"NOT_IMPLEMENTED": "Not Implemented Yet",
|
||||
"RECOMMENDED_UNISTORES": "Recommended UniStores",
|
||||
"REVISION": "Revision",
|
||||
"SCREENSHOT": "Screenshot %d / %d",
|
||||
"SCREENSHOT_COULD_NOT_LOAD": "Screenshot could not be loaded.",
|
||||
"SCREENSHOT_INSTRUCTIONS": "Press to change and to zoom",
|
||||
"SEARCH_FILTERS": "Search and Filters",
|
||||
"SELECT_DIR": "Select a directory",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "download.hpp"
|
||||
#include "init.hpp"
|
||||
#include "mainScreen.hpp"
|
||||
#include "sound.hpp"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -36,6 +37,8 @@ bool exiting = false, is3DSX = false, needUnloadFont = false;
|
|||
C2D_SpriteSheet sprites;
|
||||
int fadeAlpha = 0;
|
||||
u32 old_time_limit;
|
||||
std::unique_ptr<Sound> Music = nullptr;
|
||||
bool dspfirmFound = false;
|
||||
|
||||
/*
|
||||
Set, if 3DSX or CIA.
|
||||
|
|
@ -46,6 +49,32 @@ static void getCurrentUsage(){
|
|||
is3DSX = (id != 0x0004000004391700);
|
||||
}
|
||||
|
||||
/*
|
||||
Init Music.
|
||||
*/
|
||||
static void InitMusic() {
|
||||
if (access("sdmc:/3ds/dspfirm.cdc", F_OK) == 0) { // Ensure dspfirm dump exist.
|
||||
if (access("sdmc:/3ds/Universal-Updater/music.wav", F_OK) == 0) { // Ensure music.wav exist.
|
||||
dspfirmFound = true;
|
||||
ndspInit();
|
||||
Music = std::make_unique<Sound>("sdmc:/3ds/Universal-Updater/music.wav");
|
||||
|
||||
Music->play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Exit Music.
|
||||
*/
|
||||
static void ExitMusic() {
|
||||
if (dspfirmFound) {
|
||||
Music->stop();
|
||||
Music = nullptr;
|
||||
ndspExit();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If button Position pressed -> Do something.
|
||||
|
||||
|
|
@ -121,6 +150,7 @@ Result Init::Initialize() {
|
|||
if (exiting) return -1; // In case the update was successful.
|
||||
|
||||
Gui::setScreen(std::make_unique<MainScreen>(), false, false);
|
||||
InitMusic();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -172,6 +202,7 @@ Result Init::Exit() {
|
|||
Gui::exit();
|
||||
Gui::unloadSheet(sprites);
|
||||
UnloadFont();
|
||||
ExitMusic();
|
||||
gfxExit();
|
||||
cfguExit();
|
||||
config->save();
|
||||
|
|
|
|||
|
|
@ -47,8 +47,9 @@ void Overlays::ShowCredits() {
|
|||
Gui::DrawString(10, 70, 0.5f, TEXT_COLOR, "- dlbeer", 0, 0, font);
|
||||
Gui::DrawString(10, 90, 0.5f, TEXT_COLOR, "- FlagBrew", 0, 0, font);
|
||||
Gui::DrawString(10, 110, 0.5f, TEXT_COLOR, "- https://icons8.com/", 0, 0, font);
|
||||
Gui::DrawString(10, 130, 0.5f, TEXT_COLOR, "- PabloMK7", 0, 0, font);
|
||||
Gui::DrawString(10, 150, 0.5f, TEXT_COLOR, Lang::get("CONTRIBUTOR_TRANSLATORS"), 210, 0, font);
|
||||
Gui::DrawString(10, 130, 0.5f, TEXT_COLOR, "- Ivandeve", 0, 0, font);
|
||||
Gui::DrawString(10, 150, 0.5f, TEXT_COLOR, "- PabloMK7", 0, 0, font);
|
||||
Gui::DrawString(10, 170, 0.5f, TEXT_COLOR, Lang::get("CONTRIBUTOR_TRANSLATORS"), 210, 0, font);
|
||||
Gui::DrawString(10, 197, 0.5f, TEXT_COLOR, Lang::get("GITHUB"), 390, 0, font);
|
||||
|
||||
Gui::Draw_Rect(0, 215, 400, 25, BAR_COLOR);
|
||||
|
|
|
|||
|
|
@ -45,11 +45,9 @@ static const std::vector<Structs::ButtonPos> mainButtons = {
|
|||
{ 10, 154, 300, 22 },
|
||||
{ 10, 184, 300, 22 },
|
||||
|
||||
/* Add, Delete, Info.. */
|
||||
{ 92, 215, 16, 16 },
|
||||
{ 136, 215, 16, 16 },
|
||||
{ 180, 215, 16, 16 },
|
||||
{ 224, 215, 16, 16 },
|
||||
{ 112, 215, 16, 16 }, // Delete.
|
||||
{ 154, 215, 16, 16 }, // Update.
|
||||
{ 200, 215, 16, 16 }, // Add.
|
||||
{ 4, 0, 24, 24 } // Back.
|
||||
};
|
||||
|
||||
|
|
@ -265,7 +263,7 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
|
|||
|
||||
Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR);
|
||||
Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR);
|
||||
GFX::DrawSprite(sprites_arrow_idx, mainButtons[10].x, mainButtons[10].y);
|
||||
GFX::DrawSprite(sprites_arrow_idx, mainButtons[9].x, mainButtons[9].y);
|
||||
Gui::DrawStringCentered(0, 2, 0.6, TEXT_COLOR, Lang::get("SELECT_UNISTORE_2"), 310, 0, font);
|
||||
|
||||
for(int i = 0; i < 6 && i < (int)info.size(); i++) {
|
||||
|
|
@ -280,7 +278,6 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
|
|||
GFX::DrawSprite(sprites_delete_idx, mainButtons[6].x, mainButtons[6].y);
|
||||
GFX::DrawSprite(sprites_update_idx, mainButtons[7].x, mainButtons[7].y);
|
||||
GFX::DrawSprite(sprites_add_idx, mainButtons[8].x, mainButtons[8].y);
|
||||
GFX::DrawSprite(sprites_qr_code_idx, mainButtons[9].x, mainButtons[9].y);
|
||||
C3D_FrameEnd(0);
|
||||
|
||||
hidScanInput();
|
||||
|
|
@ -317,9 +314,9 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
|
|||
else if (info[selection].Version < 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_OLD"));
|
||||
else if (info[selection].Version > _UNISTORE_VERSION) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW"));
|
||||
else {
|
||||
config->lastStore(info[selection].FileName);
|
||||
store = std::make_unique<Store>(_STORE_PATH + info[selection].FileName, info[selection].FileName);
|
||||
StoreUtils::ResetAll(store, meta, entries);
|
||||
config->lastStore(info[selection].FileName);
|
||||
StoreUtils::SortEntries(false, SortType::LAST_UPDATED, entries);
|
||||
doOut = true;
|
||||
}
|
||||
|
|
@ -339,9 +336,10 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
|
|||
else if (info[i + sPos].Version < 3) Msg::waitMsg(Lang::get("UNISTORE_TOO_OLD"));
|
||||
else if (info[i + sPos].Version > _UNISTORE_VERSION) Msg::waitMsg(Lang::get("UNISTORE_TOO_NEW"));
|
||||
else {
|
||||
config->lastStore(info[i + sPos].FileName);
|
||||
store = std::make_unique<Store>(_STORE_PATH + info[i + sPos].FileName, info[i + sPos].FileName);
|
||||
StoreUtils::ResetAll(store, meta, entries);
|
||||
config->lastStore(info[i + sPos].FileName);
|
||||
StoreUtils::SortEntries(false, SortType::LAST_UPDATED, entries);
|
||||
doOut = true;
|
||||
}
|
||||
|
||||
|
|
@ -395,8 +393,6 @@ void Overlays::SelectStore(std::unique_ptr<Store> &store, std::vector<std::uniqu
|
|||
}
|
||||
|
||||
/* Go out of the menu. */
|
||||
if ((hidKeysDown() & KEY_B) || (hidKeysDown() & KEY_TOUCH && touching(touch, mainButtons[10]))) {
|
||||
doOut = true;
|
||||
}
|
||||
if ((hidKeysDown() & KEY_B) || (hidKeysDown() & KEY_TOUCH && touching(touch, mainButtons[9]))) doOut = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +62,11 @@ static const std::vector<Structs::ButtonPos> mainButtons = {
|
|||
{ 10, 94, 300, 22 },
|
||||
{ 10, 124, 300, 22 },
|
||||
{ 10, 154, 300, 22 },
|
||||
{ 10, 184, 300, 22 }
|
||||
{ 10, 184, 300, 22 },
|
||||
|
||||
{ 5, 215, 24, 24 }, // QR Code / List.
|
||||
{ 35, 215, 24, 24 }, // Keyboard.
|
||||
{ 4, 0, 24, 24 } // Back.
|
||||
};
|
||||
extern bool touching(touchPosition touch, Structs::ButtonPos button);
|
||||
|
||||
|
|
@ -84,6 +88,8 @@ QRCode::QRCode() {
|
|||
quirc_resize(this->qrData, 400, 240);
|
||||
|
||||
if (checkWifiStatus()) this->stores = FetchStores(); // Fetching Stores here.
|
||||
|
||||
if (this->stores.size() > 0) this->displayList = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -140,14 +146,20 @@ void QRCode::drawThread() {
|
|||
C2D_TargetClear(Top, TRANSPARENT);
|
||||
C2D_TargetClear(Bottom, TRANSPARENT);
|
||||
|
||||
if (!this->displayInfo) {
|
||||
if (!this->displayList) {
|
||||
this->buffToImage(); // Fetch image.
|
||||
Gui::ScreenDraw(Top);
|
||||
C2D_DrawImageAt(this->image, 0, 0, 0.5, nullptr, 1.0f, 1.0f);
|
||||
|
||||
GFX::DrawBottom();
|
||||
Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR);
|
||||
Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR);
|
||||
|
||||
} else {
|
||||
GFX::DrawTop();
|
||||
Gui::DrawStringCentered(0, 1, 0.7, TEXT_COLOR, Lang::get("STORE_INFO"), 390, 0, font);
|
||||
|
||||
if (this->stores.size() > 0) {
|
||||
Gui::DrawStringCentered(0, 30, 0.7f, TEXT_COLOR, this->stores[this->selectedStore].Title, 390, 0, font);
|
||||
Gui::DrawStringCentered(0, 50, 0.6f, TEXT_COLOR, this->stores[this->selectedStore].Author, 380, 0, font);
|
||||
|
||||
|
|
@ -165,14 +177,18 @@ void QRCode::drawThread() {
|
|||
GFX::DrawBottom();
|
||||
Gui::Draw_Rect(0, 0, 320, 25, ENTRY_BAR_COLOR);
|
||||
Gui::Draw_Rect(0, 25, 320, 1, ENTRY_BAR_OUTL_COLOR);
|
||||
Gui::DrawStringCentered(0, 2, 0.6, TEXT_COLOR, Lang::get("AVAILABLE_UNISTORES"), 310, 0, font);
|
||||
Gui::DrawStringCentered(0, 2, 0.6, TEXT_COLOR, Lang::get("RECOMMENDED_UNISTORES"), 310, 0, font);
|
||||
|
||||
for(int i = 0; i < 6 && i < (int)this->stores.size(); i++) {
|
||||
if (this->sPos + i == this->selectedStore) GFX::DrawBox(mainButtons[i].x, mainButtons[i].y, mainButtons[i].w, mainButtons[i].h, false);
|
||||
|
||||
Gui::DrawStringCentered(10 - 160 + (300 / 2), mainButtons[i].y + 4, 0.45f, TEXT_COLOR, this->stores[this->sPos + i].Title, 295, 0, font);
|
||||
}
|
||||
}
|
||||
|
||||
GFX::DrawSprite((this->displayList ? sprites_qr_code_idx : sprites_list_idx), mainButtons[6].x, mainButtons[6].y);
|
||||
if (this->displayList) GFX::DrawSprite(sprites_keyboard_idx, mainButtons[7].x, mainButtons[7].y);
|
||||
GFX::DrawSprite(sprites_arrow_idx, mainButtons[8].x, mainButtons[8].y);
|
||||
C3D_FrameEnd(0);
|
||||
}
|
||||
|
||||
|
|
@ -192,6 +208,7 @@ void QRCode::captureThread() {
|
|||
CAMU_SetSize(SELECT_OUT1, SIZE_CTR_TOP_LCD, CONTEXT_A);
|
||||
CAMU_SetOutputFormat(SELECT_OUT1, OUTPUT_RGB_565, CONTEXT_A);
|
||||
CAMU_SetFrameRate(SELECT_OUT1, FRAME_RATE_30);
|
||||
|
||||
CAMU_SetNoiseFilter(SELECT_OUT1, true);
|
||||
CAMU_SetAutoExposure(SELECT_OUT1, true);
|
||||
CAMU_SetAutoWhiteBalance(SELECT_OUT1, true);
|
||||
|
|
@ -275,41 +292,44 @@ void captureHelper(void *arg) {
|
|||
|
||||
/*
|
||||
Handle the capture.
|
||||
|
||||
std::vector<u8> &out: The Reference, where to output the decoded result.
|
||||
*/
|
||||
void QRCode::handler(std::vector<u8> &out) {
|
||||
void QRCode::handler(std::string &result) {
|
||||
hidScanInput();
|
||||
touchPosition t;
|
||||
hidTouchRead(&t);
|
||||
u32 keyDown = hidKeysDown();
|
||||
u32 keyRepeat = hidKeysDownRepeat();
|
||||
|
||||
if (keyDown & KEY_B) {
|
||||
this->cancel = true;
|
||||
if ((keyDown & KEY_B) || (keyDown & KEY_TOUCH && touching(t, mainButtons[8]))) {
|
||||
result = "";
|
||||
this->finished = true;
|
||||
this->finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->displayInfo) {
|
||||
if (this->timeout == 0) { // hidKeysDown() is pretty buggy, hence try to do it a timeout way.
|
||||
if (keyDown & KEY_SELECT) {
|
||||
this->timeout = 10;
|
||||
keyDown = 0;
|
||||
this->displayInfo = false;
|
||||
/* Keyboard. */
|
||||
if (keyDown & KEY_TOUCH && touching(t, mainButtons[7])) {
|
||||
if (this->displayList) {
|
||||
const std::string temp = Input::setkbdString(150, Lang::get("ENTER_URL"), { });
|
||||
|
||||
if (temp != "") {
|
||||
result = temp;
|
||||
this->finished = true;
|
||||
this->finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (this->displayList) {
|
||||
gspWaitForVBlank();
|
||||
|
||||
if ((keyDown & KEY_SELECT) || (keyDown & KEY_TOUCH && touching(t, mainButtons[6]))) {
|
||||
keyDown = 0;
|
||||
this->displayList = false;
|
||||
}
|
||||
|
||||
if (this->stores.size() > 0) {
|
||||
if (this->timeout == 0) {
|
||||
if (keyDown & KEY_SELECT) {
|
||||
this->timeout = 30;
|
||||
keyDown = 0;
|
||||
this->displayInfo = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyRepeat & KEY_DOWN) {
|
||||
if (this->selectedStore < (int)this->stores.size() - 1) this->selectedStore++;
|
||||
else this->selectedStore = 0;
|
||||
|
|
@ -321,7 +341,8 @@ void QRCode::handler(std::vector<u8> &out) {
|
|||
}
|
||||
|
||||
if (keyDown & KEY_A) {
|
||||
this->FromList = true;
|
||||
result = this->stores[this->selectedStore].URL;
|
||||
this->finished = true;
|
||||
this->finish();
|
||||
return;
|
||||
}
|
||||
|
|
@ -330,8 +351,8 @@ void QRCode::handler(std::vector<u8> &out) {
|
|||
for (int i = 0; i < 6; i++) {
|
||||
if (touching(t, mainButtons[i])) {
|
||||
if (i + this->sPos < (int)this->stores.size()) {
|
||||
this->selectedStore = i + this->sPos;
|
||||
this->FromList = true;
|
||||
result = this->stores[i + this->sPos].URL;
|
||||
this->finished = true;
|
||||
this->finish();
|
||||
return;
|
||||
}
|
||||
|
|
@ -340,8 +361,16 @@ void QRCode::handler(std::vector<u8> &out) {
|
|||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (this->stores.size() > 0) {
|
||||
if ((keyDown & KEY_SELECT) || (keyDown & KEY_TOUCH && touching(t, mainButtons[6]))) {
|
||||
keyDown = 0;
|
||||
this->displayList = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->capturing) {
|
||||
/* create camera draw thread. */
|
||||
/* create camera capture thread. */
|
||||
if (threadCreate((ThreadFunc)&captureHelper, this, 0x10000, 0x1A, 1, true) != NULL) this->capturing = true;
|
||||
else {
|
||||
this->finish();
|
||||
|
|
@ -372,50 +401,34 @@ void QRCode::handler(std::vector<u8> &out) {
|
|||
|
||||
if (!quirc_decode(&code, &scan_data)) {
|
||||
this->finish();
|
||||
out.resize(scan_data.payload_len);
|
||||
std::copy(scan_data.payload, scan_data.payload + scan_data.payload_len, out.begin());
|
||||
this->out.resize(scan_data.payload_len);
|
||||
std::copy(scan_data.payload, scan_data.payload + scan_data.payload_len, this->out.begin());
|
||||
|
||||
/* From scanned stuff. */
|
||||
if (this->out.empty()) result = "";
|
||||
|
||||
/* If Terminator, do -1. */
|
||||
if (this->out.back() == '\0') result = std::string((char *)this->out.data(), this->out.size() - 1);
|
||||
else result = std::string((char *)this->out.data(), this->out.size());
|
||||
}
|
||||
}
|
||||
|
||||
if (this->selectedStore < this->sPos) this->sPos = this->selectedStore;
|
||||
else if (this->selectedStore > this->sPos + 6 - 1) this->sPos = this->selectedStore - 6 + 1;
|
||||
}
|
||||
|
||||
if (this->timeout > 0) this->timeout--;
|
||||
}
|
||||
|
||||
/*
|
||||
The Store Add QR Code handle and such.
|
||||
*/
|
||||
std::string QR_Scanner::StoreHandle() {
|
||||
std::vector<u8> data = { };
|
||||
std::string result = "";
|
||||
|
||||
std::unique_ptr<QRCode> qrData = std::make_unique<QRCode>();
|
||||
aptSetHomeAllowed(false); // Block the Home key.
|
||||
|
||||
threadCreate((ThreadFunc)&drawHelper, qrData.get(), 0x10000, 0x1A, 1, true);
|
||||
while (!qrData->done()) qrData->handler(data); // Handle.
|
||||
while (!qrData->done()) qrData->handler(result); // Handle.
|
||||
aptSetHomeAllowed(true); // Re-Allow it.
|
||||
|
||||
/* Selected from list. */
|
||||
if (qrData->FromList) {
|
||||
return qrData->stores[qrData->selectedStore].URL;
|
||||
}
|
||||
|
||||
/* False means Keyboard. */
|
||||
if (!qrData->Mode()) {
|
||||
const std::string out = Input::setkbdString(150, Lang::get("ENTER_URL"), { });
|
||||
return out;
|
||||
|
||||
} else {
|
||||
/* From scanned stuff. */
|
||||
if (data.empty()) return "";
|
||||
|
||||
/* If Terminator, do -1. */
|
||||
if (data.back() == '\0') return std::string((char *)data.data(), data.size() - 1);
|
||||
|
||||
else return std::string((char *)data.data(), data.size());
|
||||
}
|
||||
|
||||
return "";
|
||||
return result;
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ MainScreen::MainScreen() {
|
|||
void MainScreen::Draw(void) const {
|
||||
if (this->storeMode == 5) {
|
||||
/* Screenshot Menu. */
|
||||
StoreUtils::DrawScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->sSize, this->screenshotName, this->zoom);
|
||||
StoreUtils::DrawScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->sSize, this->screenshotName, this->zoom, this->canDisplay);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -180,13 +180,15 @@ void MainScreen::Logic(u32 hDown, u32 hHeld, touchPosition touch) {
|
|||
if (this->screenshotIndex < this->sSize) {
|
||||
if (this->sSize > 0) {
|
||||
this->Screenshot = FetchScreenshot(this->entries[this->store->GetEntry()]->GetScreenshots()[this->screenshotIndex]);
|
||||
if (this->Screenshot.tex) this->canDisplay = true;
|
||||
else this->canDisplay = false;
|
||||
}
|
||||
}
|
||||
|
||||
this->screenshotFetch = false;
|
||||
}
|
||||
|
||||
StoreUtils::ScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->storeMode, this->sSize, this->zoom);
|
||||
StoreUtils::ScreenshotMenu(this->Screenshot, this->screenshotIndex, this->screenshotFetch, this->storeMode, this->sSize, this->zoom, this->canDisplay);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@
|
|||
#include "structs.hpp"
|
||||
|
||||
extern bool touching(touchPosition touch, Structs::ButtonPos button);
|
||||
static const Structs::ButtonPos btn = { 53, 215, 20, 20 };
|
||||
static const Structs::ButtonPos btn = { 53, 215, 24, 24 };
|
||||
static const Structs::ButtonPos sshot = { 83, 215, 24, 24 };
|
||||
extern bool checkWifiStatus();
|
||||
|
||||
/*
|
||||
Draw the Entry Info part.
|
||||
|
|
@ -61,7 +63,8 @@ void StoreUtils::DrawEntryInfo(const std::unique_ptr<Store> &store, const std::u
|
|||
Gui::DrawString(61, 190, 0.45, TEXT_COLOR, Lang::get("LICENSE") + ": " + entry->GetLicense(), 240, 0, font);
|
||||
|
||||
GFX::DrawBox(btn.x, btn.y, btn.w, btn.h, false);
|
||||
Gui::DrawString(btn.x + 3, btn.y, 0.6f, TEXT_COLOR, "★", 0, 0, font);
|
||||
GFX::DrawSprite(sprites_screenshot_idx, sshot.x, sshot.y);
|
||||
Gui::DrawString(btn.x + 5, btn.y + 2, 0.6f, TEXT_COLOR, "★", 0, 0, font);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,12 +77,16 @@ void StoreUtils::DrawEntryInfo(const std::unique_ptr<Store> &store, const std::u
|
|||
|
||||
bool &showMark: Reference to showMark.. to show the mark menu.
|
||||
bool &fetch: Reference to fetch, so we know, if we need to fetch, when accessing download list.
|
||||
bool &sFetch: Reference to the screenshot fetch.
|
||||
int &mode: Reference to the Store mode.
|
||||
*/
|
||||
void StoreUtils::EntryHandle(bool &showMark, bool &fetch, bool &sFetch, int &mode) {
|
||||
if ((hDown & KEY_START) || (hDown & KEY_TOUCH && touching(touch, btn))) showMark = true;
|
||||
|
||||
if (hDown & KEY_SELECT) {
|
||||
if ((hDown & KEY_SELECT) || (hDown & KEY_TOUCH && touching(touch, sshot))) {
|
||||
if (checkWifiStatus()) {
|
||||
sFetch = true;
|
||||
mode = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ static const std::vector<Structs::ButtonPos> markBox = {
|
|||
{ 196, 94, 52, 52 },
|
||||
{ 258, 94, 52, 52 },
|
||||
|
||||
{ 53, 215, 20, 20 }
|
||||
{ 53, 215, 24, 24 }
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -68,7 +68,7 @@ void StoreUtils::DisplayMarkBox(int marks) {
|
|||
Gui::DrawString(markBox[4].x + 15, markBox[4].y + 11, 0.9, TEXT_COLOR, "♠", 0, 0, font);
|
||||
|
||||
GFX::DrawBox(markBox[5].x, markBox[5].y, markBox[5].w, markBox[5].h, false);
|
||||
Gui::DrawString(markBox[5].x + 3, markBox[5].y, 0.6f, TEXT_COLOR, "★", 0, 0, font);
|
||||
Gui::DrawString(markBox[5].x + 5, markBox[5].y + 2, 0.6f, TEXT_COLOR, "★", 0, 0, font);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "structs.hpp"
|
||||
|
||||
extern bool touching(touchPosition touch, Structs::ButtonPos button);
|
||||
extern bool checkWifiStatus();
|
||||
|
||||
/*
|
||||
Draw the Screenshot menu.
|
||||
|
|
@ -38,16 +39,32 @@ extern bool touching(touchPosition touch, Structs::ButtonPos button);
|
|||
const int screenshotSize: The screenshot amount.
|
||||
const std::string &name: The name of the screenshot.
|
||||
const int zoom: The zoom level, zoom out, 1x scale, or zoom in.
|
||||
const bool canDisplay: If can display, or not.
|
||||
*/
|
||||
void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom) {
|
||||
void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, const bool sFetch, const int screenshotSize, const std::string &name, const int zoom, const bool canDisplay) {
|
||||
Gui::ScreenDraw(Top);
|
||||
Gui::Draw_Rect(0, 0, 400, 240, BG_COLOR);
|
||||
|
||||
if (!canDisplay) {
|
||||
GFX::DrawBottom();
|
||||
if (screenshotSize > 0) { // if texture is nullptr AND screenshot size is larger than 0.
|
||||
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("SCREENSHOT_COULD_NOT_LOAD"), 310);
|
||||
|
||||
} else {
|
||||
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sFetch) { // Only, if not fetch. This avoids a small flicker of the old screenshot on entries without screenshots.
|
||||
if (screenshotSize > 0) {
|
||||
float scale = 1.0f;
|
||||
|
||||
if (zoom == 0) {
|
||||
scale = std::min(1.0f, std::min(400.0f / img.subtex->width, 240.0f / img.subtex->height));
|
||||
if (img.tex) C2D_DrawImageAt(img, (400 - img.subtex->width * scale) / 2, (240 - img.subtex->height * scale) / 2, 0.5f, nullptr, scale, scale);
|
||||
|
||||
} else {
|
||||
// Create new C2D_Image with smaller subtex
|
||||
C2D_Image top = img;
|
||||
|
|
@ -89,6 +106,7 @@ void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, cons
|
|||
GFX::DrawBottom();
|
||||
Gui::DrawStringCentered(0, 2, 0.6f, WHITE, Lang::get("NO_SCREENSHOTS_AVAILABLE"), 310);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -99,29 +117,35 @@ void StoreUtils::DrawScreenshotMenu(const C2D_Image &img, const int sIndex, cons
|
|||
bool &sFetch: If fetching screenshots or not.
|
||||
const int screenshotSize: The screenshot amount.
|
||||
int &zoom: The zoom level, zoom out, 1x scale, or zoom in.
|
||||
bool &canDisplay: If can display or not.
|
||||
*/
|
||||
void StoreUtils::ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &storeMode, const int screenshotSize, int &zoom) {
|
||||
void StoreUtils::ScreenshotMenu(C2D_Image &img, int &sIndex, bool &sFetch, int &storeMode, const int screenshotSize, int &zoom, bool &canDisplay) {
|
||||
if (hDown & KEY_B) {
|
||||
zoom = false;
|
||||
canDisplay = false;
|
||||
zoom = 0;
|
||||
sIndex = 0;
|
||||
storeMode = 0; // Go back to EntryInfo.
|
||||
}
|
||||
|
||||
if (hDown & KEY_RIGHT) {
|
||||
if ((hDown & KEY_RIGHT) || (hDown & KEY_R)) {
|
||||
if (checkWifiStatus()) {
|
||||
if (sIndex < screenshotSize - 1) {
|
||||
sIndex++;
|
||||
sFetch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hDown & KEY_DOWN && zoom > 0) zoom--;
|
||||
|
||||
if (hDown & KEY_UP && zoom < 2) zoom++;
|
||||
|
||||
if (hDown & KEY_LEFT) {
|
||||
if ((hDown & KEY_LEFT) || (hDown & KEY_L)) {
|
||||
if (checkWifiStatus()) {
|
||||
if (sIndex > 0) {
|
||||
sIndex--;
|
||||
sFetch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -112,8 +112,10 @@ Config::Config() {
|
|||
|
||||
/* Let us create a new one. */
|
||||
if (!this->json.contains("Version")) this->initialize();
|
||||
|
||||
if (!this->json.contains("Language")) this->sysLang();
|
||||
else this->language(this->getString("Language"));
|
||||
|
||||
if (this->json.contains("LastStore")) this->lastStore(this->getString("LastStore"));
|
||||
if (this->json.contains("List")) this->list(this->getBool("List"));
|
||||
if (this->json.contains("AutoUpdate")) this->autoupdate(this->getBool("AutoUpdate"));
|
||||
|
|
@ -160,20 +162,20 @@ void Config::save() {
|
|||
bool Config::getBool(const std::string &key) {
|
||||
if (!this->json.contains(key)) return false;
|
||||
|
||||
return this->json.at(key).get_ref<const bool&>();
|
||||
return this->json.at(key).get_ref<const bool &>();
|
||||
}
|
||||
void Config::setBool(const std::string &key, bool v) { this->json[key] = v; };
|
||||
|
||||
int Config::getInt(const std::string &key) {
|
||||
if (!this->json.contains(key)) return 0;
|
||||
|
||||
return this->json.at(key).get_ref<const int64_t&>();
|
||||
return this->json.at(key).get_ref<const int64_t &>();
|
||||
}
|
||||
void Config::setInt(const std::string &key, int v) { this->json[key] = v; };
|
||||
|
||||
std::string Config::getString(const std::string &key) {
|
||||
if (!this->json.contains(key)) return "";
|
||||
|
||||
return this->json.at(key).get_ref<const std::string&>();
|
||||
return this->json.at(key).get_ref<const std::string &>();
|
||||
}
|
||||
void Config::setString(const std::string &key, const std::string &v) { this->json[key] = v; };
|
||||
|
|
@ -864,7 +864,7 @@ static StoreList fetch(const std::string &entry, nlohmann::json &js) {
|
|||
Fetch Store list for available UniStores.
|
||||
*/
|
||||
std::vector<StoreList> FetchStores() {
|
||||
Msg::DisplayMsg(Lang::get("FETCHING_AVAILABLE_UNISTORES"));
|
||||
Msg::DisplayMsg(Lang::get("FETCHING_RECOMMENDED_UNISTORES"));
|
||||
std::vector<StoreList> stores = { };
|
||||
|
||||
Result ret = 0;
|
||||
|
|
|
|||
166
source/utils/sound.cpp
Normal file
166
source/utils/sound.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* This file is part of Universal-Updater
|
||||
* Copyright (C) 2019-2020 Universal-Team
|
||||
*
|
||||
* 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 "sound.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
Reference: http://yannesposito.com/Scratch/en/blog/2010-10-14-Fun-with-wav/
|
||||
*/
|
||||
typedef struct _WavHeader {
|
||||
char magic[4]; // "RIFF"
|
||||
u32 totallength; // Total file length, minus 8.
|
||||
char wavefmt[8]; // Should be "WAVEfmt ".
|
||||
u32 format; // 16 for PCM format.
|
||||
u16 pcm; // 1 for PCM format.
|
||||
u16 channels; // Channels.
|
||||
u32 frequency; // Sampling frequency.
|
||||
u32 bytes_per_second;
|
||||
u16 bytes_by_capture;
|
||||
u16 bits_per_sample;
|
||||
char data[4]; // "data".
|
||||
u32 bytes_in_data;
|
||||
} WavHeader;
|
||||
static_assert(sizeof(WavHeader) == 44, "WavHeader size is not 44 bytes.");
|
||||
|
||||
#define _MAX_SIZE 10485760 // 10 MiB.
|
||||
|
||||
/*
|
||||
Initialize the sound.
|
||||
|
||||
const std::string &path: Path to the file to play.
|
||||
const int channel: The channel to use. 1 by default.
|
||||
const bool toloop: If should loop or not. True by default.
|
||||
*/
|
||||
Sound::Sound(const std::string &path, const int channel, const bool toloop) {
|
||||
ndspSetOutputMode(NDSP_OUTPUT_MONO);
|
||||
ndspSetOutputCount(2); // Amount of buffers.
|
||||
|
||||
/* Reading wav file. */
|
||||
FILE *file = fopen(path.c_str(), "rb");
|
||||
|
||||
if (!file) {
|
||||
printf("Could not open the WAV file: %s.\n", path.c_str());
|
||||
this->good = false;
|
||||
return;
|
||||
}
|
||||
|
||||
WavHeader wavHeader;
|
||||
size_t read = fread(&wavHeader, 1, sizeof(wavHeader), file);
|
||||
if (read != sizeof(wavHeader)) {
|
||||
/* Short read. */
|
||||
printf("WAV file header is too short: %s.\n", path.c_str());
|
||||
fclose(file);
|
||||
this->good = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify the header. */
|
||||
static const char RIFF_magic[4] = { 'R','I','F','F' };
|
||||
if (memcmp(wavHeader.magic, RIFF_magic, sizeof(wavHeader.magic)) != 0) {
|
||||
/* Incorrect magic number. */
|
||||
printf("Wrong file format.\n");
|
||||
fclose(file);
|
||||
this->good = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (wavHeader.totallength == 0 ||
|
||||
(wavHeader.channels != 1 && wavHeader.channels != 2) ||
|
||||
(wavHeader.bits_per_sample != 8 && wavHeader.bits_per_sample != 16)) {
|
||||
/* Unsupported WAV file. */
|
||||
printf("Corrupted wav file.\n");
|
||||
fclose(file);
|
||||
this->good = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the file size. */
|
||||
fseek(file, 0, SEEK_END);
|
||||
this->dataSize = ftell(file) - sizeof(wavHeader);
|
||||
|
||||
if (this->dataSize > _MAX_SIZE) {
|
||||
fclose(file);
|
||||
this->good = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocating and reading samples. */
|
||||
this->data = reinterpret_cast<u8 *>(linearAlloc(this->dataSize));
|
||||
fseek(file, 44, SEEK_SET);
|
||||
fread(this->data, 1, this->dataSize, file);
|
||||
fclose(file);
|
||||
|
||||
//if (wavHeader.bits_per_sample == 16) this->dataSize /= 2; // Not sure.. if that is actually needed at all.
|
||||
|
||||
this->chnl = channel;
|
||||
ndspChnReset(this->chnl);
|
||||
ndspChnSetInterp(this->chnl, NDSP_INTERP_NONE);
|
||||
ndspChnSetRate(this->chnl, float(wavHeader.frequency));
|
||||
ndspChnSetFormat(this->chnl, ((wavHeader.bits_per_sample == 8) ? NDSP_FORMAT_MONO_PCM8 : NDSP_FORMAT_MONO_PCM16));
|
||||
|
||||
/* Create and play a wav buffer. */
|
||||
memset(&this->waveBuf, 0, sizeof(this->waveBuf));
|
||||
|
||||
this->waveBuf.data_vaddr = reinterpret_cast<u32 *>(this->data);
|
||||
this->waveBuf.nsamples = this->dataSize / (wavHeader.bits_per_sample >> 3);
|
||||
this->waveBuf.looping = toloop;
|
||||
this->waveBuf.status = NDSP_WBUF_FREE;
|
||||
}
|
||||
|
||||
Sound::~Sound() {
|
||||
if (this->good) {
|
||||
this->waveBuf.data_vaddr = 0;
|
||||
this->waveBuf.nsamples = 0;
|
||||
this->waveBuf.looping = false;
|
||||
this->waveBuf.status = 0;
|
||||
ndspChnWaveBufClear(this->chnl);
|
||||
|
||||
if (this->data) linearFree(this->data);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Plays the sound.
|
||||
*/
|
||||
void Sound::play() {
|
||||
if (!this->data || !this->good) return;
|
||||
|
||||
DSP_FlushDataCache(this->data, this->dataSize);
|
||||
ndspChnWaveBufAdd(this->chnl, &this->waveBuf);
|
||||
}
|
||||
|
||||
/*
|
||||
Stops the sound.
|
||||
*/
|
||||
void Sound::stop() {
|
||||
if (!this->data || !this->good) return;
|
||||
|
||||
ndspChnWaveBufClear(this->chnl);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue