diff --git a/docs/css/frankenfirm.css b/docs/css/frankenfirm.css
new file mode 100755
index 0000000..860b0ae
--- /dev/null
+++ b/docs/css/frankenfirm.css
@@ -0,0 +1,261 @@
+body {
+ background-color: black;
+}
+
+.logo img{
+ margin-left: auto;
+ margin-right: auto;
+ width: 30%;
+ display: block;
+ padding-top: 4%;
+}
+
+.text p {
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 0;
+ width: 30%;
+ text-align: center;
+ display: block;
+ padding-top: 4%;
+ padding-bottom: 0;
+}
+.text img {
+ margin-left: auto;
+ margin-right: auto;
+ width: 30%;
+ display: block;
+ padding-top: 0;
+}
+
+.graphics img{
+ position:fixed;
+ bottom:0px;
+ margin-left: auto;
+ margin-right: auto;
+ width: 100%;
+ z-index: -99;
+}
+
+/*.downloads {
+ padding-top: 5%;
+}*/
+
+.hidden {
+ display: none;
+}
+
+button.donate {
+ margin-top: 10px;
+ font-weight: 700;
+ font-size: 1.2rem;
+ word-spacing: 30px;
+ background-color: #FFFFFF;
+ text-align: center;
+ border:none;
+ letter-spacing: 1px;
+ margin-left: auto;
+ margin-right: auto;
+ display: flex;
+ justify-content: center;
+ width:240px;
+ color: black;
+ min-width: 200px;
+}
+
+p {
+ font-family: 'PT Sans Caption', sans-serif;
+ color: white;
+}
+select {
+ font-family: 'PT Sans Caption', sans-serif;
+ text-transform: uppercase;
+ padding-top: 10px;
+ padding-right: 10px;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ cursor: pointer;
+ border: solid 2px;
+ border-color: white;
+ background-color: rgba(0,0,0,0);
+ color: white;
+ margin: 0;
+}
+option {
+ font-family: 'PT Sans Caption', sans-serif;
+ text-transform: uppercase;
+ padding-top: 10px;
+ padding-right: 10px;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ background-color: rgba(0,0,0,255);
+ color: white;
+}
+button {
+ font-family: 'PT Sans Caption', sans-serif;
+ text-transform: uppercase;
+ padding-top: 10px;
+ padding-right: 30px;
+ padding-bottom: 10px;
+ padding-left: 30px;
+ cursor: pointer;
+}
+
+.btn-group.error {
+ margin-left: auto;
+ margin-right: auto;
+ text-align: center;
+ margin-top: 2%;
+}
+
+.btn-group.firmware {
+ margin-left: auto;
+ margin-right: auto;
+ text-align: center;
+}
+
+.btn-group.console {
+ margin-left: auto;
+ margin-right: auto;
+ text-align: center;
+}
+
+.btn-group.forced {
+ pointer-events: none;
+}
+
+button.group{
+ border: solid 2px;
+ border-color: white;
+ background-color: rgba(0,0,0,0);
+ color: white;
+ margin: 0;
+}
+button.group:hover {
+ background-color: #333333;
+}
+
+button.group.selected{
+ background-color: #FFFFFF;
+ color: black;
+}
+
+button#download{
+ margin-top: 2%
+}
+
+button#download.active{
+ background-color: #FFFFFF;
+ color: black;
+}
+
+button#download{
+ font-weight: 700;
+ color: white;
+ font-size: 1.2rem;
+ background-color: rgba(0,0,0,0);
+ border:solid 2px;
+ border-color: white;
+ letter-spacing: 1px;
+ margin-left: auto;
+ margin-right: auto;
+ display: flex;
+ justify-content: center;
+ width:280px;
+ text-align: center;
+ min-width: 200px;
+ height: 45px;
+}
+
+.round {
+ border-radius: 2px;
+}
+
+@media only screen and (max-width: 1024px) and (-webkit-min-device-pixel-ratio: 3) {
+ .logo img{
+ margin-left: auto;
+ margin-right: auto;
+ width: 80%;
+ display: block;
+ padding-top: 4%;
+ }
+
+ .text img {
+ margin-left: auto;
+ margin-right: auto;
+ width: 80%;
+ display: block;
+ padding-top: 5%;
+ }
+
+ .graphics img{
+ position:fixed;
+ bottom:0px;
+ margin-left: auto;
+ margin-right: auto;
+ width: 100%;
+ z-index: -99;
+ }
+ p {
+ font-size: 50px;
+ }
+
+ button {
+ font-family: 'PT Sans Caption', sans-serif;
+ text-transform: uppercase;
+ font-size: 50px;
+ padding-top: 20px;
+ padding-right: 40px;
+ padding-bottom: 20px;
+ padding-left: 40px;
+ }
+ button.group{
+ border: solid 5px;
+ border-color: white;
+ background-color: rgba(0,0,0,0);
+ color: white;
+ margin: 0;
+ }
+ div.downloads {
+ margin-top: 15%
+ }
+
+ button#download{
+ padding-top: 20px;
+ padding-right: 40px;
+ padding-bottom: 70px;
+ padding-left: 40px;
+ font-weight: 700;
+ color: white;
+ font-size: 50px;
+ background-color: rgba(0,0,0,0);
+ border:solid 5px;
+ border-color: white;
+ margin-left: 20%;
+ margin-right: 20%;
+ display: flex;
+ justify-content: center;
+ width:60%;
+ text-align: center;
+ }
+ button#download.active{
+ background-color: #FFFFFF;
+ color: black;
+ }
+ button.donate {
+ margin-top: 30px;
+ font-weight: 700;
+ font-size: 50px;
+ word-spacing: 30px;
+ background-color: #FFFFFF;
+ text-align: center;
+ border:none;
+ letter-spacing: 1px;
+ margin-left: auto;
+ margin-right: auto;
+ display: flex;
+ justify-content: center;
+ width: 60%;
+ color: black;
+ }
+}
diff --git a/docs/frankenfirm.html b/docs/frankenfirm.html
new file mode 100755
index 0000000..7530623
--- /dev/null
+++ b/docs/frankenfirm.html
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+ SoundHax - Frankenfirm | Nintendo Hacking 2016-2020
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FRANKENFIRM/CARTUPDATED
+
+
+
+
+
+
+ Choose error from running normal soundhax:
+ Don't choose if you haven't tried yet
+
+
+
+
+
+
Input your full system version:
+
.
.
-
+
+
+
Choose a console:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/js/frankenfirm.js b/docs/js/frankenfirm.js
new file mode 100755
index 0000000..9733315
--- /dev/null
+++ b/docs/js/frankenfirm.js
@@ -0,0 +1,268 @@
+/* http://stackoverflow.com/a/5077091 */
+String.prototype.format = function () {
+ var args = arguments;
+ return this.replace(/\{(\d+)\}/g, function (m, n) { return args[n]; });
+};
+
+var ERR_INVALID_INPUT = 0;
+var ERR_NOT_SUPPORTED = 1;
+var ERR_USE_NORMAL_FIRST = 2;
+var ERR_LIKELY_WRONG_NORMAL = 3;
+
+var ERRS_USE_NORMAL = [ERR_USE_NORMAL_FIRST, ERR_LIKELY_WRONG_NORMAL];
+
+function checkDownloadable() {
+ var href = checkSelection();
+ console.log("check result", href)
+ if (ERRS_USE_NORMAL.includes(href)) {
+ $('#download').text("Normal Soundhax");
+ } else if (href === ERR_INVALID_INPUT) {
+ $('#download').text("Invalid Input");
+ } else if (href === ERR_NOT_SUPPORTED) {
+ $('#download').text("Not Supported");
+ } else {
+ $('#download').text("Download M4A");
+ }
+ if (typeof href === "string" || ERRS_USE_NORMAL.includes(href)) {
+ $('#download').addClass('active');
+ } else {
+ $('#download').removeClass('active');
+ }
+}
+
+$('button.group').on('click', function() {
+ if ($(this).parent().hasClass('forced')) {
+ return;
+ }
+ if ($(this).hasClass('selected')) {
+ $(this).removeClass('selected');
+ } else {
+ $(this).siblings().removeClass('selected');
+ $(this).addClass('selected');
+ }
+
+ checkDownloadable();
+});
+
+$('select').on('change', function() {
+ checkDownloadable();
+});
+
+function regionFN(region) {
+ switch (region) {
+ case "E":
+ return "eur";
+ case "U":
+ return "usa";
+ case "J":
+ return "jpn";
+ case "K":
+ return "kor";
+ case "C":
+ return "chn";
+ case "T":
+ return "twn";
+ }
+}
+
+function updateConsoleSelector(region, show) {
+ if (["C", "T"].includes(region)) {
+ show = false;
+ }
+ if (show) {
+ $('.console').show();
+ } else {
+ $('.console').hide();
+ if (!$('.console').hasClass("forced")) {
+ $('.console').children().removeClass('selected');
+ }
+ }
+}
+
+function checkSelection() {
+ // Possible max minor for each major, major as key
+ var major_minor_map = {
+ 0: -1, // invalidate all 0.x
+ 1: 1,
+ 2: 2,
+ 3: 1,
+ 4: 5,
+ 5: 1,
+ 6: 4,
+ 7: 2,
+ 8: 1,
+ 9: 9,
+ 10: 7,
+ 11: 17
+ };
+
+ var error = $('.error').children('.selected').attr('id');
+ var console_ = $('.console').children('.selected').attr('id');
+ var major = parseInt($('#major').val());
+ var minor = parseInt($('#minor').val());
+ var nver = parseInt($('#nver').val());
+ var region = $('#region').val();
+
+ updateConsoleSelector(region, major >= 8);
+
+ if (major == 11 && minor == 17 && ["K", "C", "T"].includes(region)) {
+ return ERR_INVALID_INPUT;
+ }
+
+ var minor_max = major_minor_map[major];
+ if (!isNaN(minor_max) && minor > minor_max) {
+ return ERR_INVALID_INPUT;
+ }
+
+ if (console_ === "n3ds") {
+ return ERR_USE_NORMAL_FIRST;
+ }
+
+ if (["K", "C", "T"].includes(region)) {
+ return ERR_USE_NORMAL_FIRST;
+ }
+
+ switch (nver) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ console.log("nver 0-3")
+ if (major < 2 || (major == 2 && minor <= 1)) {
+ switch (error) {
+ case "unplayable":
+ // very unlikely to have v1027 sound app in this case?
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-pre2.1");
+ case "crash":
+ return ERR_INVALID_INPUT; // WTF
+ default:
+ return ERR_USE_NORMAL_FIRST;
+ }
+ } else if (major < 5) {
+ switch (error) {
+ case "unplayable":
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-pre2.1");
+ case "crash":
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-v2.1and2.2");
+ default:
+ return ERR_USE_NORMAL_FIRST;
+ }
+ } else if (major < 11 || (major == 11 && minor <= 3)) {
+ switch (error) {
+ case "unplayable":
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-pre2.1-post5franken");
+ case "crash":
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-v2.1and2.2-post5franken");
+ default:
+ return ERR_USE_NORMAL_FIRST;
+ }
+ } else if ((major == 11 && minor > 3) || major > 11) {
+ return ERR_NOT_SUPPORTED;
+ }
+ case 4:
+ console.log("nver 4")
+ if (major < 2 || (major == 2 && minor < 1)) {
+ return ERR_INVALID_INPUT; // WTF
+ } else if (major == 2 && minor == 1) {
+ switch (error) {
+ case "unplayable":
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-v2.1and2.2");
+ case "crash":
+ return ERR_INVALID_INPUT; // WTF
+ default:
+ return ERR_USE_NORMAL_FIRST;
+ }
+ } else if (major < 5) {
+ switch (error) {
+ case "unplayable":
+ return ERR_LIKELY_WRONG_NORMAL;
+ case "crash":
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-v2.1and2.2");
+ default:
+ return ERR_USE_NORMAL_FIRST;
+ }
+ } else if (major < 11 || (major == 11 && minor <= 3)) {
+ switch (error) {
+ case "unplayable":
+ return ERR_LIKELY_WRONG_NORMAL;
+ case "crash":
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-v2.1and2.2-post5franken");
+ default:
+ return ERR_USE_NORMAL_FIRST;
+ }
+ } else if ((major == 11 && minor > 3) || major > 11) {
+ return ERR_NOT_SUPPORTED;
+ }
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ console.log("nver 5-10");
+ if (major < 5) {
+ switch (error) {
+ case "unplayable":
+ case "crash":
+ return ERR_LIKELY_WRONG_NORMAL;
+ default:
+ return ERR_USE_NORMAL_FIRST;
+ }
+ } else if (major < 11 || (major == 11 && minor <= 3)) {
+ switch (error) {
+ case "unplayable":
+ case "crash":
+ return ERR_LIKELY_WRONG_NORMAL;
+ default:
+ return ERR_USE_NORMAL_FIRST;
+ }
+ } else if ((major == 11 && minor > 3) || major > 11) {
+ return ERR_NOT_SUPPORTED;
+ }
+ default:
+ if (nver < 37) {
+ console.log("nver 11-36");
+ switch (error) {
+ case "unplayable":
+ case "crash":
+ return ERR_NOT_SUPPORTED;
+ default:
+ return "soundhax-{0}-{1}.m4a".format(regionFN(region), "o3ds-post5.0");
+ }
+ } else {
+ console.log("nver 37+");
+ return ERR_NOT_SUPPORTED;
+ }
+ }
+}
+checkDownloadable();
+
+$('#download').on('click', function() {
+ if (!$(this).hasClass('active')) {
+ return;
+ }
+
+ var href = checkSelection();
+ if (ERRS_USE_NORMAL.includes(href)) {
+ if (href === ERR_LIKELY_WRONG_NORMAL) {
+ alert("You likely chosed wrong file previously in normal soundhax, make sure you select it correctly and try again.");
+ }
+ //window.location.href = "index.html";
+ window.location.href = "http://soundhax.com";
+ } else if (typeof href === "string") {
+ var base = "https://github.com/danny8376/soundhax/raw/frankenfirmware/";
+ window.location.href = base + href;
+ }
+});
+
+function forceOptionSelected(id) {
+ $('#' + id).trigger("click");
+ $('#' + id).parent().addClass("forced");
+ //$('#' + id).parent().hide();
+}
+
+$.each(["unplayable", "crash"], function(idx, opt) {
+ if (location.search.includes(opt)) {
+ forceOptionSelected(opt);
+ }
+});
diff --git a/exp.py b/exp.py
index b8e8527..cd6a6f2 100644
--- a/exp.py
+++ b/exp.py
@@ -9,6 +9,7 @@
REGION = "usa"
TYPE = "old"
FIRM = "post5"
+POST5FRANKEN = False
if len(sys.argv) > 1:
REGION = sys.argv[1].lower()
@@ -18,6 +19,9 @@
if len(sys.argv) > 3:
FIRM = sys.argv[3].lower()
+if len(sys.argv) > 4:
+ POST5FRANKEN = sys.argv[4].lower() == "true"
+
# Check for impossible combinations
if TYPE not in ("old", "new"):
print("Error: invalid console type: {}".format(TYPE))
@@ -31,6 +35,9 @@
if FIRM in ("pre21", "v21and22") and REGION not in ("usa", "eur", "jpn"):
print("Error: {} can only be used for USA/EUR/JPN regions".format(FIRM))
sys.exit(1)
+if FIRM in ("v3xand4x", "post5") and POST5FRANKEN:
+ print("Error: use normal \"post5\", no need for franken build")
+ sys.exit(1)
constants = {
"pre21": constants_pre_21,
@@ -112,7 +119,7 @@ def code_va_to_pa(va):
off = va - 0x00100000
appmem_end = 0x24000000 if TYPE == "old" else 0x27C00000
- if FIRM == "post5" or TYPE == "new":
+ if FIRM == "post5" or TYPE == "new" or POST5FRANKEN:
return appmem_end - 0x00200000 + off
else:
return appmem_end - code_image_size + off
@@ -272,9 +279,15 @@ def internal(tree):
else:
assert TYPE == "old"
if FIRM == "pre21":
- fn = './soundhax-{}-{}-{}.m4a'.format(REGION, "o3ds", "pre2.1")
+ if POST5FRANKEN:
+ fn = './soundhax-{}-{}-{}-post5franken.m4a'.format(REGION, "o3ds", "pre2.1")
+ else:
+ fn = './soundhax-{}-{}-{}.m4a'.format(REGION, "o3ds", "pre2.1")
elif FIRM == "v21and22":
- fn = './soundhax-{}-{}-{}.m4a'.format(REGION, "o3ds", "v2.1and2.2")
+ if POST5FRANKEN:
+ fn = './soundhax-{}-{}-{}-post5franken.m4a'.format(REGION, "o3ds", "v2.1and2.2")
+ else:
+ fn = './soundhax-{}-{}-{}.m4a'.format(REGION, "o3ds", "v2.1and2.2")
elif FIRM == "v3xand4x":
fn = './soundhax-{}-{}-{}.m4a'.format(REGION, "o3ds", "v3.xand4.x")
else :
diff --git a/generate_all.sh b/generate_all.sh
index 57f8337..bc50511 100755
--- a/generate_all.sh
+++ b/generate_all.sh
@@ -3,33 +3,45 @@
# There is no New3DS model for CHN/TWN
# N3DS (post5)
-python exp.py usa new
-python exp.py eur new
-python exp.py jpn new
-python exp.py kor new
+python2 exp.py usa new
+python2 exp.py eur new
+python2 exp.py jpn new
+python2 exp.py kor new
# O3DS (post5)
-python exp.py usa old post5
-python exp.py eur old post5
-python exp.py jpn old post5
-python exp.py kor old post5
-python exp.py chn old post5
-python exp.py twn old post5
+python2 exp.py usa old post5
+python2 exp.py eur old post5
+python2 exp.py jpn old post5
+python2 exp.py kor old post5
+python2 exp.py chn old post5
+python2 exp.py twn old post5
# O3DS (v3xand4x)
-python exp.py usa old v3xand4x
-python exp.py eur old v3xand4x
-python exp.py jpn old v3xand4x
-python exp.py kor old v3xand4x
-python exp.py chn old v3xand4x
-python exp.py twn old v3xand4x
+python2 exp.py usa old v3xand4x
+python2 exp.py eur old v3xand4x
+python2 exp.py jpn old v3xand4x
+python2 exp.py kor old v3xand4x
+python2 exp.py chn old v3xand4x
+python2 exp.py twn old v3xand4x
# O3DS (v21and22)
-python exp.py usa old v21and22
-python exp.py eur old v21and22
-python exp.py jpn old v21and22
+python2 exp.py usa old v21and22
+python2 exp.py eur old v21and22
+python2 exp.py jpn old v21and22
# O3DS (pre21)
-python exp.py usa old pre21
-python exp.py eur old pre21
-python exp.py jpn old pre21
+python2 exp.py usa old pre21
+python2 exp.py eur old pre21
+python2 exp.py jpn old pre21
+
+# ==== FRANKENFIRMWARE ====
+
+# O3DS (v21and22)
+python2 exp.py usa old v21and22 true
+python2 exp.py eur old v21and22 true
+python2 exp.py jpn old v21and22 true
+
+# O3DS (pre21)
+python2 exp.py usa old pre21 true
+python2 exp.py eur old pre21 true
+python2 exp.py jpn old pre21 true
diff --git a/soundhax-eur-o3ds-pre2.1-post5franken.m4a b/soundhax-eur-o3ds-pre2.1-post5franken.m4a
new file mode 100644
index 0000000..3444852
Binary files /dev/null and b/soundhax-eur-o3ds-pre2.1-post5franken.m4a differ
diff --git a/soundhax-eur-o3ds-v2.1and2.2-post5franken.m4a b/soundhax-eur-o3ds-v2.1and2.2-post5franken.m4a
new file mode 100644
index 0000000..03a8f2b
Binary files /dev/null and b/soundhax-eur-o3ds-v2.1and2.2-post5franken.m4a differ
diff --git a/soundhax-jpn-o3ds-pre2.1-post5franken.m4a b/soundhax-jpn-o3ds-pre2.1-post5franken.m4a
new file mode 100644
index 0000000..6b93534
Binary files /dev/null and b/soundhax-jpn-o3ds-pre2.1-post5franken.m4a differ
diff --git a/soundhax-jpn-o3ds-v2.1and2.2-post5franken.m4a b/soundhax-jpn-o3ds-v2.1and2.2-post5franken.m4a
new file mode 100644
index 0000000..0f7c173
Binary files /dev/null and b/soundhax-jpn-o3ds-v2.1and2.2-post5franken.m4a differ
diff --git a/soundhax-usa-o3ds-pre2.1-post5franken.m4a b/soundhax-usa-o3ds-pre2.1-post5franken.m4a
new file mode 100644
index 0000000..57fadb7
Binary files /dev/null and b/soundhax-usa-o3ds-pre2.1-post5franken.m4a differ
diff --git a/soundhax-usa-o3ds-v2.1and2.2-post5franken.m4a b/soundhax-usa-o3ds-v2.1and2.2-post5franken.m4a
new file mode 100644
index 0000000..8caf6c9
Binary files /dev/null and b/soundhax-usa-o3ds-v2.1and2.2-post5franken.m4a differ