Compare commits

...
Author SHA1 Message Date
Tyler Wilding 637b043293 deps: update zydis to latest commit (#3306)
Updates Zydis to it's latest commit, this should fix building the
project on intel macs with a more recent version of macOS. This likely
needs some sanity checks that the debugger stuff still works as
expected.
2024-01-15 16:56:14 -05:00
ManDude 46db6a36da [pckernel] use pc-get-resolution to fetch initial fullscreen resolution (#3307)
This is the more correct way of doing what that code is trying to do.
Fixes #3296

Also fixed some type inconsistencies with related code, probably wasn't
causing issues though.

May also fix the "black screen on startup" issues people keep having,
but that would simply be a nice bonus and isn't the aim of this PR.
2024-01-15 18:53:49 +00:00
Hat Kid 619f39d3b7 custom levels: enum lump support (#3305)
This adds support for using enums in lumps using the new lump types
`enum-int32` and `enum-uint32`. Also adds these other new lump types:

- `water-height` (takes 3 meter floats, an enum and another optional
meter float)
- `eco-info` (takes an enum and an int)
- `vector3m` (3 meter floats + `w` set to 1.0)
2024-01-15 12:46:42 +01:00
Matt Dallmeyer 2071c98b55 Fix cases of string formatting with non string literals (#3304)
The logger used in `goalc` tries to print an already-formatted string
`message` using `fmt::print(message);` Usually this doesn't cause
problems, but if you try to print, for example, an exception that has
special characters (notably `{`) it will try to do another round of
formatting/replacements, despite not having any args to replace with,
which ends up throwing another exception. This is why errors when
parsing custom level JSON cause the REPL to exit.

I've hopefully identified all the various instances of this across the
codebase
2024-01-14 12:02:08 +00:00
ManDude 7a8aa71204 [jak2] implement statistics tracker (#3288)
Currently only tracks enemy kills, and how they were killed. There is
currently no menu for this, but I've already added most of the text for
it. Also did a bunch of misc decompilation fixes and renamed some
methods.

Fixes #3277 
Fixes #3278
2024-01-11 22:49:41 +00:00
Tyler Wilding a80cff9a4c game: Fix issues related to remapping with SDL axii's (ie. triggers) (#3294)
This was just not implemented end to end. There are still two notable
issues, one that I can live with, one I need to narrow down eventually:
1. Rebinding confirm buttons with trigger (ie. X) behaviour is not 100%
as it should be. I fixed it enough that I can live with it but it's
still not proper. The difficulty is that unlike a button it will
re-trigger the pressed state on the journey back to neutral (aka
unpressed).
2. If you change the bind for the confirm button, then reset your
bindings, the next confirm input is eaten. This is unrelated to these
changes but I briefly looked into it and was unable to find the root
cause.
2024-01-09 16:50:58 -05:00
Tyler Wilding 4cccaf2645 d/j3: all-types: guess at associated process for non-virtual states and fix some issues along the way (#3300)
This will make a best effort attempt at guessing which process a
non-virtual state belongs to:
![Screenshot 2024-01-08
195309](https://github.com/open-goal/jak-project/assets/13153231/69132f10-823d-4df5-b2d6-662d4dd754a0)

I also noticed some issues while working on this, mainly around how
virtual states were being output. They were being duplicated, for
example:
![Screenshot 2024-01-08
184733](https://github.com/open-goal/jak-project/assets/13153231/1edb0f1a-3ac7-46cb-96cd-cf93d42fb01f)
or
![Screenshot 2024-01-08
193730](https://github.com/open-goal/jak-project/assets/13153231/45673653-4000-45bb-af00-9baa6e2a70ae)

I think I've fixed that, but @Hat-Kid I defer to you to see if i've done
something terrible.
![Screenshot 2024-01-08
194513](https://github.com/open-goal/jak-project/assets/13153231/75543d2e-69da-4bbd-b143-2f824b9d8dde)
2024-01-09 16:50:05 -05:00
Matt Dallmeyer 9d680a0aba Support extracting collision to obj for jak2/3 formats (#3292)
![image](https://github.com/open-goal/jak-project/assets/2515356/b4d43254-4fc4-4f66-92d1-0d61e471b90e)

![image](https://github.com/open-goal/jak-project/assets/2515356/d2fa9fb8-5f51-43c5-8e0e-b51b64499b72)
2024-01-05 09:36:09 +01:00
dependabot[bot] b0713641e7 build(deps): bump actions/download-artifact from 3 to 4 (#3283)
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 3 to 4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<p>The release of upload-artifact@v4 and download-artifact@v4 are major
changes to the backend architecture of Artifacts. They have numerous
performance and behavioral improvements.</p>
<p>For more information, see the <a
href="https://github.com/actions/toolkit/tree/main/packages/artifact"><code>@​actions/artifact</code></a>
documentation.</p>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/bflad"><code>@​bflad</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/download-artifact/pull/194">actions/download-artifact#194</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/download-artifact/compare/v3...v4.0.0">https://github.com/actions/download-artifact/compare/v3...v4.0.0</a></p>
<h2>v3.0.2</h2>
<ul>
<li>Bump <code>@actions/artifact</code> to v1.1.1 - <a
href="https://redirect.github.com/actions/download-artifact/pull/195">actions/download-artifact#195</a></li>
<li>Fixed a bug in Node16 where if an HTTP download finished too quickly
(&lt;1ms, e.g. when it's mocked) we attempt to delete a temp file that
has not been created yet <a
href="hhttps://redirect.github.com/actions/toolkit/pull/1278">actions/toolkit#1278</a></li>
</ul>
<h2>v3.0.1</h2>
<ul>
<li><a
href="https://redirect.github.com/actions/download-artifact/pull/178">Bump
<code>@​actions/core</code> to 1.10.0</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/download-artifact/commit/f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110"><code>f44cd7b</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/259">#259</a>
from actions/robherley/glob-downloads</li>
<li><a
href="https://github.com/actions/download-artifact/commit/3181fe853d2c9a606cd326853bf4c5b8ced5df02"><code>3181fe8</code></a>
add some migration docs</li>
<li><a
href="https://github.com/actions/download-artifact/commit/aaaac7b403f278b6b7eebdca69ca1658616f1c57"><code>aaaac7b</code></a>
licensed cache</li>
<li><a
href="https://github.com/actions/download-artifact/commit/7c9182f0e18dadedfbca3189ab7a22a416aa6714"><code>7c9182f</code></a>
update readme</li>
<li><a
href="https://github.com/actions/download-artifact/commit/b94e7015566b40b2de5eeeda514f239968da2dd7"><code>b94e701</code></a>
licensed cache</li>
<li><a
href="https://github.com/actions/download-artifact/commit/0b55470e40ab7435f445813ebc18b1107ecf7e32"><code>0b55470</code></a>
add test case for globbed downloads to same directory</li>
<li><a
href="https://github.com/actions/download-artifact/commit/0b51c2ef9042b581aded9711127e4a6d5f71c550"><code>0b51c2e</code></a>
update prettier/eslint versions</li>
<li><a
href="https://github.com/actions/download-artifact/commit/c4c6db724f9510b2b3cff5ebcc417c87a2b2fa97"><code>c4c6db7</code></a>
support globbing artifact list &amp; merging download directory</li>
<li><a
href="https://github.com/actions/download-artifact/commit/1bd0606e08fcaa4c28afc1fc7d45830ab5482dac"><code>1bd0606</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/252">#252</a>
from stchr/patch-1</li>
<li><a
href="https://github.com/actions/download-artifact/commit/eff4d42b1f6ff704c7a0f37152ed8793673560ef"><code>eff4d42</code></a>
fix default for run-id</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/download-artifact/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-04 01:32:49 -05:00
dependabot[bot] aa68b80da2 build(deps): bump actions/upload-artifact from 3 to 4 (#3284)
Bumps
[actions/upload-artifact](https://github.com/actions/upload-artifact)
from 3 to 4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<p>The release of upload-artifact@v4 and download-artifact@v4 are major
changes to the backend architecture of Artifacts. They have numerous
performance and behavioral improvements.</p>
<p>For more information, see the <a
href="https://github.com/actions/toolkit/tree/main/packages/artifact"><code>@​actions/artifact</code></a>
documentation.</p>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/vmjoseph"><code>@​vmjoseph</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/464">actions/upload-artifact#464</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v3...v4.0.0">https://github.com/actions/upload-artifact/compare/v3...v4.0.0</a></p>
<h2>v3.1.3</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(github): remove trailing whitespaces by <a
href="https://github.com/ljmf00"><code>@​ljmf00</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/313">actions/upload-artifact#313</a></li>
<li>Bump <code>@​actions/artifact</code> version to v1.1.2 by <a
href="https://github.com/bethanyj28"><code>@​bethanyj28</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/436">actions/upload-artifact#436</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v3...v3.1.3">https://github.com/actions/upload-artifact/compare/v3...v3.1.3</a></p>
<h2>v3.1.2</h2>
<ul>
<li>Update all <code>@actions/*</code> NPM packages to their latest
versions- <a
href="https://redirect.github.com/actions/upload-artifact/issues/374">#374</a></li>
<li>Update all dev dependencies to their most recent versions - <a
href="https://redirect.github.com/actions/upload-artifact/issues/375">#375</a></li>
</ul>
<h2>v3.1.1</h2>
<ul>
<li>Update actions/core package to latest version to remove
<code>set-output</code> deprecation warning <a
href="https://redirect.github.com/actions/upload-artifact/issues/351">#351</a></li>
</ul>
<h2>v3.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@​actions/artifact</code> to v1.1.0 (<a
href="https://redirect.github.com/actions/upload-artifact/pull/327">actions/upload-artifact#327</a>)
<ul>
<li>Adds checksum headers on artifact upload (<a
href="https://redirect.github.com/actions/toolkit/pull/1095">actions/toolkit#1095</a>)
(<a
href="https://redirect.github.com/actions/toolkit/pull/1063">actions/toolkit#1063</a>)</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/c7d193f32edcb7bfad88892161225aeda64e9392"><code>c7d193f</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/466">#466</a>
from actions/v4-beta</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/13131bb095770b4070a7477c3cd2d96e1c16d9f4"><code>13131bb</code></a>
licensed cache</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/4a6c273b9834f66a1d05c170dc3f80f9cdb9def1"><code>4a6c273</code></a>
Merge branch 'main' into v4-beta</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/f391bb91a3d3118aeca171c365bb319ece276b37"><code>f391bb9</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/465">#465</a>
from actions/robherley/v4-documentation</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/9653d03c4b74c32144e02dae644fea70e079d4b3"><code>9653d03</code></a>
Apply suggestions from code review</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/875b63076402f25ef9d52c294c86ba4f97810575"><code>875b630</code></a>
add limitations section</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/ecb21463e93740a6be75c3116242169bfdbcb15a"><code>ecb2146</code></a>
add compression example</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/5e7604f84a055838f64ed68bb9904751523081ae"><code>5e7604f</code></a>
trim some repeated info</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/d6437d07581fe318a364512e6cf6b1dca6b4f92c"><code>d6437d0</code></a>
naming</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/1b561557037b4957d7d184e9aac02bec86c771eb"><code>1b56155</code></a>
s/v4-beta/v4/g</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/upload-artifact/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-04 01:32:40 -05:00
Ziemas 6901e80e7f j2-overlord: Clean up some VAG functions (#3287)
Some cleanup of vag related functions in overlord.
2024-01-02 16:30:56 +00:00
EvelynTSMG 12118e57cb Impr: Make mesh extract compatible with gLTF 2.0 (and Blender 4.0) (#3268)
:3
2024-01-01 16:30:48 -05:00
ManDude 349919f788 [jak2] implement pc cheats in menu (#3275)
Adds the opengoal cheats to the secrets menu. Only cheats that are fully
functional and unlockable are there right now, which is eight cheats.

This update will reset most Jak 2 settings.

Also fixes #3274 .
2023-12-28 11:14:10 +00:00
ManDude a01d78c7d4 [jak2] fix shadow origin using wrong joint (#3271)
Copypasta. Fixes #3269
2023-12-22 16:52:53 +00:00
Tyler Wilding 708c15788b g/j2: switch to OpenGOAL speedrun.com leaderboards (#3265)
Boards that have no runs yet look kinda awkward but i'd rather just wait
until those fill out (won't take long) rather than add another string to
be translated.
2023-12-19 19:06:55 -05:00
Tyler Wilding 6cfb89a78a g/j2: fix interleaving of local and external highscores (#3264)
Local scores weren't going above external scores even if they were
higher, a few test cases:

![Screenshot 2023-12-19
182412](https://github.com/open-goal/jak-project/assets/13153231/bf3c700d-0f23-441e-b537-88794532523b)
![Screenshot 2023-12-19
182446](https://github.com/open-goal/jak-project/assets/13153231/18d5d6eb-54b1-466e-8302-ca629677344f)
![Screenshot 2023-12-19
182442](https://github.com/open-goal/jak-project/assets/13153231/7de763a5-3587-416f-8755-1868049b92ed)
![Screenshot 2023-12-19
182421](https://github.com/open-goal/jak-project/assets/13153231/d44c1b5b-5f4f-4151-a1f0-e28d7612ed9d)
2023-12-19 18:58:25 -05:00
Tyler Wilding 99da5da441 g/j2: save window-size to pc-settings when it's changed (#3263)
Fixes #3262
2023-12-19 18:56:49 -05:00
RoyalForgottenandTyler Wilding c7af284c6b French subtitle_lines_fr-FR.json (#3259)
French subtitles complete + fixed some wrong texts

---------

Co-authored-by: Tyler Wilding <[email protected]>
2023-12-19 18:55:51 -05:00
Matt Dallmeyer 3e568cb95d Disable save_texture_pngs by default [jak1] (#3256) 2023-12-18 18:25:51 -05:00
tripp 4b9c1dde70 add ms to loader output (#3261) 2023-12-18 18:17:27 -05:00
OpenGOAL BotandOpenGOALBot 35daebcce7 CI: Periodic Controller Database Update (#3255)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2023-12-18 18:17:10 -05:00
ManDude 897e9c588b fix weird potential initialization bug with the music log (#3258) 2023-12-12 23:34:14 +00:00
water111 f17427bc26 [jak2] Fix unicode issue with GAME.CGO load (#3254)
Fix for https://github.com/open-goal/jak-project/issues/3244
2023-12-09 18:11:24 -05:00
Ziemas 168afa0e2e 989snd: sound bank loading overhaul (#3185) 2023-12-07 20:22:54 -05:00
Hat Kid 9b6f16f561 jak2: 90 fps menu option (#3245)
Closes #3223
2023-12-03 21:32:21 +01:00
ManDude 1808596679 save & load game territory setting (#3243) 2023-12-03 18:19:38 +00:00
ManDude 94b984326f [jak2] add game territory menu option (#3242) 2023-12-03 16:16:05 +00:00
ManDude 2795d3aa67 [jak2] fix health bar color fading (#3241)
Fixes #3237
2023-12-03 09:42:01 +00:00
ManDude be6a6dead4 [jak2] fix use-after-free bug in nav enemies (#3240)
Fixes #3153
2023-12-03 09:24:34 +00:00
ManDude 974f5931de [jak2] add resolutions menu (#3238) 2023-12-03 08:11:18 +00:00
Brent Hickey e119a66788 [jak2] Support STICK_DEADZONE (#3239)
fixes #3235
2023-12-03 08:11:10 +00:00
SuperSamusandMartino Fontana 37069e2f8e [jak2] Fix "Select controller" (#3191)
Co-authored-by: Martino Fontana <[email protected]>
2023-12-02 15:20:26 -05:00
Hat KidandTyler Wilding dfa6622544 jak2: add vehicle hijack lines PC cheat (#3205)
Co-authored-by: Tyler Wilding <[email protected]>
2023-12-02 15:17:54 -05:00
Luminar Light a3af37989b Allow replacing all instances of a texture with one texture (#3234)
There are art groups that are present in multiple levels, and that means
that also their textures are present in multiple levels. With texture
replacement, currently we need to make replacements for all instances if
we want it replaced everywhere, but this is not ideal, especially when
you make changes to your replacement texture and now you have to put it
in each folder again.

I added a way to replace all instances of a texture, by letting
texture-replacer people put their replacements into an '_all' folder. I
set up the logic in such a way that if you have a replacement for the
texture in its corresponding folder, it will take priority over a
replacement that you placed into the '_all' folder.

I personally found this very useful for replacing guard textures. The
guards appear in a lot of levels. But ideally you want them to look the
same everywhere. And that is why I looked into this and made a PR.

Oh and I changed what is printed in the 'Replacing ' part because it was
printing the path to our replacement, which didn't look nicely when
several textures got replaced by the same replacement from the '_all'
folder. So now it will print the original texture's page and name, I
think this information is more useful anyway.
2023-12-02 12:17:47 -05:00
water111 a01182315b [jak2] Support per-proto shrub visibility (#3228)
Fixes the issue reported in
https://github.com/open-goal/jak-project/issues/3168,
https://github.com/open-goal/jak-project/issues/3189,
https://github.com/open-goal/jak-project/issues/3166,
https://github.com/open-goal/jak-project/issues/3152,
https://github.com/open-goal/jak-project/issues/3224 where a small part
of the pipes in the `strip-grenade` mission appear, but shouldn't.
2023-12-02 12:16:14 -05:00
ManDude e38fe70ac4 [jak2] split language and text language (#3233) 2023-11-29 23:28:53 +00:00
ManDude 956645bdb9 [jak2] adjust progress generic item sizes + add scrolling effect (#3231)
Makes most of the options larger to reduce the amount of dead space and
adds a smooth scrolling effect instead of having "pages".


![imagem](https://github.com/open-goal/jak-project/assets/7569514/fc483dea-226c-44ff-96e0-680e89a6df81)

Button remap menu has no scrolling. Fixes #2984
2023-11-29 18:27:02 +00:00
582 changed files with 44799 additions and 28312 deletions

No files matched your search

+1 -1
View File
@@ -63,7 +63,7 @@ jobs:
python ./scripts/docs/append-file-docs.py
- name: Upload Docs Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: opengoal-docs
if-no-files-found: error
+1 -1
View File
@@ -71,7 +71,7 @@ jobs:
strip ./build/lsp/lsp
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: ${{ inputs.uploadArtifacts }}
with:
name: opengoal-linux-${{ inputs.cachePrefix }}
+1 -1
View File
@@ -55,7 +55,7 @@ jobs:
run: ./test.sh
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: opengoal-macos-${{ inputs.cachePrefix }}
if-no-files-found: error
+1 -1
View File
@@ -64,7 +64,7 @@ jobs:
strip ./build/lsp/lsp
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: ${{ inputs.uploadArtifacts }}
with:
name: opengoal-macos-${{ inputs.cachePrefix }}
+1 -1
View File
@@ -51,7 +51,7 @@ jobs:
- name: Prepare Artifact Folder
run: mkdir -p ./ci-artifacts/final
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
name: Download all Artifacts
with:
path: ./ci-artifacts/
+1 -1
View File
@@ -71,7 +71,7 @@ jobs:
run: ./build/bin/goalc-test.exe --gtest_color=yes --gtest_brief=0 --gtest_filter="-*MANUAL_TEST*"
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: ${{ inputs.uploadArtifacts }}
with:
name: opengoal-windows-${{ inputs.cachePrefix }}
+13
View File
@@ -218,6 +218,19 @@
"--config-override \"{\\\"decompile_code\\\": false, \\\"levels_extract\\\": true, \\\"allowed_objects\\\": []}\""
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "decompiler.exe (bin\\decompiler.exe)",
"name": "Decompiler - Jak 3",
"args": [
"${workspaceRoot}/decompiler/config/jak3/jak3_config.jsonc",
"${workspaceRoot}/iso_data",
"${workspaceRoot}/decompiler_out",
"--version",
"ntsc_v1"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
+1 -1
View File
@@ -5,7 +5,7 @@
"comments": true,
"strings": true
},
"editor.wordBasedSuggestions": true,
"editor.wordBasedSuggestions": "matchingDocuments",
"editor.snippetSuggestions": "top"
},
"python.formatting.provider": "black",
+4
View File
@@ -42,6 +42,7 @@ void ShrubDraw::serialize(Serializer& ser) {
ser.from_ptr(&num_triangles);
ser.from_ptr(&first_index_index);
ser.from_ptr(&num_indices);
ser.from_ptr(&proto_idx);
}
void InstancedStripDraw::serialize(Serializer& ser) {
@@ -416,6 +417,9 @@ void ShrubTree::serialize(Serializer& ser) {
for (auto& draw : static_draws) {
draw.serialize(ser);
}
ser.from_ptr(&has_per_proto_visibility_toggle);
ser.from_string_vector(&proto_names);
}
void BVH::serialize(Serializer& ser) {
+7 -1
View File
@@ -18,7 +18,7 @@ namespace tfrag3 {
// - if changing any large things (vertices, vis, bvh, colors, textures) update get_memory_usage
// - if adding a new category to the memory usage, update extract_level to print it.
constexpr int TFRAG3_VERSION = 38;
constexpr int TFRAG3_VERSION = 39;
enum MemoryUsageCategory {
TEXTURE,
@@ -219,6 +219,8 @@ struct ShrubDraw {
// for debug counting.
u32 num_triangles = 0;
u16 proto_idx = 0;
void serialize(Serializer& ser);
};
@@ -430,6 +432,10 @@ struct ShrubTree {
std::vector<ShrubGpuVertex> vertices; // mesh vertices
} unpacked;
// jak 2 and later can toggle on and off visibility per proto by name
bool has_per_proto_visibility_toggle = false;
std::vector<std::string> proto_names;
void serialize(Serializer& ser);
void memory_usage(MemoryUsageTracker* tracker) const;
void unpack();
+2 -2
View File
@@ -21,8 +21,8 @@ struct FormFormattingConfig {
bool combine_first_two_lines =
false; // NOTE - basically hang, but will probably stick around after hang is gone, may be
// redundant (inline_until_index!)
std::function<std::optional<int>(const std::vector<std::string>& curr_lines)> inline_until_index =
[](std::vector<std::string> curr_lines) { return std::nullopt; };
std::function<std::optional<int>(const std::vector<std::string>& /*curr_lines*/)>
inline_until_index = [](std::vector<std::string> /*curr_lines*/) { return std::nullopt; };
bool has_constant_pairs = false;
bool prevent_inlining = false; // TODO - duplicate of below
std::function<bool(FormFormattingConfig, int num_refs)> should_prevent_inlining =
+1 -1
View File
@@ -1888,7 +1888,7 @@ Object Interpreter::eval_format(const Object& form,
fmt::format_args(args2.data(), static_cast<unsigned>(args2.size())));
if (truthy(dest)) {
lg::print(formatted.c_str());
lg::print("{}", formatted.c_str());
}
return StringObject::make_new(formatted);
+1 -1
View File
@@ -106,7 +106,7 @@ void log_print(const char* message) {
}
if (gLogger.stdout_log_level < lg::level::off_unless_die) {
fmt::print(message);
fmt::print("{}", message);
fflush(stdout);
fflush(stderr);
}
@@ -373,7 +373,7 @@ bool GameSubtitleDB::write_subtitle_db_to_files(const GameVersion game_version)
file_util::write_text_file(dump_path, lines_file.dump(2));
}
} catch (std::exception& ex) {
lg::error(ex.what());
lg::error("{}", ex.what());
return false;
}
return true;
+2 -2
View File
@@ -16,12 +16,12 @@ void private_assert_failed(const char* expr,
if (!msg || msg[0] == '\0') {
std::string log = fmt::format("Assertion failed: '{}'\n\tSource: {}:{}\n\tFunction: {}\n", expr,
file, line, function);
lg::die(log);
lg::die("{}", log);
} else {
std::string log =
fmt::format("Assertion failed: '{}'\n\tMessage: {}\n\tSource: {}:{}\n\tFunction: {}\n",
expr, msg, file, line, function);
lg::die(log);
lg::die("{}", log);
}
abort();
}
+10 -7
View File
@@ -12,30 +12,33 @@
#include "common/common_types.h"
#include "common/util/Assert.h"
#include "third-party/span.hpp"
class BinaryReader {
public:
explicit BinaryReader(const std::vector<uint8_t>& _buffer) : m_buffer(_buffer) {}
explicit BinaryReader(nonstd::span<const uint8_t> _span) : m_span(_span) {}
template <typename T>
T read() {
ASSERT(m_seek + sizeof(T) <= m_buffer.size());
ASSERT(m_seek + sizeof(T) <= m_span.size());
T obj;
memcpy(&obj, m_buffer.data() + m_seek, sizeof(T));
memcpy(&obj, m_span.data() + m_seek, sizeof(T));
m_seek += sizeof(T);
return obj;
}
void ffwd(int amount) {
m_seek += amount;
ASSERT(m_seek <= m_buffer.size());
ASSERT(m_seek <= m_span.size());
}
uint32_t bytes_left() const { return m_buffer.size() - m_seek; }
uint8_t* here() { return m_buffer.data() + m_seek; }
uint32_t bytes_left() const { return m_span.size() - m_seek; }
const uint8_t* here() { return m_span.data() + m_seek; }
BinaryReader at(u32 pos) { return BinaryReader(m_span.subspan(pos)); }
uint32_t get_seek() const { return m_seek; }
void set_seek(u32 seek) { m_seek = seek; }
private:
std::vector<u8> m_buffer;
nonstd::span<const u8> m_span;
uint32_t m_seek = 0;
};
+1 -1
View File
@@ -21,7 +21,7 @@ void assert_string_empty_after(const char* str, int size) {
}
}
std::string get_object_file_name(const std::string& original_name, u8* data, int size) {
std::string get_object_file_name(const std::string& original_name, const u8* data, int size) {
const std::string art_group_text_strings[] = {
fmt::format("/src/next/data/art-group{}/", versions::jak1::ART_FILE_VERSION),
fmt::format("/src/jak2/final/art-group{}/", versions::jak2::ART_FILE_VERSION),
+1 -1
View File
@@ -6,4 +6,4 @@
#include "common/versions/versions.h"
void assert_string_empty_after(const char* str, int size);
std::string get_object_file_name(const std::string& original_name, u8* data, int size);
std::string get_object_file_name(const std::string& original_name, const u8* data, int size);
+24 -10
View File
@@ -20,16 +20,30 @@
// this makes collision 2x slower and bigger, so only use if really needed
"double_sided_collide": false,
// available res-lump tag data types:
// int32, float, meters, vector, vector4m (meters)
// available res-lump tag types:
// value types: int32, uint32, enum-int32, enum-uint32, float, meters (1 meter = 4096.0 units), degrees (65536.0 = 360°)
// vector types: vector (normal floats), vector4m (meters), vector3m (meters with w set to 1.0), vector-vol (normal floats with w in meters), movie-pos (meters with w in degrees)
// special types: eco-info, water-height
//
// examples:
//
// adds a float tag 'spring-height' with value of 200 meters (1 meter = 4096.0 units):
// "spring-height": ["meters", 200.0]
//
// adds a vector tag 'movie-pos':
// "movie-pos": ["vector", [4096000.0, -176128.0, 1353973.76, 1.0]]
// adds a degrees tag 'rotoffset':
// "rotoffset": ["degrees", -45.0]
//
// adds a movie-pos tag:
// "movie-pos": ["movie-pos", [100.22, -25.3, 99.5, 180.0]]
//
// adds an enum tag 'options':
// "options": ["enum-int32", "(fact-options large)"]
//
// adds a water-height tag:
// "water-height": ["water-height", 25.0, 0.5, 2.0, "(water-flags wt08 wt03 wt01)"]
//
// adds an eco-info tag:
// "eco-info": ["eco-info", "(pickup-type health)", 2]
// The base actor id for your custom level. If you have multiple levels this should be unique!
"base_id": 100,
@@ -65,7 +79,7 @@
"lump": {
"name": "test-ambient",
"type": "'hint",
"text-id": ["int32", 557], // text id for the "POWER CELL" text
"text-id": ["enum-uint32", "(text-id fuel-cell)"], // text id for the "POWER CELL" text
"play-mode": "'notice"
}
}
@@ -75,7 +89,7 @@
{
"trans": [-21.6238, 20.0496, 17.1191], // translation
"etype": "fuel-cell", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-21.6238, 19.3496, 17.1191, 10], // bounding sphere
"lump": {
@@ -86,20 +100,20 @@
{
"trans": [-15.2818, 15.2461, 17.1360], // translation
"etype": "crate", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
"lump": {
"name": "test-crate",
"crate-type": "'steel",
"eco-info": ["int32", 5, 10]
"eco-info": ["eco-info", "(pickup-type money)", 10]
}
},
{
"trans": [-5.4630, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
"lump": {
@@ -109,7 +123,7 @@
// {
// "trans": [-7.41, 3.5, 28.42], // translation
// "etype": "plat", // actor type
// "game_task": 0, // associated game task (for powercells, etc)
// "game_task": "(game-task none)", // associated game task (for powercells, etc)
// "quat": [0, 0, 0, 1], // quaternion
// "bsphere": [-7.41, 3.5, 28.42, 10], // bounding sphere
// "lump": {
+22 -9
View File
@@ -20,24 +20,37 @@
// this makes collision 2x slower and bigger, so only use if really needed
"double_sided_collide": false,
// available res-lump tag data types:
// int32, float, meters, vector, vector4m (meters)
// available res-lump tag types:
// value types: int32, uint32, enum-int32, enum-uint32, float, meters (1 meter = 4096.0 units), degrees (65536.0 = 360°)
// vector types: vector (normal floats), vector4m (meters), vector3m (meters with w set to 1.0), vector-vol (normal floats with w in meters), movie-pos (meters with w in degrees)
// special types: eco-info, water-height
//
// examples:
//
// adds a float tag 'spring-height' with value of 200 meters (1 meter = 4096.0 units):
// "spring-height": ["meters", 200.0]
//
// adds a vector tag 'movie-pos':
// "movie-pos": ["vector", [4096000.0, -176128.0, 1353973.76, 1.0]]
// adds a degrees tag 'rotoffset':
// "rotoffset": ["degrees", -45.0]
//
// adds a movie-pos tag:
// "movie-pos": ["movie-pos", [100.22, -25.3, 99.5, 180.0]]
//
// adds an enum tag 'options':
// "options": ["enum-int32", "(fact-options large)"]
//
// adds a water-height tag:
// "water-height": ["water-height", 25.0, 0.5, 2.0, "(water-flags can-swim can-wade)"]
//
// adds an eco-info tag:
// "eco-info": ["eco-info", "(pickup-type health)", 2]
// The base actor id for your custom level. If you have multiple levels, this should be unique!
"base_id": 100,
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
// Removed so that the release builds don't have to double-decompile the game
//"art_groups": ["prsn-torture-ag"],
"art_groups": [],
// "art_groups": ["prsn-torture-ag"],
// Any textures you want to include in your custom level.
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
@@ -55,14 +68,14 @@
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
"lump": {
"name": "test-crate",
"eco-info": ["int32", 18, 2]
"eco-info": ["eco-info", "(pickup-type health)", 2]
}
},
{
"trans": [-5.4630, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"kill_mask": 0,
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
@@ -74,7 +87,7 @@
{
"trans": [-7.41, 13.5, 28.42], // translation
"etype": "prsn-torture", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-7.41, 13.5, 28.42, 10], // bounding sphere
"lump": {
+3 -3
View File
@@ -3141,11 +3141,11 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
}
if (m_static_info.shadow_joint_index != 0) {
forms.push_back(pretty_print::to_symbol(
fmt::format(":shadow-joint-index {}", m_static_info.origin_joint_index)));
fmt::format(":shadow-joint-index {}", m_static_info.shadow_joint_index)));
}
if (m_static_info.light_index != 0) {
forms.push_back(pretty_print::to_symbol(
fmt::format(":light-index {}", m_static_info.origin_joint_index)));
forms.push_back(
pretty_print::to_symbol(fmt::format(":light-index {}", m_static_info.light_index)));
}
}
+2 -1
View File
@@ -222,13 +222,14 @@ class ObjectFileDB {
void ir2_setup_labels(const Config& config, ObjectFileData& data);
void ir2_run_mips2c(const Config& config, ObjectFileData& data);
struct PerObjectAllTypeInfo {
std::string object_name;
std::unordered_set<std::string> already_seen_symbols;
// type-name : { method id : state name }
std::unordered_map<std::string, std::unordered_map<int, std::string>> state_methods;
// symbol-name : type-name
std::unordered_map<std::string, std::string> symbol_types;
// state-name : type-name
std::unordered_map<std::string, std::string> non_virtual_state_guesses;
struct TypeInfo {
bool from_inspect_method = false; // does this come from an inspect method?
+61 -8
View File
@@ -10,6 +10,7 @@
#include "common/log/log.h"
#include "common/util/FileUtil.h"
#include "common/util/Timer.h"
#include "common/util/string_util.h"
#include "decompiler/IR2/Form.h"
#include "decompiler/analysis/analyze_inspect_method.h"
@@ -319,7 +320,7 @@ void ObjectFileDB::ir2_top_level_pass(const Config& config) {
void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
const std::optional<std::string>& previous_game_types,
const std::unordered_set<std::string>& bad_types) {
std::vector<PerObjectAllTypeInfo> per_object;
std::unordered_map<std::string, PerObjectAllTypeInfo> per_object;
DecompilerTypeSystem previous_game_ts(GameVersion::Jak2); // version here doesn't matter.
if (previous_game_types) {
@@ -328,16 +329,66 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
TypeInspectorCache ti_cache;
// Do a first pass to initialize all types and symbols
for_each_obj([&](ObjectFileData& data) {
if (data.obj_version == 3 || (data.obj_version == 5 && data.linked_data.has_any_functions())) {
auto& object_result = per_object.emplace_back();
object_result.object_name = data.to_unique_name();
per_object[data.to_unique_name()] = PerObjectAllTypeInfo();
// Go through the top-level segment first to identify the type names associated with each
// symbol def
for_each_function_in_seg_in_obj(TOP_LEVEL_SEGMENT, data, [&](Function& f) {
inspect_top_level_for_metadata(f, data.linked_data, dts, previous_game_ts, object_result);
inspect_top_level_for_metadata(f, data.linked_data, dts, previous_game_ts,
per_object.at(data.to_unique_name()));
});
}
});
// Guess at non-virtual state type's:
//
// Collect all type names, since the DTS doesn't know the actual type tree (all-types is empty!)
// we can't filter by what is actually a process type (with existing code).
std::unordered_map<std::string, std::vector<std::string>> all_type_names;
for (auto& [obj_name, obj_info] : per_object) {
for (const auto& type_name : obj_info.type_names_in_order) {
if (all_type_names.find(obj_name) == all_type_names.end()) {
all_type_names[obj_name] = {};
}
all_type_names[obj_name].push_back(type_name);
}
}
std::unordered_map<std::string, std::string> state_to_type_map;
for (auto& [obj_name, obj_info] : per_object) {
for (const auto& [sym_name, sym_type] : obj_info.symbol_types) {
if (sym_type == "state") {
int longest_match_length = 0;
std::string longest_match = "";
std::string longest_match_object_name = "";
// Make a best effort guess by finding the longest prefix match
for (const auto& [obj_name, type_names] : all_type_names) {
for (const auto& type_name : type_names) {
if (str_util::starts_with(sym_name, type_name) &&
type_name.length() > longest_match_length) {
longest_match_length = type_name.length();
longest_match = type_name;
longest_match_object_name = obj_name;
}
}
}
if (longest_match != "") {
if (per_object.find(longest_match_object_name) != per_object.end()) {
per_object.at(longest_match_object_name).non_virtual_state_guesses[sym_name] =
longest_match;
obj_info.already_seen_symbols.insert(sym_name);
}
}
}
}
}
// Then another to actually setup the definitions
for_each_obj([&](ObjectFileData& data) {
if (data.obj_version == 3 || (data.obj_version == 5 && data.linked_data.has_any_functions())) {
auto& object_result = per_object.at(data.to_unique_name());
// Handle the top level last, which is fine as all symbol_defs are always written after
// typedefs
@@ -368,12 +419,14 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
}
});
// Output result
std::string result;
result += ";; All Types\n\n";
for (auto& obj : per_object) {
for (auto& [obj_name, obj] : per_object) {
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
result += fmt::format(";; {:30s} ;;\n", obj.object_name);
result += fmt::format(";; {:30s} ;;\n", obj_name);
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");
for (const auto& type_name : obj.type_names_in_order) {
auto& info = obj.type_info.at(type_name);
@@ -749,7 +802,7 @@ void ObjectFileDB::ir2_insert_lets(int seg, ObjectFileData& data) {
"Error while inserting lets: {}. Make sure that the return type is not "
"none if something is actually returned.",
e.what());
lg::warn(err);
lg::warn("{}", err);
func.warnings.error(err);
}
}
+61 -56
View File
@@ -1427,10 +1427,15 @@ std::string inspect_inspect_method(Function& inspect_method,
object_file_meta);
}
std::string old_method_string(const MethodInfo& info) {
std::string old_method_string(const MethodInfo& info, const bool omit_comment = false) {
if (info.type.arg_count() > 0) {
if (info.type.base_type() == "function" || info.type.base_type() == "state") {
std::string result = fmt::format(" ;; ({} (", info.name);
std::string result;
if (omit_comment) {
result = fmt::format(" ({} (", info.name);
} else {
result = fmt::format(" ;; ({} (", info.name);
}
bool add = false;
for (int i = 0; i < (int)info.type.arg_count() - 1; i++) {
result += info.type.get_arg(i).print();
@@ -1450,6 +1455,9 @@ std::string old_method_string(const MethodInfo& info) {
}
}
if (omit_comment) {
return fmt::format(" ({} {}) weird method", info.name, info.type.print());
}
return fmt::format(" ;; ({} {}) weird method", info.name, info.type.print());
}
@@ -1637,81 +1645,75 @@ std::string TypeInspectorResult::print_as_deftype(
result.append("\n ");
}
std::string state_methods_list;
std::unordered_map<int, std::string> method_states = {};
if (object_file_meta.state_methods.count(type_name) != 0) {
method_states = object_file_meta.state_methods.at(type_name);
for (const auto& [method_id, state_name] : method_states) {
MethodInfo info;
state_methods_list += fmt::format(" {} ;; {}", state_name, method_id);
if (old_game_type && old_game_type->get_my_method(method_id, &info)) {
state_methods_list += ", old:" + old_method_string(info, true);
}
state_methods_list += "\n";
}
}
std::string methods_list;
if (type_method_count > 9) {
std::string methods_list;
std::string state_methods_list;
MethodInfo old_new_method;
if (old_game_type && old_game_type->get_my_new_method(&old_new_method)) {
methods_list.append(" ");
methods_list.append(old_method_string(old_new_method));
methods_list.push_back('\n');
}
bool done_with_state_methods = false;
for (int i = parent_method_count; i < type_method_count; i++) {
bool print_as_state_method = false;
if (method_states.count(i) != 0) {
if (!done_with_state_methods) {
print_as_state_method = true;
state_methods_list.append(fmt::format(" {}", method_states.at(i)));
} else {
methods_list.append(
fmt::format(" ({} () _type_ :state) ;; {}", method_states.at(i), i));
}
} else {
done_with_state_methods = true;
methods_list.append(fmt::format(" ({}-method-{} () none) ;; {}", type_name, i, i));
// If it's a state-method (virtual state) skip it
if (method_states.find(i) != method_states.end()) {
continue;
}
methods_list.append(fmt::format(" ({}-method-{} () none) ;; {}", type_name, i, i));
if (old_game_type) {
MethodInfo info;
if (old_game_type->get_my_method(i, &info)) {
if (print_as_state_method) {
state_methods_list += old_method_string(info);
} else {
methods_list += old_method_string(info);
}
methods_list += old_method_string(info);
}
}
if (print_as_state_method) {
state_methods_list.push_back('\n');
} else {
methods_list.push_back('\n');
}
}
if (!state_methods_list.empty()) {
result.append("(:state-methods\n");
result.append(state_methods_list);
result.append(" )\n ");
}
if (!methods_list.empty()) {
result.append("(:methods");
result.append(methods_list);
result.append(" )\n ");
methods_list.push_back('\n');
}
}
// Print out (normal) states if we have em
// - Could probably assume the process name comes first and associate it with the right type
// but that may or may not be risky so, edit the types yourself...
if (method_states.size() > 0) {
result.append("(:states\n ");
for (const auto& [id, name] : method_states) {
result.append(name);
// Append old symbol def if we have it
auto it = previous_game_ts.symbol_types.find(name);
// non-virtual states
std::string non_virtual_states_list;
for (const auto& [state_name, guessed_type_name] : object_file_meta.non_virtual_state_guesses) {
if (type_name == guessed_type_name) {
std::string line;
line += fmt::format(" {}", state_name);
auto it = previous_game_ts.symbol_types.find(state_name);
if (it != previous_game_ts.symbol_types.end()) {
result.append(fmt::format(" ;; {}", it->second.print()));
line += fmt::format(" ;; associated process guessed by decompiler, old: {}",
it->second.print());
}
// Add symbol name to `already_seen_symbols`
object_file_meta.already_seen_symbols.insert(name);
result.append("\n ");
non_virtual_states_list.append(line + "\n");
}
result.append(")\n ");
}
// methods and virtual states
if (!methods_list.empty()) {
result.append("(:methods\n");
result.append(methods_list);
result.append(" )\n ");
}
if (!state_methods_list.empty()) {
result.append("(:state-methods\n");
result.append(state_methods_list);
result.append(" )\n ");
}
// non-virtual states
if (!non_virtual_states_list.empty()) {
result.append("(:states\n");
result.append(non_virtual_states_list);
result.append(" )\n ");
}
result.append(")\n");
@@ -1800,7 +1802,8 @@ void inspect_top_level_for_metadata(Function& top_level,
const auto& aop = top_level.ir2.atomic_ops->ops.at(i);
const std::string as_str = aop.get()->to_string(top_level.ir2.env);
// Keep track of the last seen label so we can easily reference it if a later operation uses it
// Keep track of the last seen label so we can easily reference it if a later operation uses
// it
auto label_match = get_regex_match(as_str, std::regex("\\(set!\\s[^\\s]*\\s(L.*)\\)"));
if (!label_match.empty()) {
last_seen_label = label_match;
@@ -1858,7 +1861,8 @@ void inspect_top_level_for_metadata(Function& top_level,
}
// lwu t9, 16(v1) ;; [ 21] (set! t9-0 (l.wu (+ v1-10 16)))
// ;; [v1: <the etype type> ] -> [t9: (function symbol type int type)
// ;; [v1: <the etype type> ] -> [t9: (function symbol type int
// type)
const auto& aop_1 = top_level.ir2.atomic_ops->ops.at(i + 1);
if (!is_set_reg_to_load(aop_1.get(), Register(Reg::GPR, Reg::T9), 16)) {
continue;
@@ -1935,8 +1939,9 @@ std::string inspect_top_level_symbol_defines(Function& top_level,
if (as_store && as_store->addr().kind() == SimpleExpression::Kind::IDENTITY &&
as_store->addr().get_arg(0).is_sym_val()) {
auto& sym_name = as_store->addr().get_arg(0).get_str();
if (object_file_meta.already_seen_symbols.find(sym_name) ==
object_file_meta.already_seen_symbols.end()) {
const auto sym_already_seen = object_file_meta.already_seen_symbols.find(sym_name) !=
object_file_meta.already_seen_symbols.end();
if (!sym_already_seen) {
object_file_meta.already_seen_symbols.insert(sym_name);
if (dts.ts.partially_defined_type_exists(sym_name)) {
continue;
+1 -1
View File
@@ -172,7 +172,7 @@ bool convert_to_expressions(
"statement.",
f.name());
f.warnings.warning(warn);
lg::warn(warn);
lg::warn("{}", warn);
}
}
+1 -1
View File
@@ -87,7 +87,7 @@ bool rewrite_inline_asm_instructions(Form* top_level_form,
} catch (std::exception& e) {
std::string warning =
fmt::format("ASM instruction re-writing failed in {}: {}", f.name(), e.what());
lg::warn(warning);
lg::warn("{}", warning);
f.warnings.error(";; {}", warning);
return false;
}
+1 -1
View File
@@ -23608,7 +23608,7 @@
(define-extern nav-enemy-turn-to-face-point (function vector float none :behavior nav-enemy))
(define-extern nav-enemy-execute-jump (function none :behavior nav-enemy))
(define-extern nav-enemy-jump-land-anim (function none :behavior nav-enemy)) ;; TODO
(define-extern nav-enemy-rnd-float-range (function float float float :behavior nav-enemy))
(define-extern nav-enemy-rnd-float-range (function float float float))
(define-extern nav-enemy-common-post (function none :behavior nav-enemy)) ;; TODO not confirmed
(define-extern nav-enemy-execute-custom-jump (function int float float none :behavior nav-enemy))
(define-extern nav-enemy-initialize-custom-jump (function vector symbol float float float none :behavior nav-enemy))
+1 -1
View File
@@ -108,7 +108,7 @@
// these can be displayed in game, but makes the .fr3 files slightly larger
"extract_collision": true,
// save game textures as .png files.
"save_texture_pngs": true,
"save_texture_pngs": false,
////////////////////////////
// PATCHING OPTIONS
+157 -90
View File
@@ -7381,6 +7381,14 @@
(progress-cheats-board-tricks #x1260)
(progress-cheats-weather-bad #x1261)
(progress-cheats-weather-good #x1262)
(progress-cheats-hijack-lines #x1263)
(progress-cheats-locked #x1264)
(progress-cheats-turbo-board-unlock #x1265)
(progress-cheats-health-bars-unlock #x1266)
(progress-cheats-vehicle-health-bars-unlock #x1267)
(progress-cheats-statistics-unlock #x1268)
(progress-cheats-suck-in-all-unlock #x1269)
(progress-cheats-fast-travel-unlock #x126a)
(progress-camera-options #x1280)
(progress-camera-options-first-horz #x1281)
(progress-camera-options-first-vert #x1282)
@@ -7415,6 +7423,47 @@
(progress-shadows #x12a0)
(progress-shadows-normal #x12a1)
(progress-shadows-extended #x12a2)
(progress-error-no-resolutions #x12a3)
(progress-territory-auto #x12a4)
(progress-kill-stats #x12a5)
(progress-other-stats #x12a6)
(progress-ks-total-killed #x12a7)
(progress-ks-killed-by-jak #x12a8)
(progress-ks-killed-by-darkjak #x12a9)
(progress-ks-killed-by-daxter #x12aa)
(progress-ks-killed-by-others #x12ab)
(progress-ks-source-gun-yellow #x12ac)
(progress-ks-source-gun-red #x12ad)
(progress-ks-source-gun-blue #x12ae)
(progress-ks-source-gun-dark #x12af)
(progress-ks-source-board #x12b0)
(progress-ks-source-board-trick #x12b1)
(progress-ks-source-mech #x12b2)
(progress-ks-source-mech-bonk #x12b3)
(progress-ks-source-turret #x12b4)
(progress-ks-source-punch #x12b5)
(progress-ks-source-flop #x12b6)
(progress-ks-source-uppercut #x12b7)
(progress-ks-source-spin #x12b8)
(progress-ks-source-roll #x12b9)
(progress-ks-source-darkjak-punch #x12ba)
(progress-ks-source-darkjak-flop #x12bb)
(progress-ks-source-darkjak-uppercut #x12bc)
(progress-ks-source-darkjak-spin #x12bd)
(progress-ks-source-darkjak-roll #x12be)
(progress-ks-source-darkjak-bomb0 #x12bf)
(progress-ks-source-darkjak-bomb1 #x12c0)
(progress-ks-source-indax-punch #x12c1)
(progress-ks-source-indax-spin #x12c2)
(progress-ks-source-guard #x12c3)
(progress-ks-source-sig #x12c4)
(progress-ks-source-ashelin #x12c5)
(progress-ks-source-jinx #x12c6)
(progress-ks-source-grim #x12c7)
(progress-ks-source-mog #x12c8)
(progress-ks-source-metalhead #x12c9)
(progress-ks-source-other-bot #x12ca)
(progress-ks-source-other-enemy #x12cb)
(progress-input-options-auto-hide-cursor #x1300)
(progress-menu-reassign-binds #x1301)
(progress-reassign-binds-controller #x1302)
@@ -7437,6 +7486,7 @@
(progress-highscores-local-time #x1313)
(progress-fps-disclaimer-warning #x1314)
(progress-fps-disclaimer #x1315)
(progress-highscores-local-score #x1316)
(trick-board-none #x1320)
(trick-board-spin #x1321)
(trick-board-boost #x1322)
@@ -15775,6 +15825,24 @@
(test 22) ;; hi 64
)
;; +++game-h:knocked-type
(defenum knocked-type
:type uint8
(knocked-type-0 0)
(knocked-type-1 1)
(knocked-type-2 2)
(knocked-type-3 3)
(knocked-type-4 4) ;; what the heck is this! (its on gator, and cant trigger it for the life of me)
(knocked-type-5 5)
(knocked-type-6 6)
(knocked-type-7 7)
(knocked-type-8 8)
(knocked-type-9 9)
(knocked-type-10 10)
)
;; ---game-h:knocked-type
(declare-type touching-shapes-entry structure)
(deftype attack-info (structure)
@@ -15800,7 +15868,7 @@
(penetrate-using penetrate :offset-assert 136)
(damage float :offset-assert 144)
(shield-damage float :offset-assert 148)
(knock uint8 :offset-assert 152)
(knock knocked-type :offset-assert 152)
(test symbol :offset-assert 156)
)
:method-count-assert 12
@@ -24877,7 +24945,7 @@
(define-extern shadow-add-single-tris function)
(define-extern shadow-add-double-tris function)
(define-extern shadow-add-double-edges function)
(define-extern debug-draw-settings (function matrix none))
(define-extern debug-draw-settings (function shadow-settings symbol))
(define-extern shadow-execute (function shadow-dma-packet pointer pointer))
(define-extern shadow-vu0-upload (function none))
(define-extern shadow-execute-all (function dma-buffer none))
@@ -27728,7 +27796,7 @@
(define-extern dist-info-valid? (function collide-los-dist-info symbol)) ;;
(define-extern dist-info-append (function collide-los-dist-info vector none)) ;;
(define-extern dist-info-print (function collide-los-dist-info string object)) ;;
(define-extern los-cw-ccw (function (inline-array collide-cache-tri) vector vector float collide-los-result vector float symbol)) ;;
(define-extern los-cw-ccw (function (inline-array collide-cache-tri) vector vector float collide-los-result vector float symbol :behavior camera-slave)) ;;
(define-extern cam-los-spline-collide (function vector vector pat-surface float)) ;;
(define-extern cam-los-setup-lateral (function collide-los-result vector vector symbol :behavior camera-slave)) ;;
(define-extern cam-los-collide (function vector vector collide-los-result pat-surface symbol :behavior camera-slave)) ;;
@@ -32801,42 +32869,42 @@
(defenum enemy-flag
:type int64
:bitfield #t
(lock-focus 0)
(death-start 1)
(enable-on-active 2)
(checking-water 3)
(check-water 4)
(spawn-gem 5)
(chase-startup 6)
(attackable-backup 7)
(look-at-focus 8)
(use-notice-distance 9)
(enable-on-notice 10)
(look-at-move-dest 11)
(notice 12)
(auto-reset-penetrate 13)
(jump-check-blocked 14)
(drawn-mirrored 15)
(multi-focus 16)
(alert 17)
(victory 18)
(dangerous-backup 19)
(actor-pause-backup 20)
(trackable 21)
(called-dying 22)
(check-water-backup 23)
(no-initial-move-to-ground 24)
(cam-attack-mode 25)
(trackable-backup 26)
(enable-on-hostile 27)
(directed-ready 28)
(use-trigger 29)
(directed 30)
(dislike-combo 31)
(recover-applied-velocity 32)
(vulnerable-backup 33)
(vulnerable 34)
(recover 35)
(look-at-focus 0)
(look-at-move-dest 1)
(vulnerable 2)
(vulnerable-backup 3)
(dangerous-backup 4)
(notice 5)
(alert 6)
(auto-reset-penetrate 7)
(victory 8)
(cam-attack-mode 9)
(use-notice-distance 10)
(attackable-backup 11)
(actor-pause-backup 12)
(enable-on-notice 13)
(enable-on-active 14)
(enable-on-hostile 15)
(dislike-combo 16)
(directed 17)
(directed-ready 18)
(chase-startup 19)
(lock-focus 20)
(multi-focus 21)
(use-trigger 22)
(trackable 23)
(trackable-backup 24)
(spawn-gem 25)
(check-water 26)
(check-water-backup 27)
(checking-water 28)
(recover 29)
(recover-applied-velocity 30)
(drawn-mirrored 31)
(called-dying 32)
(no-initial-move-to-ground 33)
(jump-check-blocked 34)
(death-start 35)
(enemy-flag36 36)
(enemy-flag37 37)
(enemy-flag38 38)
@@ -32975,8 +33043,21 @@
:flag-assert #x900000018
)
(defenum enemy-jump-flags
:bitfield #t
:type uint8
(enjflag-0)
(enjflag-1)
(enjflag-2)
(enjflag-3)
(enjflag-4)
(enjflag-5)
(enjflag-6)
(enjflag-7)
)
(deftype enemy-jump-info (structure)
((flags uint8 :offset-assert 0)
((flags enemy-jump-flags :offset-assert 0)
(anim-speed float :offset-assert 4)
(hang-time time-frame :offset-assert 8)
(start-pos vector :inline :offset-assert 16)
@@ -33000,27 +33081,13 @@
:flag-assert #x90000002c
)
;; +++enemy-h:knocked-type
(defenum knocked-type
:type uint8
(knocked-type-0 0)
(knocked-type-1 1)
(knocked-type-2 2)
(knocked-type-3 3)
(knocked-type-4 4) ;; what the heck is this! (its on gator, and cant trigger it for the life of me)
(knocked-type-5 5)
(knocked-type-6 6)
(knocked-type-7 7)
)
;; ---enemy-h:knocked-type
(deftype enemy-attack-info (structure)
((attack-id uint32 :offset-assert 0)
(knocked-type knocked-type :offset-assert 4)
(blue-juggle-count uint8 :offset-assert 5)
(attacker-handle handle :offset-assert 8)
(attack-time time-frame :offset-assert 16)
(penetrate-using uint64 :offset-assert 24)
(penetrate-using penetrate :offset-assert 24)
(attacker-pos vector :inline :offset-assert 32)
(attack-direction vector :inline :offset-assert 48)
)
@@ -33114,7 +33181,7 @@
"TODO"
(_type_ process-focusable) symbol) ;; 53
(enemy-method-54 (_type_) enemy-flag) ;; 54
(track-target!
(common-post
"Does a lot of various things relating to interacting with the target
- tracks when the enemy was last drawn
- looks at the target and handles attacking
@@ -33139,8 +33206,8 @@
(enemy-method-61 (_type_ int) int :behavior enemy) ;; 61
(enemy-method-62 (_type_) none) ;; 62
(enemy-method-63 (_type_ process-focusable enemy-aware) symbol) ;; 63
(enemy-method-64 (_type_) none) ;; 64
(enemy-method-65 (_type_) none) ;; 65
(go-dormant (_type_) object) ;; 64
(go-dormant-aware (_type_) object) ;; 65
(go-ambush (_type_) object) ;; 66
(go-stare (_type_) object) ;; 67
(go-stare2 (_type_) object) ;; 68
@@ -33159,8 +33226,8 @@
(_type_ process int symbol event-message-block) object) ;; 74
(enemy-method-75 (_type_ process event-message-block) object) ;; 75
(enemy-method-76 (_type_ process event-message-block) symbol) ;; 76
(enemy-method-77 (_type_ (pointer float)) symbol) ;; 77
(enemy-method-78 (_type_ (pointer float)) symbol) ;; 78
(enemy-method-77 (_type_ enemy-knocked-info) symbol) ;; 77
(enemy-method-78 (_type_ enemy-knocked-info) symbol) ;; 78
(enemy-method-79 (_type_ int enemy-knocked-info) symbol) ;; 79
(enemy-method-80 (_type_ enemy-knocked-info) symbol) ;; 80
(enemy-method-81 (_type_) symbol) ;; 81
@@ -33174,10 +33241,7 @@
(enemy-method-89 (_type_ enemy-jump-info) symbol) ;; 89
(enemy-method-90 (_type_ int enemy-jump-info) symbol) ;; 90
(enemy-method-91 (_type_ int enemy-jump-info) none) ;; 91
(enemy-method-92
"TODO - nav-poly is a guess
@abstract"
(_type_ int nav-poly) none) ;; 92
(enemy-method-92 "@abstract" (_type_ int enemy-jump-info) none) ;; 92
(enemy-method-93 (_type_) none) ;; 93
(enemy-method-94 (_type_ vector float) symbol) ;; 94
(enemy-method-95 (_type_ vector float) symbol) ;; 95
@@ -33197,11 +33261,11 @@
(enemy-method-103 (_type_) collide-spec) ;; 103
(enemy-method-104 (_type_ process touching-shapes-entry uint) symbol :behavior process) ;; 104
(enemy-method-105 (_type_ process) enemy-flag) ;; 105
(enemy-method-106 (_type_ process object int attack-info) none :behavior enemy) ;; 106
(set-incoming-attack-info (_type_ process object penetrate attack-info) none :behavior enemy) ;; 106
(get-enemy-target
"@returns the [[process-focusable]] that the enemy is currently focusing on, or [[#f]] otherwise"
(_type_) process-focusable) ;; 107
(enemy-method-108 (_type_ enemy event-message-block) int) ;; 108
(enemy-method-108 (_type_ process-drawable event-message-block) int) ;; 108
(look-at-target!
"Logic for looking at the target that is locked on, sets some flags and adjusts the neck to look at the target if available
@param flag Reacts to [[enemy-flag::death-start]] and [[enemy-flag::enable-on-active]], see implementation for details"
@@ -33224,33 +33288,32 @@
"Common method called to initialize the enemy, typically sets up default field values and calls ancillary helper methods"
(_type_) none) ;; 115
(go-idle (_type_) none) ;; 116
(get-rand-float
(rnd-float
"@returns the result of calling [[rand-vu]]"
(_type_) float) ;; 117
(get-rand-float-range
(rnd-float-range
"@param low The lower bound of the range (inclusive)
@param high The upper bound of the range (exclusive)
@returns A random float in the specified range"
(_type_ float float) float) ;; 118
(get-rand-int
(rnd-int-count
"@param high The upper bound of the range (exclusive)
@returns a random integer in the range 0 to `high`
@see [[rand-vu]]"
(_type_ int) int) ;; 119
(enemy-method-120 "TODO" (_type_ int int) int) ;; 120
(get-rand-int-range
(rnd-bit "TODO" (_type_ int int) int) ;; 120
(rnd-int-range
"@param low The lower bound of the range (inclusive)
@param high The upper bound of the range (exclusive)
@returns A random integer in the specified range"
(_type_ int int) int) ;; 121
(rng-hit?
"TODO - not the best name
@param chance The value to compare ([[>=]]) with the result from [[rand-vu]].
(rnd-percent?
"@param chance The value to compare ([[>=]]) with the result from [[rand-vu]].
@returns If `chance` is greater than the random draw"
(_type_ float) symbol) ;; 122
(enemy-method-123 "TODO" (_type_ float) symbol) ;; 123
(rnd-go-idle? "TODO" (_type_ float) symbol) ;; 123
(enemy-method-124 "TODO" (_type_) collide-spec) ;; 124
(enemy-method-125 (_type_ collide-query collide-spec float float float) pat-surface) ;; 125
(ground-pat-set! (_type_ collide-query collide-spec float float float) pat-surface) ;; 125
(enemy-above-ground?
"@returns if the enemy is above the ground or not
@see [[above-ground?]]"
@@ -33259,12 +33322,12 @@
(enemy-method-128 (_type_ vector move-above-ground-params) none) ;; 128
(enemy-method-129 (_type_) none) ;; 129
(enemy-method-130 (_type_ float) symbol) ;; 130
(enemy-method-131 (_type_ int) uint) ;; 131
(dispose!
(penetrate-using->knocked (_type_ penetrate) knocked-type) ;; 131
(dying
"Cleans-up the enemy and any associated resources. Potentially spawns skull gems"
(_type_) none) ;; 132
(enemy-method-133 (_type_) symbol) ;; 133
(enemy-method-134 (_type_ process attack-info) process-focusable) ;; 134
(get-attacker (_type_ process attack-info) process-focusable) ;; 134
(enemy-method-135 (_type_ int) sound-id) ;; 135
(enemy-method-136 (_type_) enemy-flag) ;; 136
)
@@ -34814,7 +34877,7 @@
(unknown-byte-n1k2n3 int8 :offset 636)
(unknown-byte-m2j342 int8 :offset 637)
(unknown-byte-1ji2n3 int8 :offset 638)
(unknown-byte-n123n int8 :offset 639)
(unknown-byte-n123n uint8 :offset 639)
(state-timeout2 uint64 :offset-assert 640)
(next-warn-time time-frame :offset-assert 648)
(dest vector :inline :offset-assert 656)
@@ -38515,7 +38578,7 @@
charge
)
(:methods
(rhino-method-182 (_type_ process event-message-block) symbol) ;; 182
(hit-stomach? (_type_ process event-message-block) symbol) ;; 182
)
)
@@ -39415,7 +39478,7 @@
(hit-by-enemy-count uint16 :offset-assert 698)
(hit-by-player-count uint16 :offset-assert 700)
(notice-enemy-dist float :offset-assert 704)
(channel uint8 :offset-assert 708)
(channel gui-channel :offset-assert 708)
(focus-mode int8 :offset-assert 709)
(nav-mesh-index int8 :offset-assert 710)
(delay-too-far-check int8 :offset-assert 711)
@@ -39478,13 +39541,13 @@
(play-speech (_type_ int) none) ;; 206
(play-death-sound "Play one of our death sounds." (_type_ string) none) ;; 207
(bot-method-208 (_type_) symbol) ;; 208
(channel-active? "Is the given [[gui-channel]] active?" (_type_ uint) symbol) ;; 209
(channel-active? "Is the given [[gui-channel]] active?" (_type_ gui-channel) symbol) ;; 209
(init! "Set defaults for various fields." (_type_) none) ;; 210
(clear-speech-flags! "Clear the `playing` flag for all of our speeches." (_type_) none) ;; 211
(reset-warn-time! (_type_) none) ;; 212
(go-to-waypoint! "Start moving to the given [[bot-waypoint]]." (_type_ int symbol) object) ;; 213
(bot-method-214 (_type_) symbol) ;; 214
(skip-waypoint (_type_) none) ;; 215
(skip-waypoint (_type_) object) ;; 215
(bot-method-216 (_type_) none) ;; 216
(speech-ended? "Is the given speech active?" (_type_ int) symbol) ;; 217
(speech-playing? "Is the given speech playing?" (_type_ int) symbol) ;; 218
@@ -43427,7 +43490,7 @@
(define-extern set-countdown-to-roar (function none :behavior metalkor))
(define-extern metalkor-go-next-stage (function none :behavior metalkor))
(define-extern metalkor-setup-hit-anim (function attack-info process-drawable art-element art-element float none :behavior metalkor))
(define-extern metalkor-get-gem-tracker (function process-focusable none :behavior metalkor))
(define-extern metalkor-get-gem-tracker (function process-focusable gem-tracker :behavior metalkor))
(define-extern metalkor-handler (function process int symbol event-message-block object :behavior metalkor))
(define-extern metalkor-start-egg (function symbol :behavior metalkor))
(define-extern metalkor-check-egg (function symbol :behavior metalkor))
@@ -50579,13 +50642,15 @@
(
(ai-hook (function vehicle-guard none) :offset-assert 880)
(turret turret-control :inline :offset-assert 888)
(target-flags turret-flag :offset-assert 968)
(target-flags traffic-target-flag :offset-assert 968)
(target-in-sight-time time-frame :offset-assert 976)
(minimap connection-minimap :offset-assert 984)
(vehicle-guard-pad-k1jn23k1 uint32 :offset-assert 988)
(traffic-target-status traffic-target-status :offset-assert 992)
(pursuit-target handle :offset-assert 1000)
(vehicle-guard-pad-1kjh2nb3k1 uint32 16 :offset-assert 1008)
(vehicle-guard-pad-0jkfdjslf uint32 4 :offset-assert 1008)
(vehicle-guard-vector0341413 vector :inline :offset-assert 1024)
(vehicle-guard-pad-1kjh2nb3k1 uint32 8 :offset-assert 1040)
(lod2 symbol :offset-assert 1072)
)
:method-count-assert 159
@@ -50616,7 +50681,7 @@
(define-extern vehicle-draw-beam (function sparticle-launcher vector vector object symbol none))
(define-extern vehicle-draw-laser-spot (function vector vector symbol none))
(define-extern vehicle-draw-laser (function vector vector none))
(define-extern vehicle-guard-choose-branch (function vehicle-controller vehicle nav-branch))
(define-extern vehicle-guard-choose-branch (function vehicle-controller vehicle-guard nav-branch))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; transport ;;
@@ -52949,7 +53014,9 @@
(deftype mechblock (process-drawable)
((root collide-shape-moving :override)
(origin vector :inline :offset-assert 208)
(drop-point vector :inline :offset 256)
(unknown-quat quaternion :inline :offset-assert 224)
(unknown-vector vector :inline :offset-assert 240)
(drop-point vector :inline :offset-assert 256)
(allow-drag? symbol :offset-assert 272)
(reset-on-land? symbol :offset-assert 276)
(hit-something? symbol :offset-assert 280)
@@ -53473,4 +53540,4 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *default-envmap-shader* adgif-shader)
(define-extern *generic-envmap-texture* texture)
(define-extern *generic-envmap-texture* texture)
@@ -654,7 +654,7 @@
"collectables": [[69, "(function part-tracker vector)"]],
"mech-states": [[50, "(function none :behavior target)"]],
"target-mech": [
[7, "(function none :behavior target)"],
[7, "(function none :behavior manipy)"],
[8, "(function none :behavior mech)"],
[9, "(function none :behavior manipy)"],
[18, "(function surface object surface int none :behavior target)"],
@@ -1227,8 +1227,8 @@
"castle-baron": [[7, "(function collectable none)"]],
"metalkor-extras": [[65, "(function vector :behavior metalkor-shot)"]],
"metalkor-setup": [
[1, "(function gem-tracker none)"],
[2, "(function gem-tracker none)"]
[1, "(function gem-tracker symbol)"],
[2, "(function gem-tracker symbol)"]
],
"meet-brutter": [
[0, "(function none :behavior task-manager)"],
@@ -4309,7 +4309,8 @@
"(method 74 enemy)": [
[50, "s3", "process-drawable"],
[94, "v1", "attack-info"],
[[111, 205], "s2", "attack-info"],
[[111, 137], "s2", "attack-info"],
[204, "s2", "attack-info"],
[554, "a0", "vector"]
],
"(method 56 enemy)": [[[0, 6], "v1", "attack-info"]],
@@ -4537,7 +4538,7 @@
],
"(method 23 joint-exploder)": [[26, "v1", "process-drawable"]],
"(method 28 joint-exploder)": [[[0, 250], "s5", "joint-exploder-list"]],
"joint-exploder-joint-callback": [[3, "s4", "joint-exploder"]],
"joint-exploder-joint-callback": [[[3, 25], "s4", "joint-exploder"]],
"(event idle fort-trap-door)": [[4, "v1", "attack-info"]],
"(code idle hide-light)": [[10, "v1", "art-joint-anim"]],
"(event impact turret-shot)": [[11, "s4", "process-drawable"]],
@@ -4968,10 +4969,6 @@
],
"(enter target-mech-carry-hit-ground)": [[3, "v0", "sound-rpc-set-param"]],
"(event target-mech-grab)": [[24, "a0", "process"]],
"(anon-function 7 target-mech)": [
[32, "a0", "joint-mod-ik"],
[26, "a0", "(array joint-mod-ik)"]
],
"(enter target-mech-hit-ground)": [[3, "v0", "sound-rpc-set-param"]],
"(exit target-mech-carry-drag)": [
[11, "v0", "sound-rpc-set-param"],
@@ -7064,7 +7061,7 @@
],
"(method 9 city-level-info)": [[387, "v1", "nav-segment"]],
"(method 67 traffic-engine)": [
[[137, 183], "s0", "crimson-guard"],
[[137, 185], "s0", "crimson-guard"],
[[44, 86], "a3", "vehicle"]
],
"set-eye-draw-flag": [[20, "s5", "eye-control"]],
@@ -10155,5 +10152,8 @@
"race-birth-func-texture-position-word": [
[10, "v1", "(array int32)"],
[1, "v1", "(array int32)"]
]
],
"(method 206 hal)": [[32, "a2", "bot"]],
"(method 209 hal)": [[32, "v1", "bot"]],
"(method 220 hal)": [[29, "v1", "bot"]]
}
+25 -1
View File
@@ -4228,7 +4228,9 @@
"vars": {
"v1-3": "shadow-settings",
"a3-0": "shadow-geo",
"t0-0": "dist"
"t0-0": "dist",
"a3-2": ["shadow-pack1", "shadow-dma-packet"],
"t2-11": ["shadow-pack2", "shadow-dma-packet"]
}
},
"progress-selected": {
@@ -4637,5 +4639,27 @@
"vars": {
"t1-3": ["imp-sound", "sound-name"]
}
},
"(method 9 menu-secret-option)": {
"vars": {
"s5-1": "hero?",
"s3-0": "min-item",
"s2-0": "max-item",
"s5-2": "scroll-sound?",
"v1-74": "item",
"a0-54": "flag",
"a1-9": "on-off?"
}
},
"(method 10 menu-unlocked-menu-option)": {
"vars": {
"s5-0": "secrets",
"f30-0": "alpha"
}
},
"joint-exploder-joint-callback": {
"vars": {
"s4-0": ["exploder", "joint-exploder"]
}
}
}
+39 -50
View File
@@ -169,7 +169,7 @@
(_data uint8 :score -50 :dynamic :offset 16)
)
(:methods
(new (symbol type int) _type_ 0))
(new (symbol type int) _type_))
:method-count-assert 9
:size-assert #x10
:flag-assert #x900000010
@@ -296,9 +296,9 @@
(self process-tree :offset-assert 32)
)
(:methods
(new (symbol type string) _type_ 0)
(activate (_type_ process-tree basic pointer) process-tree 9)
(deactivate (_type_) none 10)
(new (symbol type string) _type_)
(activate (_type_ process-tree basic pointer) process-tree)
(deactivate (_type_) none)
(init-from-entity!
"Typically the method that does the initial setup on the process, potentially using the [[entity-actor]] provided as part of that.
This commonly includes things such as:
@@ -306,9 +306,9 @@
- collision information
- loading the skeleton group / bones
- sounds"
(_type_ entity-actor) none 11)
(run-logic? (_type_) symbol 12)
(process-tree-method-13 () none 13)
(_type_ entity-actor) none)
(run-logic? (_type_) symbol)
(process-tree-method-13 () none)
)
:size-assert #x24
:method-count-assert 14
@@ -361,13 +361,13 @@
:size-assert #x5c
:flag-assert #xf0000005c
(:methods
(new (symbol type int) _type_ 0)
(update-rates! (_type_ float) float 9)
(advance-by! (_type_ float) clock 10)
(tick! (_type_) clock 11)
(save! (_type_ (pointer uint64)) int 12)
(load! (_type_ (pointer uint64)) int 13)
(reset! (_type_) none 14)
(new (symbol type int) _type_)
(update-rates! (_type_ float) float)
(advance-by! (_type_ float) clock)
(tick! (_type_) clock)
(save! (_type_ (pointer uint64)) int)
(load! (_type_ (pointer uint64)) int)
(reset! (_type_) none)
)
)
@@ -387,9 +387,9 @@
:size-assert #x28
:flag-assert #xc00000028
(:methods
(stack-size-set! (_type_ int) none 9)
(thread-suspend (_type_) none 10)
(thread-resume (_type_) none 11)
(stack-size-set! (_type_ int) none)
(thread-suspend (_type_) none)
(thread-resume (_type_) none)
)
)
@@ -408,7 +408,7 @@
:size-assert #x80
:flag-assert #xc00000080
(:methods
(new (symbol type process symbol int pointer) _type_ 0)
(new (symbol type process symbol int pointer) _type_)
)
)
@@ -421,9 +421,9 @@
:flag-assert #x1000000024
;; Failed to read fields.
(:methods
(new (symbol type int int string) _type_ 0)
(get-process (_type_ type int) process 14)
(return-process (_type_ process) none 15)
(new (symbol type int int string) _type_)
(get-process (_type_ type int) process)
(return-process (_type_ process) none)
)
)
@@ -459,19 +459,19 @@
:flag-assert #x1c00000068
;; Failed to read fields.
(:methods
(new (symbol type string int int) _type_ 0)
(init (_type_ symbol int) none 16)
(compact (dead-pool-heap int) none 17)
(shrink-heap (dead-pool-heap process) dead-pool-heap 18)
(churn (dead-pool-heap int) none 19)
(memory-used (_type_) int 20)
(memory-total (_type_) int 21)
(memory-free (dead-pool-heap) int 22)
(compact-time (dead-pool-heap) uint 23)
(gap-size (dead-pool-heap dead-pool-heap-rec) int 24)
(gap-location (dead-pool-heap dead-pool-heap-rec) pointer 25)
(find-gap (dead-pool-heap dead-pool-heap-rec) dead-pool-heap-rec 26)
(find-gap-by-size (dead-pool-heap int) dead-pool-heap-rec 27)
(new (symbol type string int int) _type_)
(init (_type_ symbol int) none)
(compact (dead-pool-heap int) none)
(shrink-heap (dead-pool-heap process) dead-pool-heap)
(churn (dead-pool-heap int) none)
(memory-used (_type_) int)
(memory-total (_type_) int)
(memory-free (dead-pool-heap) int)
(compact-time (dead-pool-heap) uint)
(gap-size (dead-pool-heap dead-pool-heap-rec) int)
(gap-location (dead-pool-heap dead-pool-heap-rec) pointer)
(find-gap (dead-pool-heap dead-pool-heap-rec) dead-pool-heap-rec)
(find-gap-by-size (dead-pool-heap int) dead-pool-heap-rec)
)
)
@@ -499,7 +499,7 @@
:size-assert #xb0
:flag-assert #x9000000b0
(:methods
(new (symbol type symbol function (pointer uint64)) object 0)
(new (symbol type symbol function (pointer uint64)) object)
)
)
@@ -535,7 +535,7 @@
(function none)
function
(function none)
(function process int symbol event-message-block object)) _type_ 0)
(function process int symbol event-message-block object)) _type_)
)
:method-count-assert 9
:size-assert #x24
@@ -566,7 +566,7 @@
:size-assert #x10
:flag-assert #xa00000010
(:methods
(send-all! (_type_) none 9)
(send-all! (_type_) none)
)
)
@@ -594,7 +594,7 @@
(stack uint8 :dynamic :offset-assert 128 :score -1)
)
(:methods
(new (symbol type string int) _type_ 0)
(new (symbol type string int) _type_)
)
(:states
dead-state
@@ -604,17 +604,6 @@
:no-runtime-type ;; already defined by kscheme. Don't do it again.
)
(deftype sql-result (basic)
((len int32 :offset-assert 4)
(allocated-length uint32 :offset-assert 8)
(error symbol :offset-assert 12)
(data string :dynamic :offset-assert 16) ;; are these actually symbols, or are they strings (in the GOAL code they are treated as strings atleast)
)
(:methods (new (symbol type uint) _type_ 0))
:method-count-assert 9
:size-assert #x10
)
(define-extern *sql-result* sql-result)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -693,4 +682,4 @@
(define-extern *mid-pool* process-tree)
(define-extern *pusher-pool* process-tree)
(define-extern *bg-pool* process-tree)
(define-extern *default-pool* process-tree) ;; process-tree
(define-extern *default-pool* process-tree) ;; process-tree
+1 -1
View File
@@ -80,7 +80,7 @@
////////////////////////////
// CONFIG FILES
////////////////////////////
"type_casts_file": "decompiler/config/jak3/ntsc_v1/type_casts.jsonc",
"anonymous_function_types_file": "decompiler/config/jak3/ntsc_v1/anonymous_function_types.jsonc",
"var_names_file": "decompiler/config/jak3/ntsc_v1/var_names.jsonc",
+15 -12
View File
@@ -133,20 +133,23 @@ void TextureDB::replace_textures(const fs::path& path) {
fs::path base_path(path);
for (auto& tex : textures) {
fs::path full_path = base_path / tpage_names.at(tex.second.page) / (tex.second.name + ".png");
if (fs::exists(full_path)) {
lg::info("Replacing {}", full_path.string().c_str());
int w, h;
auto data = stbi_load(full_path.string().c_str(), &w, &h, 0, 4); // rgba channels
if (!data) {
lg::warn("failed to load PNG file: {}", full_path.string().c_str());
if (!fs::exists(full_path)) {
full_path = base_path / "_all" / (tex.second.name + ".png");
if (!fs::exists(full_path))
continue;
}
tex.second.rgba_bytes.resize(w * h);
memcpy(tex.second.rgba_bytes.data(), data, w * h * 4);
tex.second.w = w;
tex.second.h = h;
stbi_image_free(data);
}
lg::info("Replacing {}", tpage_names.at(tex.second.page) + "/" + (tex.second.name));
int w, h;
auto data = stbi_load(full_path.string().c_str(), &w, &h, 0, 4); // rgba channels
if (!data) {
lg::warn("failed to load PNG file: {}", full_path.string().c_str());
continue;
}
tex.second.rgba_bytes.resize(w * h);
memcpy(tex.second.rgba_bytes.data(), data, w * h * 4);
tex.second.w = w;
tex.second.h = h;
stbi_image_free(data);
}
}
@@ -1,5 +1,6 @@
#include "extract_collide_frags.h"
#include "common/log/log.h"
#include "common/util/FileUtil.h"
namespace decompiler {
@@ -230,6 +231,7 @@ void set_vertices_for_tri(tfrag3::CollisionMesh::Vertex* out, const math::Vector
void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
const Config& config,
const std::string& debug_name,
tfrag3::Level& out,
bool dump_level) {
@@ -260,8 +262,8 @@ void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
if (dump_level) {
auto debug_out = debug_dump_to_obj(all_frags);
auto file_path =
file_util::get_file_path({"debug_out", fmt::format("collide-{}.obj", debug_name)});
auto file_path = file_util::get_file_path(
{fmt::format("debug_out/{}", config.game_name), fmt::format("collide-{}.obj", debug_name)});
file_util::create_dir_if_needed_for_file(file_path);
file_util::write_text_file(file_path, debug_out);
}
@@ -408,10 +410,40 @@ void handle_collide_fragment(const TypedRef& collide_fragment,
}
}
std::string debug_dump_to_obj(const std::vector<tfrag3::CollisionMesh::Vertex>& verts_in) {
std::vector<math::Vector4f> verts;
std::vector<math::Vector<u32, 3>> faces;
for (auto& v : verts_in) {
verts.emplace_back(v.x / 4096.0, v.y / 4096.0, v.z / 4096.0, 1.0);
u32 v_len = verts.size();
if (v_len % 3 == 0) {
// add face from last 3 vertices
faces.emplace_back(v_len - 2, v_len - 1, v_len);
}
}
std::string result;
for (auto& vert : verts) {
result += fmt::format("v {} {} {}\n", vert.x(), vert.y(), vert.z());
}
for (auto& face : faces) {
result += fmt::format("f {}/{} {}/{} {}/{}\n", face.x(), face.x(), face.y(), face.y(), face.z(),
face.z());
}
return result;
}
void extract_collide_frags(const level_tools::CollideHash& chash,
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
const Config& config,
const std::string& debug_name,
const decompiler::DecompilerTypeSystem& dts,
tfrag3::Level& out) {
tfrag3::Level& out,
bool dump_level) {
// We need to find all collide-hash-fragments, but we can't just scan through the entire file.
// for collide-hash-fragments, we need to figure out which TIEs they belong to, to apply the
// instance transformation matrix.
@@ -474,5 +506,15 @@ void extract_collide_frags(const level_tools::CollideHash& chash,
}
}
}
if (dump_level) {
// out.collision.vertices every 3 vertices make a face, so it duplicates vertices in many cases
// for now debug_dump_to_obj isn't smart and doesn't hash these to save space or anything
auto debug_out = debug_dump_to_obj(out.collision.vertices);
auto file_path = file_util::get_file_path(
{fmt::format("debug_out/{}", config.game_name), fmt::format("collide-{}.obj", debug_name)});
file_util::create_dir_if_needed_for_file(file_path);
file_util::write_text_file(file_path, debug_out);
}
}
} // namespace decompiler
@@ -8,13 +8,17 @@ namespace decompiler {
void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
const Config& config,
const std::string& debug_name,
tfrag3::Level& out,
bool dump_level);
void extract_collide_frags(const level_tools::CollideHash& chash,
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
const Config& config,
const std::string& debug_name,
const decompiler::DecompilerTypeSystem& dts,
tfrag3::Level& out);
tfrag3::Level& out,
bool dump_level);
} // namespace decompiler
} // namespace decompiler
+7 -5
View File
@@ -159,9 +159,10 @@ std::vector<level_tools::TextureRemap> extract_tex_remap(const ObjectFileDB& db,
level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
const TextureDB& tex_db,
const std::string& dgo_name,
const DecompileHacks& hacks,
const Config& config,
bool extract_collision,
tfrag3::Level& level_data) {
auto hacks = config.hacks;
auto bsp_rec = get_bsp_file(db.obj_files_by_dgo.at(dgo_name), dgo_name);
if (!bsp_rec) {
lg::warn("Skipping extract for {} because the BSP file was not found", dgo_name);
@@ -236,8 +237,8 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
ASSERT(as_collide_frags);
ASSERT(!got_collide);
got_collide = true;
extract_collide_frags(as_collide_frags, all_ties, fmt::format("{}-{}-collide", dgo_name, i++),
level_data, false);
extract_collide_frags(as_collide_frags, all_ties, config,
fmt::format("{}-{}-collide", dgo_name, i++), level_data, false);
} else {
lg::print(" unsupported tree {}\n", draw_tree->my_type());
}
@@ -245,7 +246,8 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
if (bsp_header.collide_hash.num_items) {
ASSERT(!got_collide);
extract_collide_frags(bsp_header.collide_hash, all_ties, db.dts, level_data);
extract_collide_frags(bsp_header.collide_hash, all_ties, config,
fmt::format("{}-{}-collide", dgo_name, i++), db.dts, level_data, false);
}
level_data.level_name = level_name;
@@ -348,7 +350,7 @@ void extract_from_level(const ObjectFileDB& db,
// the bsp header file data
auto bsp_header =
extract_bsp_from_level(db, tex_db, dgo_name, config.hacks, extract_collision, level_data);
extract_bsp_from_level(db, tex_db, dgo_name, config, extract_collision, level_data);
extract_art_groups_from_level(db, tex_db, bsp_header.texture_remap_table, dgo_name, level_data,
art_group_data);
+14 -2
View File
@@ -424,7 +424,8 @@ void make_draws(tfrag3::Level& lev,
std::vector<std::vector<u32>> indices_regrouped_by_draw;
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
size_t global_vert_counter = 0;
for (auto& proto : protos) {
for (u32 proto_idx = 0; proto_idx < protos.size(); proto_idx++) {
auto& proto = protos[proto_idx];
// packed_vert_indices[frag][draw] = {start, end}
std::vector<std::vector<std::pair<int, int>>> packed_vert_indices;
@@ -509,7 +510,9 @@ void make_draws(tfrag3::Level& lev,
std::vector<u32>* verts_to_add_to = nullptr;
if (existing_draws_in_tex != static_draws_by_tex.end()) {
for (auto idx : existing_draws_in_tex->second) {
if (tree_out.static_draws.at(idx).mode == mode) {
auto& candidate_draw_out = tree_out.static_draws.at(idx);
if (candidate_draw_out.mode == mode && (!tree_out.has_per_proto_visibility_toggle ||
candidate_draw_out.proto_idx == proto_idx)) {
draw_to_add_to = &tree_out.static_draws[idx];
verts_to_add_to = &indices_regrouped_by_draw[idx];
}
@@ -523,6 +526,9 @@ void make_draws(tfrag3::Level& lev,
draw_to_add_to = &tree_out.static_draws.back();
draw_to_add_to->mode = mode;
draw_to_add_to->tree_tex_id = idx_in_lev_data;
if (tree_out.has_per_proto_visibility_toggle) {
draw_to_add_to->proto_idx = proto_idx;
}
verts_to_add_to = &indices_regrouped_by_draw.emplace_back();
}
@@ -573,10 +579,16 @@ void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
bool dump_level,
GameVersion version) {
auto& tree_out = out.shrub_trees.emplace_back();
if (version > GameVersion::Jak1) {
tree_out.has_per_proto_visibility_toggle = true;
}
auto& protos = tree->info.prototype_inline_array_shrub;
std::vector<ShrubProtoInfo> proto_info;
for (auto& proto : protos.data) {
proto_info.push_back(extract_proto(proto, tex_db, map, version));
tree_out.proto_names.push_back(proto.name);
}
for (auto& arr : tree->discovered_arrays) {
+23
View File
@@ -115,6 +115,29 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
});
}
void DecompilerTypeSystem::parse_enum_defs(const std::vector<std::string>& file_path) {
auto read = m_reader.read_from_file(file_path);
auto& data = cdr(read);
for_each_in_list(data, [&](goos::Object& o) {
try {
if (car(o).as_symbol() == "defenum") {
auto symbol_metadata = DefinitionMetadata();
parse_defenum(cdr(o), &ts, &symbol_metadata);
symbol_metadata.definition_info = m_reader.db.get_short_info_for(o);
auto* rest = &cdr(o);
const auto& enum_name = car(*rest).as_symbol();
symbol_metadata_map[enum_name.name_ptr] = symbol_metadata;
// so far, enums are never runtime types so there's no symbol for them.
}
} catch (std::exception& e) {
auto info = m_reader.db.get_info_for(o);
lg::error("{} when parsing decompiler type file:{}", e.what(), info);
throw;
}
});
}
TypeSpec DecompilerTypeSystem::parse_type_spec(const std::string& str) const {
auto read = m_reader.read_from_string(str);
auto data = cdr(read);
+1
View File
@@ -56,6 +56,7 @@ class DecompilerTypeSystem {
const TypeSpec& type_spec,
const DefinitionMetadata& symbol_metadata);
void parse_type_defs(const std::vector<std::string>& file_path);
void parse_enum_defs(const std::vector<std::string>& file_path);
TypeSpec parse_type_spec(const std::string& str) const;
void add_type_flags(const std::string& name, u64 flags);
void add_type_parent(const std::string& child, const std::string& parent);
File diff suppressed because it is too large. Load diff
@@ -1,4 +1,243 @@
{
"cutscenes": {},
"other": {}
"other": {
"erol002": {
"lines": [
{
"frame_end": 100,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "errol"
},
{
"frame_end": 162,
"frame_start": 101,
"merge": false,
"offscreen": true,
"speaker": "errol"
},
{
"frame_end": 277,
"frame_start": 163,
"merge": false,
"offscreen": true,
"speaker": "errol"
},
{
"frame_end": 348,
"frame_start": 278,
"merge": false,
"offscreen": true,
"speaker": "errol"
},
{
"frame_end": 425,
"frame_start": 349,
"merge": false,
"offscreen": true,
"speaker": "errol"
},
{
"frame_end": 588,
"frame_start": 426,
"merge": false,
"offscreen": true,
"speaker": "errol"
},
{
"frame_end": 815,
"frame_start": 589,
"merge": false,
"offscreen": true,
"speaker": "errol"
}
]
},
"jakfall": {
"lines": [
{
"frame_end": 93,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "jak"
}
]
},
"mtn-plat-buried-rocks-a": {
"lines": [
{
"frame_end": 168,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "none"
}
]
},
"mtn-step-plat-rocks-a": {
"lines": [
{
"frame_end": 88,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "none"
}
]
},
"mtn-step-plat-rocks-b": {
"lines": [
{
"frame_end": 92,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "none"
}
]
},
"mtn-step-plat-rocks-c": {
"lines": [
{
"frame_end": 80,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "none"
}
]
},
"sam001": {
"lines": [
{
"frame_end": 120,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "youngsamos"
},
{
"frame_end": 273,
"frame_start": 121,
"merge": false,
"offscreen": true,
"speaker": "youngsamos"
},
{
"frame_end": 423,
"frame_start": 274,
"merge": false,
"offscreen": true,
"speaker": "youngsamos"
},
{
"frame_end": 479,
"frame_start": 424,
"merge": false,
"offscreen": true,
"speaker": "youngsamos"
}
]
},
"sigc001": {
"lines": [
{
"frame_end": 140,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "sig"
}
]
},
"sigc073": {
"lines": [
{
"frame_end": 52,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "sig"
},
{
"frame_end": 151,
"frame_start": 53,
"merge": false,
"offscreen": true,
"speaker": "sig"
}
]
},
"tombplta": {
"lines": [
{
"frame_end": 129,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "none"
}
]
},
"tombpltb": {
"lines": [
{
"frame_end": 350,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "none"
}
]
},
"wtrdrain": {
"lines": [
{
"frame_end": 163,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "none"
}
]
},
"wtrfill": {
"lines": [
{
"frame_end": 165,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "none"
}
]
},
"ys002": {
"lines": [
{
"frame_end": 55,
"frame_start": 0,
"merge": false,
"offscreen": true,
"speaker": "youngsamos"
},
{
"frame_end": 93,
"frame_start": 56,
"merge": false,
"offscreen": true,
"speaker": "samos"
},
{
"frame_end": 153,
"frame_start": 94,
"merge": false,
"offscreen": true,
"speaker": "samos"
}
]
}
}
}
@@ -92,7 +92,7 @@
"1251": "Enemy Health Bars",
"1252": "Vehicle Health Bars",
"1253": "Vehicle Invulnerability",
"1254": "Statistics Page",
"1254": "Statistics",
"1255": "Automatically Grab Collectables",
"1256": "Music Player",
"1257": "No Textures Mode",
@@ -107,6 +107,14 @@
"1260": "JET-Board Trick Display",
"1261": "Bad Weather",
"1262": "Nice Weather",
"1263": "Vehicle Hijack Voice Lines",
"1264": "Locked",
"1265": "Hit all 3 valves and find Mar's Statue in \"~S\" in under ~D seconds",
"1266": "Reduce Haven City's population count by ~D",
"1267": "Reduce Haven City's vehicle count by ~D",
"1268": "Hunt every species of Metal Head",
"1269": "Use the JET-Board to break open containers",
"126a": "Transport the Rift Rider while leaving Samos and Young Samos unscathed",
"1280": "Camera Options",
"1281": "Left/Right (1st Person)",
"1282": "Up/Down (1st Person)",
@@ -142,6 +150,40 @@
"12a0": "Object Shadows",
"12a1": "Normal",
"12a2": "Extended",
"12a3": "No valid resolutions found.",
"12a4": "Automatic",
"12a5": "Bestiary",
"12a6": "Other Statistics",
"12a7": "Total Killed",
"12a8": "Killed by Jak",
"12a9": "Killed by Dark Jak",
"12aa": "Killed by Daxter",
"12ab": "Killed by Others",
"12ac": "Blaster",
"12ad": "Scatter Gun",
"12ae": "Vulcan Fury",
"12af": "Peacemaker",
"12b0": "JET-Board",
"12b1": "JET-Board Trick",
"12b2": "Titan Suit Punch",
"12b3": "Titan Suit Body",
"12b4": "Gunpod",
"12b5": "Punch",
"12b6": "Flop",
"12b7": "Uppercut",
"12b8": "Spin",
"12b9": "Roll",
"12bf": "Dark Bomb",
"12c0": "Dark Blast",
"12c3": "Krimzon Guard",
"12c4": "Sig",
"12c5": "Ashelin",
"12c6": "Jinx",
"12c7": "Grim",
"12c8": "Mog",
"12c9": "Metal Heads",
"12ca": "Other Friends",
"12cb": "Other Enemies",
"1300": "Auto Hide Cursor",
"1301": "Reassign Binds",
"1302": "Controller Binds",
@@ -164,6 +206,7 @@
"1313": "Local Time",
"1314": "Warning!",
"1315": "This setting is highly experimental. When not played at 60 frames per second, visual and gameplay issues may arise as a result.",
"1316": "Local Score",
"1320": "None",
"1321": "Spin",
"1322": "Boost",
@@ -1,6 +1,6 @@
{
"1a3": "Veuillez ne pas retirer ou insérer de périphériques, éteindre votre système ou arreter le jeu",
"1b5": "Lorsque cette icône est à l'écran, ne retirez pas ou n'insérez aucun périphérique, n'éteignez pas votre système et n'arretez pas le jeu",
"1a3": "Sauvegarde en cours. Veuillez à ne retirer ou n'insérer aucun périphérique, ni éteindre votre système ou arrêter le jeu.",
"1b5": "Lorsque cette icône est à l'écran, ne retirez ou n'insérez aucun périphérique, ni éteindre votre système ou arrêter le jeu.",
"1100": "Pas dans une mission",
"1101": "Jouer une mission bonus",
"1102": "Pulvérisator (Entrainement)",
@@ -10,84 +10,84 @@
"1106": "Le jeu d'Onin",
"1107": "Chasse-taupe",
"1200": "Mode d'affichage",
"1201": "Fenetré",
"1201": "Fenêtré",
"1202": "Plein écran",
"1203": "Sans bordures",
"1204": "Auto",
"1203": "Sans bordure",
"1204": "Adapté à la fenêtre",
"1205": "Personnalisé",
"1206": "4x3",
"1207": "16x9",
"1207": "16x9 (4x3 zoomé en vertical)",
"1208": "Choisissez le rapport entre la largeur/hauteur",
"1209": "Appuyer sur <PAD_X> pour confirmer et quitter.",
"120a": "Appuyer <PAD_CIRCLE> pour confirmer et quitter.",
"1209": "Appuyer sur <PAD_X> pour confirmer.",
"120a": "Appuyer <PAD_CIRCLE> pour confirmer.",
"120b": "Le ratio ne doit pas être inférieur à 4x3!",
"120c": "Lecteur de musique",
"120c": "Musiques",
"120d": "Synchronisation Verticale",
"120e": "Langue du texte",
"120f": "Secrets OpenGoal",
"1210": "Largeur",
"1211": "Hauteur",
"1212": "??????????",
"1213": "Lecture en cours...",
"1214": "No Track",
"1215": "Défaut",
"1216": "Morph Gun",
"1217": "Jet Board",
"1218": "Titan Suit",
"1219": "Dark Jak",
"121a": "Vehicule",
"1212": "Non débloqué",
"1213": "Lecture en cours :",
"1214": "Pas de musique",
"1215": "Normal",
"1216": "Avec une arme",
"1217": "Sur le Jet Board",
"1218": "Dans la Titanocombi",
"1219": "En Dark Jak",
"121a": "Dans un Véhicule",
"121b": "Danger",
"121c": "Sans",
"121c": "Non",
"121d": "Faible",
"121e": "Moyen",
"121f": "Élevé",
"1220": "Exploration d'Abriville",
"1220": "Abriville",
"1221": "Course-poursuite",
"1222": "Chasse-taupes (Alt)",
"1223": "Le tombeau de Mar",
"1222": "Inutilisé (Jak 3)",
"1223": "Araignée géante",
"1224": "Le défi d'Onin",
"1225": "Métal Kor",
"1225": "Praxis / Métal Kor",
"1226": "Combat contre Krew",
"1227": "Combat contre le Baron",
"1228": "Bouncing Boulders",
"1229": "Eco explosive",
"1227": "Praxis au tombeau",
"1228": "Éboulement",
"1229": "Bombes plasmites",
"122a": "Tank de la forteresse",
"122b": "Station de pompage",
"122c": "Protéger Sig",
"122d": "Mine à ciel ouvert",
"122e": "Forêt d'Abriville",
"122f": "Dragons de la foret",
"122e": "Abriforêt",
"122f": "Abriforêt 2 / Crédits",
"1230": "La forteresse",
"1231": "Fuite",
"1232": "Temple de la montagne",
"1233": "Chasse-taupe",
"1234": "Palais du baron Praxis",
"1231": "La forteresse 2",
"1232": "Temple montagne",
"1233": "Rhinocéros",
"1234": "Palais",
"1235": "Usine d'armes",
"1236": "Course d'arène",
"1236": "Les courses",
"1237": "Ville morte",
"1238": "Taille de la fenetre",
"1239": "Sélectionnez la taille de la fenetre",
"1238": "Taille de la fenêtre",
"1239": "Sélectionnez une taille",
"123a": "Résolution du jeu",
"123b": "Sélectionnez la résolution du jeu",
"123c": "Niveau des détails (arrière-plan)",
"123d": "Niveau des détails (premier plan)",
"123c": "Niveau des textures",
"123d": "Distance d'affichage des unités",
"123f": "Nom de l'orateur",
"1240": "Jamais",
"1241": "Hors écran",
"1242": "Toujours",
"1243": "Game Territory",
"1244": "America (SCEA)",
"1243": "Territoire de jeu",
"1244": "Amérique (SCEA)",
"1245": "Europe (SCEE)",
"1246": "Japan (SCEI)",
"1247": "Korea (SCEK)",
"1248": "MSAA",
"1246": "Japon (SCEI)",
"1247": "Corée (SCEK)",
"1248": "Anti-Aliasing",
"1249": "~DX",
"124a": "Options de la LED du contrôleur",
"124b": "Afficher l'état du joueur",
"124c": "Afficher le niveau de santé",
"124d": "Désactiver la sauvegarde automatique",
"124e": "Sauvegarde automatique désactivée",
"124f": "Etes-vous sûr de vouloir désactiver la sauvegarde automatique?",
"124f": "Êtes-vous sûr de vouloir désactiver la sauvegarde automatique ?",
"1250": "Turbo Jet Board dans Abriville",
"1251": "Barres de santé des ennemis",
"1252": "Barres de santé des véhicules",
@@ -104,24 +104,24 @@
"125d": "Suivi des orbes",
"125e": "Heure réelle de la journée",
"125f": "Ruines d'Abriville",
"1260": "Afficher les figures de Jet Board",
"1260": "Afficher les figures du Jet Board",
"1261": "Mauvais temps",
"1262": "Beau temps",
"1280": "Options de caméra",
"1281": "Gauche/Droite (1ere Personne)",
"1282": "Haut/Bas (1ere Personne)",
"1283": "Gauche/Droite (3eme Personne)",
"1284": "Haut/Bas (3eme Personne)",
"1281": "Horizontal (1ère Personne)",
"1282": "Vertical (1ère Personne)",
"1283": "Horizontal (3ème Personne)",
"1284": "Vertical (3ème Personne)",
"1285": "Réinitialiser les paramètres par défaut",
"1286": "Normale",
"1287": "Inversée",
"1288": "Élimination des particules",
"1289": "Discord Rich-Presence",
"128a": "Défaut",
"1289": "Rich Presence sur Discord",
"128a": "Par défaut",
"128b": "Bas",
"128c": "Haut",
"128d": "Crédits",
"128e": "Fréquence d'images",
"128e": "Fréquence d'images (FPS)",
"128f": "Autres",
"1290": "Mode speedrun",
"1291": "Options d'entrée",
@@ -129,7 +129,7 @@
"1293": "Options de la manette",
"1294": "Sélectionnez la manette",
"1295": "Zone morte",
"1296": "Ignorer si la fenetre est en arrière-plan",
"1296": "Pause en arrière-plan",
"1297": "Utiliser la LED pour la santé",
"1298": "Utiliser la LED pour d'autres états",
"1299": "Activer le clavier",
@@ -139,9 +139,9 @@
"129d": "Sensibilité horizontale",
"129e": "Sensibilité verticale",
"129f": "Déplacements du personnage",
"12a0": "Object Shadows",
"12a0": "Ombres des objets",
"12a1": "Normal",
"12a2": "Extended",
"12a2": "Élevées",
"1300": "Masquer automatiquement le curseur",
"1301": "Configuration des touches",
"1302": "Affectation des boutons de la manette",
@@ -164,8 +164,8 @@
"1313": "Heure locale",
"1314": "Attention !",
"1315": "Ce paramètre est expérimental. Si le jeu n'est pas joué à 60 images par seconde, des problèmes visuels et de gameplay peuvent survenir.",
"1320": "None",
"1321": "Spin",
"1320": "Rien",
"1321": "Tourbillon",
"1322": "Boost",
"1323": "Flip",
"1324": "Rail Grind",
@@ -183,11 +183,11 @@
"1330": "Dark Bomb",
"1331": "Dark Blast",
"1332": "Dark Giant",
"1333": "PS2 Options",
"1333": "Options PS2",
"1334": "Actor Culling",
"1335": "Force Environment Mapping",
"1336": "Fast Progress Menu",
"1336": "Menu de pause rapide",
"1337": "PS2 LOD Distance",
"1338": "Off",
"1339": "Display"
"1339": "Écran"
}
+2
View File
@@ -559,6 +559,7 @@
030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,
030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
@@ -1408,6 +1409,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -45,6 +45,13 @@ void Shrub::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProf
memcpy(&m_pc_port_data, pc_port_data.data, sizeof(TfragPcPortData));
m_pc_port_data.level_name[11] = '\0';
if (render_state->version == GameVersion::Jak2) {
// jak 2 proto visibility
auto proto_mask_data = dma.read_and_advance();
m_proto_vis_data = proto_mask_data.data;
m_proto_vis_data_size = proto_mask_data.size_bytes;
}
while (dma.current_tag_offset() != render_state->next_bucket) {
dma.read_and_advance();
}
@@ -91,6 +98,13 @@ void Shrub::update_load(const LevelData* loader_data) {
m_trees[l_tree].vertex_buffer = loader_data->shrub_vertex_data[l_tree];
m_trees[l_tree].vert_count = verts;
m_trees[l_tree].draws = &tree.static_draws;
m_trees[l_tree].proto_vis_mask.clear();
m_trees[l_tree].proto_vis_mask.resize(tree.proto_names.size(), true);
m_trees[l_tree].proto_name_to_idx.clear();
size_t i = 0;
for (auto& name : tree.proto_names) {
m_trees[l_tree].proto_name_to_idx[name].push_back(i++);
}
m_trees[l_tree].colors = &tree.time_of_day_colors;
m_trees[l_tree].index_data = tree.indices.data();
m_trees[l_tree].tod_cache = swizzle_time_of_day(tree.time_of_day_colors);
@@ -216,6 +230,45 @@ void Shrub::render_all_trees(const TfragRenderSettings& settings,
}
}
namespace {
void update_vis_mask(std::vector<bool>& vis_mask,
const u8* data,
u32 data_size,
const std::unordered_map<std::string, std::vector<u32>>& name_to_idx) {
char name_buffer[256]; // ??
for (u32 i = 0; i < vis_mask.size(); i++) {
vis_mask[i] = true;
}
const u8* end = data + data_size;
while (true) {
int name_idx = 0;
while (*data) {
name_buffer[name_idx++] = *data;
data++;
}
if (name_idx) {
ASSERT(name_idx < 254);
name_buffer[name_idx] = '\0';
const auto& it = name_to_idx.find(name_buffer);
if (it != name_to_idx.end()) {
for (auto x : name_to_idx.at(name_buffer)) {
vis_mask[x] = 0;
}
}
}
while (*data == 0) {
if (data >= end) {
return;
}
data++;
}
}
}
} // namespace
void Shrub::render_tree(int idx,
const TfragRenderSettings& settings,
SharedRenderState* render_state,
@@ -259,6 +312,10 @@ void Shrub::render_tree(int idx,
glActiveTexture(GL_TEXTURE0);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(UINT32_MAX);
if (m_proto_vis_data) {
update_vis_mask(tree.proto_vis_mask, m_proto_vis_data, m_proto_vis_data_size,
tree.proto_name_to_idx);
}
tree.perf.tod_time.add(setup_timer.getSeconds());
int last_texture = -1;
@@ -282,6 +339,9 @@ void Shrub::render_tree(int idx,
for (size_t draw_idx = 0; draw_idx < tree.draws->size(); draw_idx++) {
const auto& draw = tree.draws->operator[](draw_idx);
if (!tree.proto_vis_mask.at(draw.proto_idx)) {
continue;
}
const auto& multidraw_indices = m_cache.multidraw_offset_per_stripdraw[draw_idx];
const auto& singledraw_indices = m_cache.draw_idx_temp[draw_idx];
@@ -42,6 +42,8 @@ class Shrub : public BucketRenderer {
const std::vector<tfrag3::TimeOfDayColor>* colors = nullptr;
const u32* index_data = nullptr;
SwizzledTimeOfDay tod_cache;
std::vector<bool> proto_vis_mask;
std::unordered_map<std::string, std::vector<u32>> proto_name_to_idx;
struct {
u32 draws = 0;
@@ -78,4 +80,6 @@ class Shrub : public BucketRenderer {
std::vector<void*> multidraw_index_offset_buffer;
} m_cache;
TfragPcPortData m_pc_port_data;
const u8* m_proto_vis_data = nullptr;
int m_proto_vis_data_size = 0;
};
@@ -365,7 +365,7 @@ void Loader::update_blocking(TexturePool& tex_pool) {
}
const std::string* Loader::get_most_unloadable_level() {
for (const auto& [name, lev] : m_loaded_tfrag3_levels) {
for (auto& [name, lev] : m_loaded_tfrag3_levels) {
if (lev->frames_since_last_used > 180 &&
std::find(m_desired_levels.begin(), m_desired_levels.end(), name) ==
m_desired_levels.end()) {
@@ -511,7 +511,7 @@ void Loader::update(TexturePool& texture_pool) {
}
if (unload_timer.getMs() > 5.f) {
fmt::print("Unload took {:.2f}\n", unload_timer.getMs());
fmt::print("Unload took {:.2f}ms\n", unload_timer.getMs());
}
if (!m_garbage_buffers.empty()) {
+16 -8
View File
@@ -512,13 +512,13 @@ void pc_get_active_display_size(u32 w_ptr, u32 h_ptr) {
return;
}
if (w_ptr) {
auto w_out = Ptr<u32>(w_ptr).c();
auto w_out = Ptr<s64>(w_ptr).c();
if (w_out) {
*w_out = Display::GetMainDisplay()->get_display_manager()->get_screen_width();
}
}
if (h_ptr) {
auto h_out = Ptr<u32>(h_ptr).c();
auto h_out = Ptr<s64>(h_ptr).c();
if (h_out) {
*h_out = Display::GetMainDisplay()->get_display_manager()->get_screen_height();
}
@@ -537,13 +537,13 @@ void pc_get_window_size(u32 w_ptr, u32 h_ptr) {
return;
}
if (w_ptr) {
auto w = Ptr<u32>(w_ptr).c();
auto w = Ptr<s64>(w_ptr).c();
if (w) {
*w = Display::GetMainDisplay()->get_display_manager()->get_window_width();
}
}
if (h_ptr) {
auto h = Ptr<u32>(h_ptr).c();
auto h = Ptr<s64>(h_ptr).c();
if (h) {
*h = Display::GetMainDisplay()->get_display_manager()->get_window_height();
}
@@ -590,11 +590,11 @@ s64 pc_get_num_resolutions() {
void pc_get_resolution(u32 id, u32 w_ptr, u32 h_ptr) {
if (Display::GetMainDisplay()) {
auto res = Display::GetMainDisplay()->get_display_manager()->get_resolution(id);
auto w = Ptr<u32>(w_ptr).c();
auto w = Ptr<s64>(w_ptr).c();
if (w) {
*w = res.width;
}
auto h = Ptr<u32>(h_ptr).c();
auto h = Ptr<s64>(h_ptr).c();
if (h) {
*h = res.height;
}
@@ -664,7 +664,14 @@ u64 pc_get_controller_count() {
return 0;
}
void pc_get_controller(u32 controller_id, u32 port) {
u64 pc_get_controller_index(u32 port) {
if (Display::GetMainDisplay()) {
return Display::GetMainDisplay()->get_input_manager()->get_controller_index(port);
}
return 0;
}
void pc_set_controller(u32 controller_id, u32 port) {
if (Display::GetMainDisplay()) {
Display::GetMainDisplay()->get_input_manager()->set_controller_for_port(controller_id, port);
}
@@ -913,7 +920,8 @@ void init_common_pc_port_functions(
make_func_symbol_func("pc-get-controller-name", (void*)pc_get_controller_name);
make_func_symbol_func("pc-get-current-bind", (void*)pc_get_current_bind);
make_func_symbol_func("pc-get-controller-count", (void*)pc_get_controller_count);
make_func_symbol_func("pc-set-controller!", (void*)pc_get_controller);
make_func_symbol_func("pc-get-controller-index", (void*)pc_get_controller_index);
make_func_symbol_func("pc-set-controller!", (void*)pc_set_controller);
make_func_symbol_func("pc-set-keyboard-enabled!", (void*)pc_set_keyboard_enabled);
make_func_symbol_func("pc-set-mouse-options!", (void*)pc_set_mouse_options);
make_func_symbol_func("pc-set-mouse-camera-sens!", (void*)pc_set_mouse_camera_sens);
+1 -1
View File
@@ -70,7 +70,7 @@ void load_and_link_dgo_from_c_fast(const char* name,
// open the DGO file:
auto file_path = file_util::get_jak_project_dir() / "out" / game_version_names[g_game_version] /
"iso" / name_on_cd;
auto fp = fopen(file_path.string().c_str(), "rb");
auto fp = file_util::open_file(file_path, "rb");
if (!fp) {
lg::die("Failed to open DGO: {}, path {}\n", name, file_path.string());
}
+15 -14
View File
@@ -730,22 +730,23 @@ std::unordered_map<std::string, std::vector<std::pair<std::string, float>>>
external_highscores_cache = {};
// clang-format off
// TODO - eventually don't depend on SRC
const std::unordered_map<std::string, std::string> external_speedrun_lookup_urls = {
{"any", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/wdmze42q?embed=players&max=200"},
{"anyhoverless", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/xd1rxxrk?embed=players&max=200"},
{"allmissions", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/mkeon9d6?embed=players&max=200"},
{"100", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/7dg8q424?embed=players&max=200"},
{"anyorbs", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/wkpj7vkr?embed=players&max=200"},
{"anyhero", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/category/vdo0jodp?embed=players&max=200"}};
{"any", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/n2y6y4ed?embed=players&max=200"},
{"anyhoverless", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/7kjyn5gk?embed=players&max=200"},
{"allmissions", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/xk96myxk?embed=players&max=200"},
{"100", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/z27exp5k?embed=players&max=200"},
{"anyorbs", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/zdn3vm72?embed=players&max=200"},
{"anyhero", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/category/q25pv0wd?embed=players&max=200"}};
const std::unordered_map<std::string, std::string> external_race_lookup_urls = {
{"class3", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/rw6vp697/xd1738d8?embed=players&max=200"},
{"class2", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/n9305r90/xd1738d8?embed=players&max=200"},
{"class1", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/z98jv1wl/xd1738d8?embed=players&max=200"},
{"class3rev", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/rdn5j6dm/xd1738d8?embed=players&max=200"},
{"class2rev", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/ldye77w3/xd1738d8?embed=players&max=200"},
{"class1rev", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/gdrqkk9z/xd1738d8?embed=players&max=200"},
{"erol", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/nwl7kg9v/xd1738d8?embed=players&max=200"},
{"port", "https://www.speedrun.com/api/v1/leaderboards/ok6qlo1g/level/ywe8z4wl/xd1738d8?embed=players&max=200"}};
{"class3", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/y9m7qmx9/jdr0mg0d?embed=players&max=200"},
{"class2", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/5wk5zmpw/jdr0mg0d?embed=players&max=200"},
{"class1", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/5922g639/jdr0mg0d?embed=players&max=200"},
{"class3rev", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/29v4e8l9/jdr0mg0d?embed=players&max=200"},
{"class2rev", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/xd4475rd/jdr0mg0d?embed=players&max=200"},
{"class1rev", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/xd0mre4w/jdr0mg0d?embed=players&max=200"},
{"erol", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/rw68p7gd/jdr0mg0d?embed=players&max=200"},
{"port", "https://www.speedrun.com/api/v1/leaderboards/3dxk47y1/level/n93v5xzd/jdr0mg0d?embed=players&max=200"}};
const std::unordered_map<std::string, std::string> external_highscores_lookup_urls = {
{"scatter", "https://api.jakspeedruns.workers.dev/v1/highscores/2"},
{"blaster", "https://api.jakspeedruns.workers.dev/v1/highscores/3"},
+1 -1
View File
@@ -127,7 +127,7 @@ int main(int argc, char** argv) {
CLI11_PARSE(app, argc, argv);
if (show_version) {
lg::print(build_revision());
lg::print("{}", build_revision());
return 0;
}
+26 -24
View File
@@ -19,10 +19,12 @@ SoundBank* gBanks[N_BANKS] = {&gCommonBank, &gGunBank, &gBoardBank,
&gLevelBanks[0], &gLevelBanks[1], &gLevelBanks[2]};
void sbank_init_globals() {
memset((void*)&gCommonBank, 0, sizeof(gCommonBank));
memset((void*)&gGunBank, 0, sizeof(gGunBank));
memset((void*)&gBoardBank, 0, sizeof(gBoardBank));
memset((void*)&gLevelBanks, 0, sizeof(gLevelBanks));
gCommonBank = {};
gGunBank = {};
gBoardBank = {};
for (auto& b : gLevelBanks) {
b = {};
}
}
void InitBanks() {
@@ -30,34 +32,41 @@ void InitBanks() {
bank->bank_handle = 0;
bank->sound_count = 0;
bank->in_use = false;
bank->unk4 = 0;
// paper over version differences
// in_use doesn't exist in jak1, but setting it to true
// for all banks results in the same behaviour
if (g_game_version == GameVersion::Jak1) {
bank->in_use = true;
} else {
bank->in_use = false;
}
strcpy(bank->name, "<unused>");
bank->unk4 = 0;
strcpy(bank->name.data(), "<unused>");
}
if (g_game_version == GameVersion::Jak2) {
strncpy(gBanks[0]->name, "common", 16);
strncpy(gBanks[0]->name.data(), "common", 16);
gBanks[0]->spu_loc = 0x20000;
gBanks[0]->spu_size = 0xAFCC0;
strncpy(gBanks[1]->name, "gun", 16);
strncpy(gBanks[1]->name.data(), "gun", 16);
gBanks[1]->spu_loc = 0x131740;
gBanks[1]->spu_size = 0;
strncpy(gBanks[2]->name, "board", 16);
strncpy(gBanks[2]->name.data(), "board", 16);
gBanks[2]->spu_loc = 0x131740;
gBanks[2]->spu_size = 0;
strncpy(gBanks[3]->name, "level0", 16);
strncpy(gBanks[3]->name.data(), "level0", 16);
gBanks[3]->spu_loc = 0x131740;
gBanks[3]->spu_size = 0x42800;
strncpy(gBanks[4]->name, "level1", 16);
strncpy(gBanks[4]->name.data(), "level1", 16);
gBanks[4]->spu_loc = 0x173f40;
gBanks[4]->spu_size = 0x42800;
strncpy(gBanks[5]->name, "level2", 16);
strncpy(gBanks[5]->name.data(), "level2", 16);
gBanks[5]->spu_loc = 0x1B6740;
gBanks[5]->spu_size = 0x42800;
}
@@ -111,7 +120,7 @@ s32 LookupSoundIndex(const char* name, SoundBank** bank_out) {
}
for (int i = 0; i < (int)bank->sound_count; i++) {
if (memcmp(bank->sound[i].name, name, 16) == 0) {
if (memcmp(bank->sound[i].name.data(), name, 16) == 0) {
*bank_out = bank;
return i;
}
@@ -129,16 +138,9 @@ SoundBank* LookupBank(const char* name) {
return nullptr; // not found.
}
auto bank = gBanks[idx];
// they had some weird stuff here that took advantage of the fact that this region was
// 16-byte aligned, so it probably wasn't a memcmp, but this is easier.
if (g_game_version == GameVersion::Jak1) {
if ((memcmp(bank->name, name, 16) == 0)) {
return bank;
}
} else {
if ((memcmp(bank->name, name, 16) == 0) && bank->in_use) {
return bank;
}
if ((memcmp(bank->name.data(), name, 16) == 0) && bank->in_use) {
return bank;
}
idx--;
}
+16 -16
View File
@@ -1,31 +1,31 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "game/sound/sndshim.h"
struct SoundRecord {
char name[16];
std::array<char, 16> name;
u32 fallof_params;
};
struct SoundBank {
char name[16];
u32 bank_handle;
std::array<char, 16> name;
snd::BankHandle bank_handle;
u32 sound_count;
union {
SoundRecord sound[1];
// name list, only for jak1
std::vector<SoundRecord> sound;
// Needs to fit the biggest bank (common.sbk)
u8 buffer[10 * 2048];
// Jak 2 additions go here
struct {
u32 spu_loc;
u32 spu_size;
u32 unk4;
bool in_use;
};
};
// jak2 additions
u32 spu_loc;
u32 spu_size;
u32 unk4;
bool in_use;
};
void sbank_init_globals();
+2 -2
View File
@@ -33,10 +33,10 @@ void PrintBankInfo(SoundBank* bank) {
// we dont need this and it spams the console too much
return;
printf("Bank %s\n\n", bank->name);
printf("Bank %s\n\n", bank->name.data());
for (u32 i = 0; i < bank->sound_count; i++) {
// Some characters use the full 16 characters (bonelurker-grunt) and dont have a null terminator
std::string name = std::string(bank->sound[i].name, 16);
std::string name = std::string(bank->sound[i].name.data(), 16);
printf("%d : %16s : min %d max %d curve %d\n", i, name.c_str(),
bank->sound[i].fallof_params & 0x3fff, (bank->sound[i].fallof_params >> 14) & 0x3fff,
bank->sound[i].fallof_params >> 28);
+3 -1
View File
@@ -2,12 +2,14 @@
#include <cstring>
#include "game/sound/sndshim.h"
// added
u32 gMusicFadeHack = 0;
MusicTweaks gMusicTweakInfo;
s32 gMusicTweak = 0x80;
int32_t gSoundEnable = 1;
s32 gMusic = 0;
snd::BankHandle gMusic = nullptr;
s32 gMusicPause = 0;
s32 gSoundInUse = 0;
u8 gFPS = 60;
+2 -2
View File
@@ -117,10 +117,10 @@ struct SoundRpcSetMirrror {
extern s32 gMusicTweak;
extern MusicTweaks gMusicTweakInfo;
extern int32_t gSoundEnable;
extern s32 gMusic;
extern snd::BankHandle gMusic;
extern s32 gMusicPause;
extern s32 gSoundInUse;
extern u8 gFPS;
extern const char* gLanguage;
extern u32 gFrameNum;
void srpc_init_globals();
void srpc_init_globals();
+71 -112
View File
@@ -11,7 +11,7 @@ Sound gSounds[64];
Vec3w gEarTrans[2];
Vec3w gCamTrans;
s32 gMusicFadeDir = 0;
Curve gCurve[16];
Curve gCurves[16];
s32 gCamAngle;
u8 gMirrorMode = 0;
u32 sLastTick = 0;
@@ -134,10 +134,12 @@ s32 CalculateAngle(Vec3w* trans) {
} else {
angle = angle + 90;
}
} else if (diffZ >= 0) {
angle = angle + 270;
} else {
angle = 270 - angle;
if (diffZ >= 0) {
angle = angle + 270;
} else {
angle = 270 - angle;
}
}
}
@@ -154,7 +156,7 @@ s32 GetPan(Sound* sound) {
return CalculateAngle(&sound->params.trans);
}
s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max) {
s32 CalculateFalloffVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max) {
s32 xdiff = 0;
s32 ydiff = 0;
s32 zdiff = 0;
@@ -170,30 +172,22 @@ s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32
} else {
if (fo_curve == 1) {
return volume;
}
if (fo_curve < 9) {
xdiff = gEarTrans[0].x - pos->x;
ydiff = gEarTrans[0].y - pos->y;
zdiff = gEarTrans[0].z - pos->z;
}
if (fo_curve == 9) {
} else if (fo_curve == 9) {
xdiff = gEarTrans[1].x - pos->x;
ydiff = gEarTrans[1].y - pos->y;
zdiff = gEarTrans[1].z - pos->z;
}
if (fo_curve == 10) {
} else if (fo_curve == 10) {
xdiff = 0;
ydiff = gEarTrans[0].y - pos->y;
zdiff = 0;
}
if (fo_curve == 11) {
} else if (fo_curve == 11) {
xdiff = gEarTrans[1].x - pos->x;
ydiff = gEarTrans[1].y - pos->y;
zdiff = gEarTrans[1].z - pos->z;
} else {
xdiff = gEarTrans[0].x - pos->x;
ydiff = gEarTrans[0].y - pos->y;
zdiff = gEarTrans[0].z - pos->z;
}
}
@@ -210,72 +204,63 @@ s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32
s32 min = fo_min << 8;
s32 max = fo_max << 8;
if (max < xdiff || max < ydiff || max < zdiff) {
return 0;
}
while (max > 0x7FFF) {
max >>= 1;
min >>= 1;
xdiff >>= 1;
ydiff >>= 1;
zdiff >>= 1;
}
u32 distance = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff;
if (distance != 0) {
s32 steps = 0;
while ((distance & 0xc0000000) == 0) {
distance <<= 2;
steps++;
s32 new_vol = 0;
if (xdiff <= max && ydiff <= max && zdiff <= max) {
while (max > 0x7fff) {
max >>= 1;
min >>= 1;
xdiff >>= 1;
ydiff >>= 1;
zdiff >>= 1;
}
s32 dist_squared = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff;
s32 dist_steps = 0;
if (dist_squared != 0) {
while ((dist_squared & 0xc0000000) == 0) {
dist_steps = dist_steps + 1;
dist_squared <<= 2;
}
dist_steps = sqrt_table[dist_squared >> 24] >> (dist_steps & 0x1f);
}
new_vol = volume;
if (min < dist_steps) {
s32 voldiff = dist_steps - min;
if (dist_steps < max) {
dist_steps = max - min;
while (0xffff < voldiff) {
dist_steps >>= 1;
voldiff >>= 1;
}
voldiff = (voldiff << 0x10) / dist_steps;
if (voldiff != 0x10000) {
new_vol = voldiff * voldiff >> 0x10;
new_vol = gCurves[fo_curve].unk4 * 0x10000 + gCurves[fo_curve].unk3 * voldiff +
gCurves[fo_curve].unk2 * new_vol +
gCurves[fo_curve].unk1 * ((new_vol * voldiff) >> 0x10) >>
0xc;
if (new_vol < 0) {
new_vol = 0;
} else {
if (0x10000 < new_vol) {
new_vol = 0x10000;
}
}
new_vol = (new_vol * volume) >> 0x10;
}
} else {
new_vol = 0;
}
}
distance = sqrt_table[distance >> 24] >> steps;
} else {
distance = 0;
}
if (distance <= (u32)min) {
return volume;
if (fo_curve == 11 && new_vol < 0x180) {
new_vol = 0x180;
}
if (distance >= (u32)max) {
return 0;
}
s32 start = distance - min;
s32 end = max - min;
while (start > 0xFFFF) {
start >>= 1;
end >>= 1;
}
s32 v13 = (start << 16) / end;
if (v13 == 0x10000) {
return volume;
}
s32 factor = ((gCurve[fo_curve].unk4 << 16) + gCurve[fo_curve].unk3 * v13 +
gCurve[fo_curve].unk2 * ((v13 * v13) >> 16) +
gCurve[fo_curve].unk1 * (((((v13 * v13) >> 16) * v13) >> 16) >> 16)) >>
12;
if (factor > 0x10000) {
factor = 0x10000;
}
s32 ret = (factor * volume) >> 16;
if (fo_curve == 11 && ret < 0x180) {
ret = 0x180;
}
return ret;
return new_vol;
}
s32 GetVolume(Sound* sound) {
return CalculateFallofVolume(&sound->params.trans, sound->params.volume, sound->params.fo_curve,
sound->params.fo_min, sound->params.fo_max);
return CalculateFalloffVolume(&sound->params.trans, sound->params.volume, sound->params.fo_curve,
sound->params.fo_min, sound->params.fo_max);
}
void UpdateVolume(Sound* sound) {
@@ -322,32 +307,6 @@ void KillSoundsInGroup(u8 group) {
}
}
void UpdateLocation(Sound* sound) {
if (sound->id == 0) {
return;
}
if (g_game_version == GameVersion::Jak1) {
if ((sound->bank_entry->fallof_params >> 28) == 0) {
return;
}
}
s32 id = snd_SoundIsStillPlaying(sound->sound_handle);
if (id == 0) {
sound->id = 0;
return;
}
s32 volume = GetVolume(sound);
if (volume == 0) {
snd_StopSound(sound->sound_handle);
} else {
s32 pan = GetPan(sound);
snd_SetSoundVolPan(id, volume, pan);
}
}
void UpdateAutoVol(Sound* sound, s32 ticks) {
if (ticks < sound->auto_time) {
s32 nvol = sound->new_volume;
@@ -395,12 +354,12 @@ void PrintActiveSounds() {
for (auto& s : gSounds) {
if (s.id != 0 && s.is_music == 0) {
if (s.bank_entry != nullptr) {
u32 len = strlen(s.bank_entry->name);
u32 len = strlen(s.bank_entry->name.data());
if (len > 16) {
len = 16;
}
sprintf(string, " : Vol %d", GetVolume(&s));
memcpy(string, s.bank_entry->name, len);
memcpy(string, s.bank_entry->name.data(), len);
printf("%s\n", string);
} else { // added for printing jak2 sounds
u32 len = strlen(s.name);
@@ -417,8 +376,8 @@ void PrintActiveSounds() {
}
void SetCurve(s32 curve, s32 falloff, s32 ease) {
gCurve[curve].unk1 = ease * 2;
gCurve[curve].unk2 = falloff - 3 * ease;
gCurve[curve].unk3 = ease - falloff - 0x1000;
gCurve[curve].unk4 = 0x1000;
gCurves[curve].unk1 = ease * 2;
gCurves[curve].unk2 = falloff - 3 * ease;
gCurves[curve].unk3 = ease - falloff - 0x1000;
gCurves[curve].unk4 = 0x1000;
}
+2 -3
View File
@@ -52,7 +52,7 @@ struct Curve {
extern Sound gSounds[64];
extern Vec3w gEarTrans[2];
extern Curve gCurve[16];
extern Curve gCurves[16];
extern Vec3w gCamTrans;
extern u8 gMirrorMode;
extern s32 gCamAngle;
@@ -64,11 +64,10 @@ Sound* LookupSound(s32 id);
Sound* AllocateSound();
s32 GetVolume(Sound* sound);
void UpdateVolume(Sound* sound);
s32 CalculateFallofVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max);
s32 CalculateFalloffVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max);
s32 GetPan(Sound* sound);
s32 CalculateAngle(Vec3w* trans);
void KillSoundsInGroup(u8 group);
void UpdateLocation(Sound* sound);
void UpdateAutoVol(Sound* sound, s32 ticks);
void PrintActiveSounds();
void SetCurve(s32 curve, s32 fallof, s32 ease);
+28 -6
View File
@@ -2,6 +2,7 @@
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "common/util/BinaryReader.h"
#include "common/util/FileUtil.h"
#include "game/overlord/common/fake_iso.h"
@@ -18,7 +19,7 @@ LoadStackEntry* FS_OpenWad(FileRecord* fr, int32_t offset);
uint32_t FS_LoadSoundBank(char* name, SoundBank* bank);
void FS_PollDrive();
uint32_t FS_SyncRead();
uint32_t FS_LoadMusic(char* name, s32* bank_handle);
uint32_t FS_LoadMusic(char* name, snd::BankHandle* bank_handle);
void FS_Close(LoadStackEntry* fd);
static LoadStackEntry sLoadStack[MAX_OPEN_FILES]; //! List of all files that are "open"
static LoadStackEntry* sReadInfo; // LoadStackEntry for currently reading file
@@ -200,7 +201,7 @@ uint32_t FS_SyncRead() {
*/
void FS_PollDrive() {}
uint32_t FS_LoadMusic(char* name, s32* bank_handle) {
uint32_t FS_LoadMusic(char* name, snd::BankHandle* bank_handle) {
char namebuf[16];
strcpy(namebuf, name);
namebuf[8] = 0;
@@ -215,9 +216,27 @@ uint32_t FS_LoadMusic(char* name, s32* bank_handle) {
return 0;
}
// original overlord uses good old fread into a struct instance
// lets use BinaryReader instead
static void parseSoundBank(BinaryReader data, SoundBank& bank) {
bank.name = data.read<std::array<char, 16>>();
data.read<u32>();
bank.bank_handle = nullptr;
bank.sound_count = data.read<u32>();
bank.sound.resize(bank.sound_count);
for (auto& snd : bank.sound) {
snd.name = data.read<std::array<char, 16>>();
snd.fallof_params = data.read<u32>();
}
}
uint32_t FS_LoadSoundBank(char* name, SoundBank* bank) {
char namebuf[16];
// sector size of sound name list
int offset = 10 * 2048;
if (bank->sound_count == 101) {
offset = 1 * 2048;
@@ -234,11 +253,14 @@ uint32_t FS_LoadSoundBank(char* name, SoundBank* bank) {
return 0;
}
auto fp = file_util::open_file(get_file_path(file), "rb");
fread(bank, offset, 1, fp);
fclose(fp);
// auto fp = file_util::open_file(get_file_path(file), "rb");
// fread(bank, offset, 1, fp);
// fclose(fp);
s32 handle = snd_BankLoadEx(get_file_path(file), offset, 0, 0);
auto data = file_util::read_binary_file(fs::path(get_file_path(file)));
parseSoundBank(BinaryReader(data), *bank);
snd::BankHandle handle = snd_BankLoadEx(get_file_path(file), offset, 0, 0);
snd_ResolveBankXREFS();
PrintBankInfo(bank);
bank->bank_handle = handle;
+1 -1
View File
@@ -1368,7 +1368,7 @@ static void PauseVAG(VagCommand* vag) {
static void CalculateVAGVolumes(s32 volume, s32 positioned, Vec3w* trans, s32* left, s32* right) {
if (positioned) {
volume = CalculateFallofVolume(trans, (volume * gDialogVolume) >> 10, 1, 10, 50);
volume = CalculateFalloffVolume(trans, (volume * gDialogVolume) >> 10, 1, 10, 50);
auto* pan = &gPanTable[(630 - CalculateAngle(trans)) % 360];
*left = (pan->left * volume) >> 10;
*right = (pan->right * volume) >> 10;
+2 -2
View File
@@ -31,7 +31,7 @@ void LoadSoundBank(const char* bank_name, SoundBank* bank) {
SleepThread(); // wait for finish.
}
void LoadMusic(const char* music_name, s32* bank) {
void LoadMusic(const char* music_name, snd::BankHandle* bank) {
ASSERT(strlen(music_name) < 16);
MusicLoadCommand cmd;
cmd.cmd_id = LOAD_MUSIC;
@@ -203,4 +203,4 @@ s32 LoadISOFileChunkToEE(FileRecord* file, uint32_t dest_addr, uint32_t length,
return cmd.length_to_copy;
}
} // namespace jak1
} // namespace jak1
+1 -1
View File
@@ -7,7 +7,7 @@ struct SoundBank;
namespace jak1 {
struct VagDirEntry;
void LoadSoundBank(const char* bank_name, SoundBank* bank);
void LoadMusic(const char* music_name, s32* bank);
void LoadMusic(const char* music_name, snd::BankHandle* bank);
void QueueVAGStream(FileRecord* file, VagDirEntry* vag, u32 sound_id, u32 unk);
void PlayVAGStream(FileRecord* file,
+2 -2
View File
@@ -58,7 +58,7 @@ struct IsoFs {
uint32_t (*begin_read)(LoadStackEntry*, void*, int32_t); // 1c
uint32_t (*sync_read)(); // 20
uint32_t (*load_sound_bank)(char*, SoundBank*); // 24
uint32_t (*load_music)(char*, s32*);
uint32_t (*load_music)(char*, snd::BankHandle*);
void (*poll_drive)();
};
@@ -173,7 +173,7 @@ struct SoundBankLoadCommand : public IsoMessage {
struct MusicLoadCommand : public IsoMessage {
char music_name[16];
s32* music_handle;
snd::BankHandle* music_handle;
};
/*!
+3 -3
View File
@@ -374,7 +374,7 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) {
case Jak1SoundCommand::UNLOAD_BANK: {
SoundBank* bank = LookupBank(cmd->load_bank.bank_name);
if (bank != nullptr) {
s32 id = bank->bank_handle;
snd::BankHandle id = bank->bank_handle;
bank->bank_handle = 0;
snd_UnloadBank(id);
snd_ResolveBankXREFS();
@@ -403,7 +403,7 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) {
}
snd_UnloadBank(gMusic);
snd_ResolveBankXREFS();
gMusic = 0;
gMusic = nullptr;
}
LoadMusic(cmd->load_bank.bank_name, &gMusic);
SignalSema(gSema);
@@ -508,4 +508,4 @@ s32 VBlank_Handler(void*) {
return 1;
}
} // namespace jak1
} // namespace jak1
+27 -3
View File
@@ -54,13 +54,13 @@ void InitSound_Overlord() {
snd_StartSoundSystem();
snd_RegisterIOPMemAllocator(SndMemAlloc, SndMemFree);
snd_LockVoiceAllocator(1);
u32 voice = snd_ExternVoiceAlloc(2, 0x7f);
s32 voice = snd_ExternVoiceAlloc(2, 0x7f);
snd_UnlockVoiceAllocator();
// The voice allocator returns a number in the range 0-47 where voices
// 0-23 are on SPU Core 0 and 24-47 are on core 2.
// For some reason we convert it to this format where 0-47 alternate core every step.
voice = voice / 24 + ((voice % 24) * 2);
gVoice = voice / 24 + ((voice % 24) * 2);
// Allocate SPU RAM for our streams.
// (Which we don't need on PC)
@@ -115,6 +115,30 @@ void InitSound_Overlord() {
}
}
void UpdateLocation(Sound* sound) {
if (sound->id == 0) {
return;
}
if ((sound->bank_entry->fallof_params >> 28) == 0) {
return;
}
s32 id = snd_SoundIsStillPlaying(sound->sound_handle);
if (id == 0) {
sound->id = 0;
return;
}
s32 volume = GetVolume(sound);
if (volume == 0) {
snd_StopSound(sound->sound_handle);
} else {
s32 pan = GetPan(sound);
snd_SetSoundVolPan(id, volume, pan);
}
}
void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam_angle) {
s32 tick = snd_GetTick();
u32 delta = tick - sLastTick;
@@ -150,4 +174,4 @@ static void* SndMemAlloc() {
return nullptr;
}
static void SndMemFree(void* /*ptr*/) {}
} // namespace jak1
} // namespace jak1
+2 -1
View File
@@ -13,6 +13,7 @@ extern u32 gTrapSRAM;
extern s32 gMusicVol;
void InitSound_Overlord();
void UpdateLocation(Sound* sound);
void SetEarTrans(Vec3w* ear_trans1, Vec3w* ear_trans2, Vec3w* cam_trans, s32 cam_angle);
void SetMusicVol();
} // namespace jak1
} // namespace jak1
+22 -22
View File
@@ -1,5 +1,6 @@
#include "dma.h"
#include "game/overlord/jak2/ssound.h"
#include "game/overlord/jak2/vag.h"
#include "game/sound/sdshim.h"
#include "game/sound/sndshim.h"
@@ -90,30 +91,29 @@ int SpuDmaIntr(int, void*) {
int pitch = CalculateVAGPitch(DmaVagCmd->pitch1, DmaVagCmd->unk_256_pitch2);
if (!DmaStereoVagCmd) {
DmaVagCmd->spu_addr_to_start_playing = 0;
sceSdSetAddr(((s16)DmaVagCmd->voice) | 0x2040, DmaVagCmd->spu_stream_dma_mem_addr + 0x30);
sceSdSetParam((u16)DmaVagCmd->voice | 0x300, 0xf);
sceSdSetParam((u16)DmaVagCmd->voice | 0x400, 0x1fc0);
sceSdSetParam((u16)DmaVagCmd->voice | 0x200, pitch);
sceSdSetAddr(SD_VA_SSA | DmaVagCmd->voice, DmaVagCmd->spu_stream_dma_mem_addr + 0x30);
sceSdSetParam(SD_VP_ADSR1 | DmaVagCmd->voice, 0xf);
sceSdSetParam(SD_VP_ADSR2 | DmaVagCmd->voice, 0x1fc0);
sceSdSetParam(SD_VP_PITCH | DmaVagCmd->voice, pitch);
// start playback!
sceSdkey_on_jak2_voice(DmaVagCmd->voice);
sceSdSetSwitch(SD_S_KON | (DmaVagCmd->voice & 1), VOICE_BIT(DmaVagCmd->voice));
} else {
// same for stereo, but we start both voices.
DmaVagCmd->spu_addr_to_start_playing = 0;
DmaStereoVagCmd->spu_addr_to_start_playing = 0;
sceSdSetAddr((u16)DmaVagCmd->voice | 0x2040, DmaVagCmd->spu_stream_dma_mem_addr + 0x30);
sceSdSetAddr((u16)DmaStereoVagCmd->voice | 0x2040,
sceSdSetAddr(SD_VA_SSA | DmaVagCmd->voice, DmaVagCmd->spu_stream_dma_mem_addr + 0x30);
sceSdSetAddr(SD_VA_SSA | DmaStereoVagCmd->voice,
DmaStereoVagCmd->spu_stream_dma_mem_addr + 0x30);
sceSdSetParam((u16)DmaVagCmd->voice | 0x300, 0xf);
sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x300, 0xf);
sceSdSetParam((u16)DmaVagCmd->voice | 0x400, 0x1fc0);
sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x400, 0x1fc0);
sceSdSetParam((u16)DmaVagCmd->voice | 0x200, pitch);
sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x200, pitch);
sceSdSetParam(SD_VP_ADSR1 | DmaVagCmd->voice, 0xf);
sceSdSetParam(SD_VP_ADSR1 | DmaStereoVagCmd->voice, 0xf);
sceSdSetParam(SD_VP_ADSR2 | DmaVagCmd->voice, 0x1fc0);
sceSdSetParam(SD_VP_ADSR2 | DmaStereoVagCmd->voice, 0x1fc0);
sceSdSetParam(SD_VP_PITCH | DmaVagCmd->voice, pitch);
sceSdSetParam(SD_VP_PITCH | DmaStereoVagCmd->voice, pitch);
sceSdkey_on_jak2_voice(DmaVagCmd->voice);
sceSdkey_on_jak2_voice(DmaStereoVagCmd->voice);
sceSdSetSwitch(SD_S_KON | (DmaVagCmd->voice & 1),
VOICE_BIT(DmaVagCmd->voice) | VOICE_BIT(DmaStereoVagCmd->voice));
}
} else if (DmaVagCmd->num_processed_chunks == 2) {
// on the second chunk's DMA finish, start playing by unpausing.
@@ -127,13 +127,13 @@ int SpuDmaIntr(int, void*) {
// if we paused since the first, kill the voice.
if (DmaVagCmd->sb_paused) {
if (!DmaStereoVagCmd) {
sceSdSetParam((u16)DmaVagCmd->voice | 0x200, 0);
sceSdSetParam(SD_VP_PITCH | DmaVagCmd->voice, 0);
} else {
sceSdSetParam((u16)DmaStereoVagCmd->voice | 0x200, 0);
sceSdSetParam((u16)DmaVagCmd->voice | 0x200, 0);
sceSdkey_off_jak2_voice(DmaStereoVagCmd->voice);
sceSdSetParam(SD_VP_PITCH | DmaStereoVagCmd->voice, 0);
sceSdSetParam(SD_VP_PITCH | DmaVagCmd->voice, 0);
sceSdSetSwitch(SD_S_KOFF | (DmaVagCmd->voice & 1), VOICE_BIT(DmaStereoVagCmd->voice));
}
sceSdkey_off_jak2_voice(DmaVagCmd->voice);
sceSdSetSwitch(SD_S_KOFF | (DmaVagCmd->voice & 1), VOICE_BIT(DmaVagCmd->voice));
goto hack;
}
@@ -231,4 +231,4 @@ void DmaCancelThisVagCmd(VagCmd* param_1) {
}
}
} // namespace jak2
} // namespace jak2
+2 -2
View File
@@ -241,7 +241,7 @@ void IsoQueueVagStream(VagCmd* cmd, int param_2) {
new_cmd->id = cmd->id;
new_cmd->plugin_id = cmd->plugin_id;
new_cmd->unk_136 = cmd->unk_136;
new_cmd->sound_handler = cmd->sound_handler;
new_cmd->unk_176 = cmd->unk_176;
new_cmd->unk_288 = cmd->unk_288;
new_cmd->unk_292 = cmd->unk_292;
@@ -689,7 +689,7 @@ u32 ISOThread() {
do {
if ((((cmd_iter->byte11 == false) && (cmd_iter->sb_scanned == false)) &&
(cmd_iter->id != 0)) ||
((StopPluginStreams == 1 && (cmd_iter->unk_136) != 0))) {
((StopPluginStreams == 1 && (cmd_iter->sound_handler) != 0))) {
// CpuSuspendIntr(&local_2c);
bVar1 = false;
if (cmd_iter->id == 0) {
+3 -2
View File
@@ -5,6 +5,7 @@
#include "game/overlord/common/isocommon.h"
#include "game/overlord/jak2/pages.h"
#include "game/sce/iop.h"
#include "game/sound/sndshim.h"
namespace jak2 {
void iso_init_globals();
@@ -48,7 +49,7 @@ struct IsoFs {
int (*page_begin_read)(LoadStackEntry*, Buffer*); // 1c
uint32_t (*sync_read)(); // 20
uint32_t (*load_sound_bank)(char*, SoundBank*); // 24
uint32_t (*load_music)(char*, s32*);
uint32_t (*load_music)(char*, snd::BankHandle*);
// void (*poll_drive)();
};
@@ -147,7 +148,7 @@ struct CmdLoadSoundBank {
struct CmdLoadMusic {
CmdHeader header;
char name[16];
s32* handle;
snd::BankHandle* handle;
};
struct VagDirEntry {
+5 -5
View File
@@ -64,7 +64,7 @@ void QueueVAGStream(VagStrListNode* param_1) {
cmd.header.cmd_kind = 0x400;
cmd.header.mbx_to_reply = 0;
cmd.header.thread_id = 0;
if (param_1->unk_72 == 0) {
if (param_1->sound_handler == 0) {
EEVagAndVagwad(param_1->name, &cmd);
cmd.vol_multiplier = 0x400;
} else {
@@ -96,7 +96,7 @@ void QueueVAGStream(VagStrListNode* param_1) {
cmd.unk_176 = param_1->unk_100;
}
strncpy(cmd.name, param_1->name, 0x30);
cmd.unk_136 = param_1->unk_72;
cmd.sound_handler = param_1->sound_handler;
cmd.id = param_1->id;
cmd.plugin_id = param_1->unk_68;
cmd.priority = param_1->prio;
@@ -218,7 +218,7 @@ void LoadSoundBank(char* param_1, SoundBank* param_2) {
SleepThread();
}
void LoadMusic(char* param_1, s32* param_2) {
void LoadMusic(char* param_1, snd::BankHandle* param_2) {
CmdLoadMusic auStack88;
auStack88.header.cmd_kind = 0x380;
@@ -239,7 +239,7 @@ void LoadMusic(char* param_1, s32* param_2) {
gMusicTweak = 0x80;
}
void UnLoadMusic(s32* param_1) {
void UnLoadMusic(snd::BankHandle* param_1) {
gMusicFadeDir = -1;
if (gMusicFade != 0) {
do {
@@ -251,4 +251,4 @@ void UnLoadMusic(s32* param_1) {
*param_1 = 0;
}
} // namespace jak2
} // namespace jak2
+5 -3
View File
@@ -2,6 +2,8 @@
#include "common/common_types.h"
#include "game/sound/sndshim.h"
struct SoundBank;
struct FileRecord;
namespace jak2 {
@@ -9,10 +11,10 @@ struct VagStrListNode;
void SetVAGStreamPitch(int param_1, int param_2);
void SetDialogVolume(int param_1);
void LoadSoundBank(char* param_1, SoundBank* param_2);
void UnLoadMusic(s32* param_1);
void LoadMusic(char* param_1, s32* param_2);
void UnLoadMusic(snd::BankHandle* param_1);
void LoadMusic(char* param_1, snd::BankHandle* param_2);
void QueueVAGStream(VagStrListNode* param_1);
int LoadISOFileToEE(FileRecord* param_1, uint32_t param_2, int param_3);
int LoadISOFileToIOP(FileRecord* fr, uint8_t* addr, int len);
int LoadISOFileChunkToEE(FileRecord* param_1, uint32_t param_2, int param_3, int param_4);
} // namespace jak2
} // namespace jak2
+4 -4
View File
@@ -77,7 +77,7 @@ LoadStackEntry* FS_OpenWad(FileRecord* fr, int offset);
void FS_Close(LoadStackEntry* lse);
int FS_PageBeginRead(LoadStackEntry* lse, Buffer* buffer);
uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer);
uint32_t FS_LoadMusic(char* name, s32* buffer);
uint32_t FS_LoadMusic(char* name, snd::BankHandle* buffer);
u32 FS_SyncRead();
void iso_cd_init_globals() {
@@ -661,7 +661,7 @@ uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer) {
FileRecord* file = nullptr;
char namebuf[16];
char isoname[16];
u32 handle;
snd::BankHandle handle;
strncpy(namebuf, name, 12);
namebuf[8] = 0;
@@ -680,11 +680,11 @@ uint32_t FS_LoadSoundBank(char* name, SoundBank* buffer) {
return CMD_STATUS_DONE;
}
uint32_t FS_LoadMusic(char* name, s32* bank_handle) {
uint32_t FS_LoadMusic(char* name, snd::BankHandle* bank_handle) {
FileRecord* file = nullptr;
char namebuf[16];
char isoname[16];
u32 handle;
snd::BankHandle handle;
strncpy(namebuf, name, 12);
namebuf[8] = 0;
+2 -2
View File
@@ -842,7 +842,7 @@ void StopVagStream(VagCmd* param_1, int param_2) {
if (cmd != 0x0) {
cmd->sb_playing = '\0';
}
if (param_1->unk_136 == 0) {
if (param_1->sound_handler == 0) {
PauseVAG(param_1, 0);
param_1->byte9 = '\x01';
if (cmd != 0x0) {
@@ -892,7 +892,7 @@ u32 GetSpuRamAddress(VagCmd* param_1) {
// if the overlord thread isn't keeping up.
// as far as I can tell, it's totally fine to discard these checks because our sceSdGetAddr
// works perfectly.
return sceSdGetAddr((param_1->voice & 0xffffU) | 0x2240);
return sceSdGetAddr(SD_VA_NAX | param_1->voice);
}
u32 bswap(u32 param_1) {
+3 -3
View File
@@ -312,7 +312,7 @@ void* RPC_Player(unsigned int /*fno*/, void* data, int size) {
local_178.header.thread_id = 0;
local_178.vag_dir_entry = nullptr;
local_178.name[0] = '\0';
local_178.unk_136 = 0;
local_178.sound_handler = 0;
local_178.id = 0;
local_178.priority = 0;
StopVagStream(&local_178, 1);
@@ -383,7 +383,7 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) {
break;
}
strncpy(bank->name, cmd->load_bank.bank_name, 16);
strncpy(bank->name.data(), cmd->load_bank.bank_name, 16);
bank->in_use = true;
bank->unk4 = 0;
LoadSoundBank(cmd->load_bank.bank_name, bank);
@@ -611,4 +611,4 @@ void SetVagName(int param_1, char* param_2, int param_3) {
// CpuResumeIntr(local_18[0]);
}
} // namespace jak2
} // namespace jak2
+36 -10
View File
@@ -8,6 +8,7 @@
#include "game/overlord/jak2/streamlist.h"
#include "game/overlord/jak2/vag.h"
#include "game/sce/iop.h"
#include "game/sound/sdshim.h"
#include "game/sound/sndshim.h"
using namespace iop;
@@ -42,17 +43,16 @@ void InitSound_overlord() {
// need this one for PC sound to start up
snd_StartSoundSystem();
// there's a bunch of stuff that we don't use.
StreamVoice[0] = 0;
StreamVoice[1] = 1;
StreamVoice[2] = 2;
StreamVoice[3] = 3; // TODO idk what im doing.
StreamVoice[0] = SD_VOICE(0, 0);
StreamVoice[1] = SD_VOICE(0, 1);
StreamVoice[2] = SD_VOICE(0, 2);
StreamVoice[3] = SD_VOICE(0, 3);
for (int i = 0; i < 91; i++) {
s16 opposing_front = static_cast<s16>(((i * 0x33ff) / 0x5a) + 0xc00);
s16 opposing_front = static_cast<s16>(((i * 0x33ff) / 90) + 0xc00);
s16 rear_right = static_cast<s16>(((i * -0x2800) / 0x5a) + 0x3400);
s16 rear_left = static_cast<s16>(((i * -0xbff) / 0x5a) + 0x3fff);
s16 rear_right = static_cast<s16>(((i * -0x2800) / 90) + 0x3400);
s16 rear_left = static_cast<s16>(((i * -0xbff) / 90) + 0x3fff);
gPanTable[90 - i].left = 0x3FFF;
gPanTable[180 - i].left = opposing_front;
@@ -110,6 +110,32 @@ void SetMusicVol() {
snd_SetMasterVolume(2, vol);
}
void UpdateLocation(Sound* sound) {
if (sound->id == 0) {
return;
}
s32 id = snd_SoundIsStillPlaying(sound->sound_handle);
if (id == 0) {
sound->id = 0;
return;
}
s32 volume = GetVolume(sound);
if (volume == 0) {
snd_StopSound(sound->sound_handle);
return;
}
if (sound->params.fo_curve == 1 || sound->params.fo_curve == 10) {
snd_SetSoundVolPan(id, volume, 0);
return;
}
s32 pan = GetPan(sound);
snd_SetSoundVolPan(id, volume, pan);
}
void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam_angle) {
// some assuming that this is the same in jak2...
s32 tick = snd_GetTick();
@@ -136,7 +162,7 @@ void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam
auto* cmd = VagCmds;
// piVar6 = &VagCmds[0].vol_multiplier;
do {
if (cmd->unk_136 == 0x0) {
if (cmd->sound_handler == 0x0) {
LAB_0000c388:
SetVAGVol(cmd, 1);
} else if ((cmd->sb_scanned == '\0') || (cmd->byte8 != '\0')) {
@@ -172,4 +198,4 @@ void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam
} while (true);
}
} // namespace jak2
} // namespace jak2
+4 -1
View File
@@ -2,12 +2,15 @@
#include "game/overlord/common/ssound.h"
namespace jak2 {
#define VOICE_BIT(voice) (1 << ((voice) >> 1))
#define CORE_BIT(voice) ((voice)&1)
void ssound_init_globals();
void SetBufferMem(void*, int);
void ReleaseBufferMem();
void SetMusicVol();
void UpdateLocation(Sound* sound);
void SetEarTrans(Vec3w* ear_trans0, Vec3w* ear_trans1, Vec3w* cam_trans, s32 cam_angle);
void InitSound_overlord();
extern s32 StreamThread;
extern VolumePair gPanTable[361];
} // namespace jak2
} // namespace jak2
+3 -3
View File
@@ -178,7 +178,7 @@ void* RPC_PLAY([[maybe_unused]] unsigned int fno, void* _cmd, int size) {
strncpy(list_node.name, cmd_iter->names[s].chars, 0x30);
list_node.id = cmd_iter->id[s];
list_node.unk_76 = cmd_iter->address & 1 << (s & 0x1f) & 0xf;
list_node.unk_72 = 0;
list_node.sound_handler = 0;
list_node.unk_80 = cmd_iter->address & 0x10 << (s & 0x1f) & 0xf0;
list_node.prio = iVar5;
pRVar2 = FindThisVagStream(list_node.name, list_node.id);
@@ -247,7 +247,7 @@ void* RPC_PLAY([[maybe_unused]] unsigned int fno, void* _cmd, int size) {
strncpy(list_node.name, cmd_iter->names[s].chars, 0x30);
list_node.id = cmd_iter->id[s];
list_node.unk_68 = 0;
list_node.unk_72 = 0;
list_node.sound_handler = 0;
list_node.prio = iVar5;
pRVar2 = FindThisVagStream(cmd_iter->names[s].chars, cmd_iter->id[s]);
if ((pRVar2 == 0x0) || (pRVar2->byte4 == '\0')) {
@@ -260,7 +260,7 @@ void* RPC_PLAY([[maybe_unused]] unsigned int fno, void* _cmd, int size) {
iVar4->id = list_node.id;
iVar4->prio = list_node.prio;
iVar4->unk_72 = list_node.unk_72;
iVar4->sound_handler = list_node.sound_handler;
iVar4->unk_76 = 0;
iVar4->unk_80 = 0;
iVar4->unk_92 = 0;
+8 -8
View File
@@ -74,9 +74,9 @@ VagStrListNode* InsertVagStreamInList(VagStrListNode* param_1, List* param_2) {
pVVar5->unk_76 = param_1->unk_76;
pVVar5->unk_80 = param_1->unk_80;
pVVar5->prio = param_1->prio;
iVar1 = param_1->unk_72;
iVar1 = param_1->sound_handler;
pVVar5->unk_92 = 0;
pVVar5->unk_72 = iVar1;
pVVar5->sound_handler = iVar1;
pVVar5->vol_multiplier = param_1->vol_multiplier;
pVVar5->unk_100 = param_1->unk_100;
if (pVVar6 == (VagStrListNode*)0x0) {
@@ -132,7 +132,7 @@ void QueueNewStreamsFromList(List* list) {
// puVar4[0xe] = 0;
pvVar6->id = 0;
// puVar4[0x10] = 0;
pvVar6->unk_72 = 0;
pvVar6->sound_handler = 0;
// puVar4[0x13] = 0;
pvVar6->prio = 0;
// puVar4[0x11] = 0;
@@ -264,7 +264,7 @@ code_r0x0000f058:
(pVVar4->list).in_use = 0;
strncpy(pVVar4->name, "free", 0x30);
pVVar4->id = 0;
pVVar4->unk_72 = 0;
pVVar4->sound_handler = 0;
pVVar4->prio = 0;
pVVar4->unk_76 = 0;
pVVar4->unk_80 = 0;
@@ -306,7 +306,7 @@ u32 StreamListThread() {
// puVar4[0xe] = 0;
pvVar6->id = 0;
// puVar4[0x10] = 0;
pvVar6->unk_72 = 0;
pvVar6->sound_handler = 0;
// puVar4[0x13] = 0;
pvVar6->prio = 0;
// puVar4[0x11] = 0;
@@ -438,7 +438,7 @@ bool InitVagStreamList(List* param_1, u32 param_2, const char* param_3) {
// *(undefined4*)(piVar1 + -0x24) = 0;
pLVar3->id = 0;
// *(undefined4*)(piVar1 + -0x1c) = 0;
pLVar3->unk_72 = 0;
pLVar3->sound_handler = 0;
// *(undefined4*)(piVar1 + -0x10) = 0;
pLVar3->prio = 0;
// *(undefined4*)(piVar1 + -0x18) = 0;
@@ -525,7 +525,7 @@ void RemoveVagStreamFromList(VagStrListNode* param_1, List* param_2) {
(pVVar2->list).in_use = 0;
strncpy(pVVar2->name, "free", 0x30);
pVVar2->id = 0;
pVVar2->unk_72 = 0;
pVVar2->sound_handler = 0;
pVVar2->prio = 0;
pVVar2->unk_76 = 0;
pVVar2->unk_80 = 0;
@@ -563,7 +563,7 @@ void EmptyVagStreamList(List* param_1) {
// puVar1 = puVar1 + 0x1a;
pvVar2->id = 0;
pvVar2->unk_72 = 0;
pvVar2->sound_handler = 0;
pvVar2->prio = 0;
pvVar2->unk_76 = 0;
pvVar2->unk_80 = 0;
+1 -1
View File
@@ -10,7 +10,7 @@ struct VagStrListNode {
int unk_60;
int id;
int unk_68;
int unk_72;
int sound_handler; // 989snd handler that owns this stream
int unk_76;
int unk_80;
int prio;
+146 -422
View File
@@ -24,7 +24,8 @@ VagCmdPriListEntry VagCmdsPriList[11];
int VagCmdsPriCounter[11];
int ActiveVagStreams;
void CalculateVAGVolumes(VagCmd* cmd, int* l_out, int* r_out);
void CalculateVAGVolumes(VagCmd* cmd, u32* l_out, u32* r_out);
void StopVAG(VagCmd* cmd, int /*param_2*/);
enum VolumeCategory {
DIALOGUE = 2, // VAG streams. Copied "dialogue" name from jak 1.
@@ -101,7 +102,7 @@ void InitVagCmds() {
cmd.unk_256_pitch2 = 0; // puVar5[-9] = 0;
cmd.id = 0; // puVar5[-4] = 0;
cmd.plugin_id = 0; // puVar5[-3] = 0;
cmd.unk_136 = 0; // puVar5[-0x27] = 0;
cmd.sound_handler = 0; // puVar5[-0x27] = 0;
cmd.unk_176 = 0; // puVar5[-0x1d] = 0;
cmd.priority = 0; // puVar5[-2] = 0;
cmd.unk_288 = 0; // puVar5[-1] = 0;
@@ -189,189 +190,34 @@ VagCmd* SmartAllocVagCmd(VagCmd* cmd) {
}
void TerminateVAG(VagCmd* cmd, int param_2) {
[[maybe_unused]] int* piVar1;
int iVar2;
u32 uVar3;
VagCmd* pRVar4;
VagCmd* pRVar5;
VagStrListNode vag_node;
LfoListNode lfo_node;
// undefined4 auStack32 [2];
if (param_2 == 1) {
// CpuSuspendIntr(auStack32);
}
pRVar4 = cmd->stereo_sibling;
// if (param_2 == 1) {
// CpuSuspendIntr(auStack32);
//}
auto* sibling = cmd->stereo_sibling;
strncpy(vag_node.name, cmd->name, 0x30);
vag_node.id = cmd->id;
cmd->sb_scanned = '\0';
if (cmd->status_bytes[BYTE5] != '\0') {
pRVar5 = cmd->stereo_sibling;
PauseVAG(cmd, 0);
if (cmd->status_bytes[BYTE5] != '\0') {
uVar3 = 1 << (cmd->voice >> 1 & 0x1fU);
if (pRVar5 != 0x0) {
uVar3 = uVar3 | 1 << (pRVar5->voice >> 1 & 0x1fU);
}
// sceSdSetSwitch(*(u16*)&cmd->voice & 1 | 0x1600, uVar3);
sceSdkey_off_jak2_voice(cmd->voice);
if (cmd->stereo_sibling) {
sceSdkey_off_jak2_voice(cmd->stereo_sibling->voice);
}
}
// iVar2 = 0x18;
// piVar1 = &(cmd->header).unk_24;
// do {
// *(undefined *)(piVar1 + 0x34) = 0;
// iVar2 = iVar2 + -1;
// piVar1 = (int *)((int)piVar1 + -1);
// } while (-1 < iVar2);
for (auto& x : cmd->status_bytes) {
x = 0;
}
cmd->vol_multiplier = 0;
cmd->unk_256_pitch2 = 0;
cmd->id = 0;
cmd->plugin_id = 0;
(cmd->header).ready_for_data = 0;
cmd->unk_136 = 0;
cmd->unk_140 = 0;
cmd->pitch1 = 0;
(cmd->header).callback = NullCallback;
cmd->unk_180 = 0;
cmd->unk_184 = 0;
cmd->unk_188 = 0;
cmd->unk_192 = 0;
StopVAG(cmd, 0);
}
ReleaseMessage(&cmd->header, 0);
VagCmdsPriList[cmd->priority].cmds[cmd->idx_in_cmd_arr] = 0x0;
if (VagCmdsPriCounter[cmd->priority] < 1) {
printf("IOP: ======================================================================\n");
printf("IOP: vag RemoveVagCmd: VagCmdsPriCounter[%d] is zero\n", cmd->priority);
printf("IOP: ======================================================================\n");
} else {
VagCmdsPriCounter[cmd->priority] = VagCmdsPriCounter[cmd->priority] + -1;
RemoveVagCmd(cmd, 0);
FreeVagCmd(cmd, 0);
if (sibling != nullptr) {
sibling->sb_scanned = '\0';
RemoveVagCmd(sibling, 0);
FreeVagCmd(sibling, 0);
}
// iVar2 = 0x18;
// piVar1 = &(cmd->header).unk_24;
VagCmdsPriCounter[0] = VagCmdsPriCounter[0] + 1;
for (auto& x : cmd->status_bytes) {
x = 0;
}
// do {
// *(undefined*)(piVar1 + 0x34) = 0;
// iVar2 = iVar2 + -1;
// piVar1 = (int*)((int)piVar1 + -1);
// } while (-1 < iVar2);
cmd->sb_playing = '\0';
cmd->sb_paused = '\x01';
cmd->sb_scanned = '\0';
cmd->unk_180 = 0;
cmd->unk_184 = 0;
cmd->unk_188 = 0;
cmd->unk_192 = 0;
SetVagStreamName(cmd, 0, 0);
cmd->name[0] = '\0';
iVar2 = ActiveVagStreams;
cmd->safe_to_change_dma_fields = 1;
cmd->unk_264 = 0x4000;
(cmd->header).callback = NullCallback;
cmd->unk_140 = 0;
cmd->pitch1 = 0;
cmd->file_record = nullptr;
cmd->vag_dir_entry = nullptr;
cmd->unk_196 = 0;
cmd->unk_200 = 0;
cmd->unk_204 = 0;
cmd->num_processed_chunks = 0;
cmd->xfer_size = 0;
cmd->sample_rate = 0;
cmd->unk_260 = 0;
cmd->unk_268 = 0;
cmd->vol_multiplier = 0;
cmd->unk_256_pitch2 = 0;
cmd->id = 0;
cmd->plugin_id = 0;
cmd->unk_136 = 0;
cmd->priority = 0;
cmd->unk_288 = 0;
cmd->unk_292 = 0;
cmd->unk_296 = 0;
(cmd->header).callback_buffer = (Buffer*)0x0;
(cmd->header).ready_for_data = 0;
(cmd->header).lse = (LoadStackEntry*)0x0;
cmd->dma_iop_mem_ptr = (uint8_t*)0x0;
cmd->dma_chan = -1;
cmd->unk_236 = 0;
if (0 < iVar2) {
ActiveVagStreams = iVar2 + -1;
}
if (pRVar4 != 0x0) {
pRVar4->sb_scanned = '\0';
VagCmdsPriList[pRVar4->priority].cmds[pRVar4->idx_in_cmd_arr] = 0x0;
if (VagCmdsPriCounter[pRVar4->priority] < 1) {
printf("IOP: ======================================================================\n");
printf("IOP: vag RemoveVagCmd: VagCmdsPriCounter[%d] is zero\n", pRVar4->priority);
printf("IOP: ======================================================================\n");
} else {
VagCmdsPriCounter[pRVar4->priority] = VagCmdsPriCounter[pRVar4->priority] + -1;
}
iVar2 = 0x18;
piVar1 = &(pRVar4->header).ready_for_data;
VagCmdsPriCounter[0] = VagCmdsPriCounter[0] + 1;
for (auto& x : cmd->status_bytes) {
x = 0;
}
// do {
// *(undefined*)(piVar1 + 0x34) = 0;
// iVar2 = iVar2 + -1;
// piVar1 = (int*)((int)piVar1 + -1);
// } while (-1 < iVar2);
pRVar4->sb_playing = '\0';
pRVar4->sb_paused = '\x01';
pRVar4->sb_scanned = '\0';
pRVar4->unk_180 = 0;
pRVar4->unk_184 = 0;
pRVar4->unk_188 = 0;
pRVar4->unk_192 = 0;
SetVagStreamName(pRVar4, 0, 0);
pRVar4->name[0] = '\0';
iVar2 = ActiveVagStreams;
pRVar4->safe_to_change_dma_fields = 1;
pRVar4->unk_264 = 0x4000;
(pRVar4->header).callback = NullCallback;
pRVar4->unk_140 = 0;
pRVar4->pitch1 = 0;
pRVar4->file_record = nullptr;
pRVar4->vag_dir_entry = nullptr;
pRVar4->unk_196 = 0;
pRVar4->unk_200 = 0;
pRVar4->unk_204 = 0;
pRVar4->num_processed_chunks = 0;
pRVar4->xfer_size = 0;
pRVar4->sample_rate = 0;
pRVar4->unk_260 = 0;
pRVar4->unk_268 = 0;
pRVar4->vol_multiplier = 0;
pRVar4->unk_256_pitch2 = 0;
pRVar4->id = 0;
pRVar4->plugin_id = 0;
pRVar4->unk_136 = 0;
pRVar4->priority = 0;
pRVar4->unk_288 = 0;
pRVar4->unk_292 = 0;
pRVar4->unk_296 = 0;
(pRVar4->header).callback_buffer = (Buffer*)0x0;
(pRVar4->header).ready_for_data = 0;
(pRVar4->header).lse = (LoadStackEntry*)0x0;
pRVar4->dma_iop_mem_ptr = (uint8_t*)0x0;
pRVar4->dma_chan = -1;
pRVar4->unk_236 = 0;
if (0 < iVar2) {
ActiveVagStreams = iVar2 + -1;
}
}
if (cmd->unk_136) {
if (cmd->sound_handler) {
RemoveVagStreamFromList(&vag_node, &PluginStreamsList);
lfo_node.id = cmd->id;
lfo_node.plugin_id = cmd->plugin_id;
@@ -380,10 +226,9 @@ void TerminateVAG(VagCmd* cmd, int param_2) {
// printf("termina removing %s (2)\n", vag_node.name);
RemoveVagStreamFromList(&vag_node, &EEPlayList);
if (param_2 == 1) {
// CpuResumeIntr(auStack32[0]);
}
// return;
// if (param_2 == 1) {
// CpuResumeIntr(auStack32[0]);
//}
}
void PauseVAG(VagCmd* cmd, int /*param_2*/) {
@@ -395,13 +240,11 @@ void PauseVAG(VagCmd* cmd, int /*param_2*/) {
auto* stereo_cmd = cmd->stereo_sibling;
if (!stereo_cmd) {
if (cmd->sb_playing != '\0') {
sceSdSetParam((u16)cmd->voice | SD_VP_VOLL, 0);
sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLR, 0);
sceSdSetParam(SD_VP_VOLL | cmd->voice, 0);
sceSdSetParam(SD_VP_VOLR | cmd->voice, 0);
}
sceSdSetParam(((u16)cmd->voice) | SD_VP_PITCH, 0);
// TODO: ignored, whatever this is
// sceSdSetSwitch((((s16)cmd->voice) & 1) | 0x1600, 1 << (cmd->voice >> 1 & 0x1fU));
sceSdkey_off_jak2_voice(cmd->voice);
sceSdSetParam(SD_VP_PITCH | cmd->voice, 0);
sceSdSetSwitch(SD_S_KOFF | CORE_BIT(cmd->voice), VOICE_BIT(cmd->voice));
if (cmd->status_bytes[BYTE5] == '\0') {
cmd->spu_addr_to_start_playing = 0;
} else {
@@ -410,23 +253,21 @@ void PauseVAG(VagCmd* cmd, int /*param_2*/) {
cmd->sb_paused = 1;
} else {
if (cmd->sb_playing != '\0') {
sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLL, 0);
sceSdSetParam(((u16)cmd->voice) | SD_VP_VOLR, 0);
sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_VOLL, 0);
sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_VOLR, 0);
sceSdSetParam(SD_VP_VOLL | cmd->voice, 0);
sceSdSetParam(SD_VP_VOLR | cmd->voice, 0);
sceSdSetParam(SD_VP_VOLL | stereo_cmd->voice, 0);
sceSdSetParam(SD_VP_VOLR | stereo_cmd->voice, 0);
}
sceSdSetParam(((u16)stereo_cmd->voice) | SD_VP_PITCH, 0);
sceSdSetParam(((u16)cmd->voice) | SD_VP_PITCH, 0);
// sceSdSetSwitch(((u16)cmd->voice & 1) | 0x1600,
// 1 << (cmd->voice >> 1 & 0x1fU) | 1 << (stereo_cmd->voice >> 1 & 0x1fU));
sceSdkey_off_jak2_voice(cmd->voice);
sceSdkey_off_jak2_voice(stereo_cmd->voice);
sceSdSetParam(SD_VP_PITCH | stereo_cmd->voice, 0);
sceSdSetParam(SD_VP_PITCH | cmd->voice, 0);
sceSdSetSwitch(SD_S_KOFF | CORE_BIT(cmd->voice),
VOICE_BIT(cmd->voice) | VOICE_BIT(stereo_cmd->voice));
if (cmd->status_bytes[BYTE5] == '\0') {
cmd->spu_addr_to_start_playing = 0;
stereo_cmd->spu_addr_to_start_playing = 0;
} else {
int ram_addr = GetSpuRamAddress(cmd);
u32 ram_addr = GetSpuRamAddress(cmd);
cmd->spu_addr_to_start_playing = ram_addr & 0xfffffff8;
stereo_cmd->spu_addr_to_start_playing =
((ram_addr & 0xfffffff8) - cmd->spu_stream_dma_mem_addr) +
@@ -449,38 +290,35 @@ void UnPauseVAG(VagCmd* param_1, int /*param_2*/) {
//}
if (param_1->status_bytes[BYTE11] == '\0') {
auto* stereo_cmd = param_1->stereo_sibling;
int pitch_reuslt = CalculateVAGPitch(param_1->pitch1, param_1->unk_256_pitch2);
int vol_l, vol_r;
int pitch = CalculateVAGPitch(param_1->pitch1, param_1->unk_256_pitch2);
u32 vol_l, vol_r;
CalculateVAGVolumes(param_1, &vol_l, &vol_r);
if (!stereo_cmd) {
if (param_1->sb_playing != '\0') {
sceSdSetParam(((u16)param_1->voice) | 0x200, pitch_reuslt);
sceSdSetParam(SD_VP_PITCH | param_1->voice, pitch);
if (param_1->spu_addr_to_start_playing != 0) {
sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_addr_to_start_playing);
sceSdSetAddr(SD_VA_SSA | param_1->voice, param_1->spu_addr_to_start_playing);
}
// sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500, 1 << (voice >> 1 & 0x1fU));
sceSdkey_on_jak2_voice(param_1->voice);
sceSdSetParam(((u16)param_1->voice), vol_l);
sceSdSetParam(((u16)param_1->voice) | 0x100, vol_r);
sceSdSetSwitch(SD_S_KON | CORE_BIT(param_1->voice), VOICE_BIT(param_1->voice));
sceSdSetParam(SD_VP_VOLL | param_1->voice, vol_l);
sceSdSetParam(SD_VP_VOLR | param_1->voice, vol_r);
}
param_1->sb_paused = 0;
} else {
if (param_1->sb_playing != '\0') {
sceSdSetParam(((u16)param_1->voice) | 0x200, pitch_reuslt);
sceSdSetParam(((u16)stereo_cmd->voice) | 0x200, pitch_reuslt);
sceSdSetParam(SD_VP_PITCH | param_1->voice, pitch);
sceSdSetParam(SD_VP_PITCH | stereo_cmd->voice, pitch);
if (param_1->spu_addr_to_start_playing != 0) {
sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_addr_to_start_playing);
sceSdSetAddr(((u16)stereo_cmd->voice) | 0x2040, stereo_cmd->spu_addr_to_start_playing);
sceSdSetAddr(SD_VA_SSA | param_1->voice, param_1->spu_addr_to_start_playing);
sceSdSetAddr(SD_VA_SSA | stereo_cmd->voice, stereo_cmd->spu_addr_to_start_playing);
}
sceSdkey_on_jak2_voice(param_1->voice);
sceSdkey_on_jak2_voice(stereo_cmd->voice);
// sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500,
// 1 << (voice >> 1 & 0x1fU) | 1 << (stereo_voice >> 1 & 0x1fU));
sceSdSetParam(((u16)param_1->voice), vol_l);
sceSdSetParam(((u16)stereo_cmd->voice), 0);
sceSdSetParam(((u16)param_1->voice) | 0x100, 0);
sceSdSetParam(((u16)stereo_cmd->voice) | 0x100, vol_r);
sceSdSetSwitch(SD_S_KON | CORE_BIT(param_1->voice),
VOICE_BIT(param_1->voice) | VOICE_BIT(stereo_cmd->voice));
sceSdSetParam(SD_VP_VOLL | param_1->voice, vol_l);
sceSdSetParam(SD_VP_VOLL | stereo_cmd->voice, 0);
sceSdSetParam(SD_VP_VOLR | param_1->voice, 0);
sceSdSetParam(SD_VP_VOLR | stereo_cmd->voice, vol_r);
}
param_1->sb_paused = 0;
stereo_cmd->sb_paused = 0;
@@ -505,82 +343,54 @@ void RestartVag(VagCmd* param_1, int param_2, int /*param_3*/) {
// if (param_3 == 1) {
// CpuSuspendIntr(&local_30);
//}
int vol_l, vol_r;
u32 vol_l, vol_r;
CalculateVAGVolumes(param_1, &vol_l, &vol_r);
if (param_1->status_bytes[BYTE11] == '\0') {
int voice = 1 << (param_1->voice >> 1 & 0x1fU);
auto* stereo_sibling = param_1->stereo_sibling;
int sram_offset = param_2 ? 0x2000 : 0;
if (stereo_sibling) {
voice = voice | 1 << (stereo_sibling->voice >> 1 & 0x1fU);
}
// sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1600, voice);
sceSdkey_off_jak2_voice(param_1->voice);
if (stereo_sibling) {
sceSdkey_off_jak2_voice(stereo_sibling->voice);
}
sceSdSetParam(((u16)param_1->voice), 0);
sceSdSetParam(((u16)param_1->voice) | 0x100, 0);
int other_voice;
int sram_addr;
if (!stereo_sibling) {
other_voice = *(u16*)&param_1->voice;
sram_addr = param_1->spu_stream_dma_mem_addr;
} else {
sceSdSetParam(((u16)stereo_sibling->voice), 0);
sceSdSetParam(((u16)stereo_sibling->voice) | 0x100, 0);
sceSdSetAddr(((u16)param_1->voice) | 0x2040, param_1->spu_stream_dma_mem_addr + sram_offset);
other_voice = ((u16)stereo_sibling->voice);
sram_addr = stereo_sibling->spu_stream_dma_mem_addr;
}
sceSdSetAddr(other_voice | 0x2040, sram_addr + sram_offset);
// sceSdSetSwitch(((u16)param_1->voice & 1) | 0x1500, voice);
sceSdkey_on_jak2_voice(param_1->voice);
int voices = VOICE_BIT(param_1->voice);
if (stereo_sibling) {
sceSdkey_on_jak2_voice(stereo_sibling->voice);
voices |= VOICE_BIT(stereo_sibling->voice);
}
sceSdSetSwitch(SD_S_KOFF | CORE_BIT(param_1->voice), voices);
sceSdSetParam(SD_VP_VOLL | param_1->voice, 0);
sceSdSetParam(SD_VP_VOLR | param_1->voice, 0);
if (stereo_sibling) {
sceSdSetParam(SD_VP_VOLL | stereo_sibling->voice, 0);
sceSdSetParam(SD_VP_VOLR | stereo_sibling->voice, 0);
}
sceSdSetAddr(SD_VA_SSA | param_1->voice, param_1->spu_stream_dma_mem_addr + sram_offset);
if (stereo_sibling) {
sceSdSetAddr(SD_VA_SSA | stereo_sibling->voice,
stereo_sibling->spu_stream_dma_mem_addr + sram_offset);
}
sceSdSetSwitch(SD_S_KON | CORE_BIT(param_1->voice), voices);
if (!stereo_sibling) {
sceSdSetParam(((u16)param_1->voice), vol_l);
other_voice = ((u16)param_1->voice);
sceSdSetParam(SD_VP_VOLL | param_1->voice, vol_l);
sceSdSetParam(SD_VP_VOLR | param_1->voice, vol_r);
} else {
sceSdSetParam(((u16)param_1->voice), vol_l);
sceSdSetParam(((u16)stereo_sibling->voice), 0);
sceSdSetParam(((u16)param_1->voice) | 0x100, 0);
other_voice = ((u16)stereo_sibling->voice);
sceSdSetParam(SD_VP_VOLL | param_1->voice, vol_l);
sceSdSetParam(SD_VP_VOLL | stereo_sibling->voice, 0);
sceSdSetParam(SD_VP_VOLR | param_1->voice, 0);
sceSdSetParam(SD_VP_VOLR | stereo_sibling->voice, vol_r);
}
sceSdSetParam(other_voice | 0x100, vol_r);
}
// if (param_3 == 1) {
// CpuResumeIntr(local_30);
//}
}
struct sceSdBatch {
u32 entry;
u32 value;
u32 func;
};
void sceSdProcBatch(sceSdBatch* b, int, int n) {
for (int i = 0; i < n; i++) {
sceSdSetParam(b[i].entry, b[i].value);
}
}
void SetVAGVol(VagCmd* cmd, int param_2) {
u32 uVar1;
u32 uVar3;
int iVar4;
int iVar5;
VagCmd* stereo_cmd;
sceSdBatch batch[6];
u32 local_28;
u32 local_24;
// undefined4 local_20 [2];
u32 lvol, rvol;
if (cmd == 0x0) {
if (cmd == nullptr) {
return;
}
if (cmd->byte4 == '\0') {
@@ -592,105 +402,43 @@ void SetVAGVol(VagCmd* cmd, int param_2) {
if (cmd->byte11 != '\0') {
return;
}
auto pvVar2 = cmd->unk_136;
stereo_cmd = cmd->stereo_sibling;
if (pvVar2 == 0) {
if (cmd->unk_296 == 0) {
local_28 = (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 6;
local_24 = local_28;
if (0x3fff < local_28) {
local_28 = 0x3fff;
local_24 = local_28;
}
goto LAB_0000a258;
}
iVar4 = CalculateFallofVolume(&cmd->vec3, (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 10,
cmd->fo_curve, cmd->fo_min, cmd->fo_max);
iVar5 = CalculateAngle(&cmd->vec3);
uVar3 = 0x276 - iVar5;
uVar1 = (uVar3 >> 3) / 0x2d;
local_28 = ((s16*)gPanTable)[uVar1 * -0x2d0 + uVar3 * 2] * iVar4;
local_24 = ((s16*)gPanTable)[uVar1 * -0x2d0 + uVar3 * 2 + 1] * iVar4;
if (!cmd->sound_handler) {
CalculateVAGVolumes(cmd, &lvol, &rvol);
} else {
ASSERT_NOT_REACHED();
// uVar3 = cmd->unk_176 + 0x5a;
// uVar1 = (uVar3 >> 3) / 0x2d;
// local_24 = (((u32)(cmd->vol_multiplier * MasterVolume[*(char *)((int)pvVar2 + 0x17)]) >>
// 10) *
// (int)*(short *)((int)pvVar2 + 0x10) >> 10) * 0x3fff >> 10;
// local_28 = (int)gPanTable[uVar1 * -0x2d0 + uVar3 * 2] * local_24;
// local_24 = (int)gPanTable[uVar1 * -0x2d0 + uVar3 * 2 + 1] * local_24;
// TODO vag 989snd plugin
// SoundHandler* hnd = cmd->sound_handler;
// u32 vol =
// 0x3fff *
// ((((cmd->vol_multiplier * MasterVolume[hnd->VolGroup]) >> 10) * hnd->Current_Vol) >> 10)
// >> 10;
// lvol = (vol * gPanTable[(cmd->unk_176 + 90) % 360].left) >> 10;
// lvol = (vol * gPanTable[(cmd->unk_176 + 90) % 360].right) >> 10;
// if (lvol >= 0x4000) {
// lvol = 0x3fff;
//}
// if (rvol >= 0x4000) {
// rvol = 0x3fff;
//}
}
local_28 = local_28 >> 10;
local_24 = local_24 >> 10;
if (0x3fff < local_28) {
local_28 = 0x3fff;
}
if (0x3fff < local_24) {
local_24 = 0x3fff;
}
LAB_0000a258:
if (stereo_cmd == (VagCmd*)0x0) {
batch[0].entry = *(uint16_t*)&cmd->voice;
iVar4 = 2;
batch[1].entry = *(u16*)&cmd->voice | 0x100;
batch[2].entry = *(u16*)&cmd->voice | 0x200;
iVar5 = cmd->unk_256_pitch2;
uVar1 = cmd->pitch1;
// printf("cmd's pitch is %d, %d\n", cmd->pitch1, cmd->unk_256_pitch2);
batch[1].value = local_24;
// Originally used ProcBatch, buts this is easier to read.
stereo_cmd = cmd->stereo_sibling;
if (stereo_cmd) {
sceSdSetParam(SD_VP_VOLL | cmd->voice, lvol);
sceSdSetParam(SD_VP_VOLR | cmd->voice, 0);
sceSdSetParam(SD_VP_VOLL | stereo_cmd->voice, 0);
sceSdSetParam(SD_VP_VOLR | stereo_cmd->voice, rvol);
sceSdSetParam(SD_VP_PITCH | cmd->voice, CalculateVAGPitch(cmd->pitch1, cmd->unk_256_pitch2));
sceSdSetParam(SD_VP_PITCH | stereo_cmd->voice,
CalculateVAGPitch(cmd->pitch1, cmd->unk_256_pitch2));
} else {
batch[0].entry = *(uint16_t*)&cmd->voice;
batch[1].entry = *(uint16_t*)&stereo_cmd->voice;
batch[1].value = 0;
batch[2].value = 0;
batch[2].entry = *(u16*)&cmd->voice | 0x100;
batch[3].func = 1;
batch[3].entry = *(u16*)&stereo_cmd->voice | 0x100;
batch[4].func = 1;
batch[4].entry = *(u16*)&cmd->voice | 0x200;
iVar4 = cmd->unk_256_pitch2;
batch[4].value = cmd->pitch1;
if (iVar4 != 0) {
if (iVar4 < 1) {
batch[4].value = (u32)(batch[4].value * 0x5f4) / (0x5f4U - iVar4);
if (0x5f4U - iVar4 == 0) {
ASSERT_NOT_REACHED();
// trap(0x1c00);
}
} else {
batch[4].value = (u32)(batch[4].value * (iVar4 + 0x5f4)) / 0x5f4;
}
}
iVar4 = 5;
batch[5].func = 1;
batch[5].entry = *(u16*)&stereo_cmd->voice | 0x200;
iVar5 = cmd->unk_256_pitch2;
uVar1 = cmd->pitch1;
batch[3].value = local_24;
}
if (iVar5 != 0) {
if (iVar5 < 1) {
uVar1 = (uVar1 * 0x5f4) / (0x5f4U - iVar5);
if (0x5f4U - iVar5 == 0) {
ASSERT_NOT_REACHED();
// trap(0x1c00);
}
} else {
uVar1 = (uVar1 * (iVar5 + 0x5f4)) / 0x5f4;
}
}
batch[2].func = 1;
batch[1].func = 1;
batch[0].value = local_28;
batch[0].func = 1;
batch[iVar4].value = uVar1;
if (param_2 == 1) {
// CpuSuspendIntr(local_20);
sceSdProcBatch(batch, 0, iVar4 + 1);
// CpuResumeIntr(local_20[0]);
} else {
sceSdProcBatch(batch, 0, iVar4 + 1);
sceSdSetParam(SD_VP_VOLL | cmd->voice, lvol);
sceSdSetParam(SD_VP_VOLR | cmd->voice, rvol);
sceSdSetParam(SD_VP_PITCH | cmd->voice, CalculateVAGPitch(cmd->pitch1, cmd->unk_256_pitch2));
}
}
@@ -866,6 +614,7 @@ void FreeVagCmd(VagCmd* cmd, int /*param_2*/) {
cmd->unk_188 = 0;
cmd->unk_192 = 0;
SetVagStreamName(cmd, 0, 0);
cmd->name[0] = '\0';
cmd->unk_264 = 0x4000;
(cmd->header).callback = NullCallback;
@@ -886,7 +635,7 @@ void FreeVagCmd(VagCmd* cmd, int /*param_2*/) {
cmd->unk_256_pitch2 = 0;
cmd->id = 0;
cmd->plugin_id = 0;
cmd->unk_136 = 0;
cmd->sound_handler = 0;
cmd->priority = 0;
cmd->unk_288 = 0;
cmd->unk_292 = 0;
@@ -948,15 +697,11 @@ void StopVAG(VagCmd* cmd, int /*param_2*/) {
auto& sibling = cmd->stereo_sibling;
PauseVAG(cmd, 0);
if (cmd->status_bytes[BYTE5] != '\0') {
int val = 1 << (cmd->voice >> 1 & 0x1fU);
int val = VOICE_BIT(cmd->voice);
if (sibling) {
val = val | 1 << (sibling->voice >> 1 & 0x1fU);
}
// sceSdSetSwitch(u16(cmd->voice) & 1 | 0x1600, val);
sceSdkey_off_jak2_voice(cmd->voice);
if (sibling) {
sceSdkey_off_jak2_voice(sibling->voice);
val = val | VOICE_BIT(sibling->voice);
}
sceSdSetSwitch(SD_S_KOFF | CORE_BIT(cmd->voice), val);
}
for (auto& x : cmd->status_bytes) {
x = 0;
@@ -967,7 +712,7 @@ void StopVAG(VagCmd* cmd, int /*param_2*/) {
cmd->id = 0;
cmd->plugin_id = 0;
(cmd->header).ready_for_data = 0;
cmd->unk_136 = 0;
cmd->sound_handler = 0;
cmd->unk_140 = 0;
cmd->pitch1 = 0;
cmd->unk_180 = 0;
@@ -989,16 +734,14 @@ void VAG_MarkLoopStart(int8_t* param_1) {
}
int CalculateVAGPitch(int param_1, int param_2) {
if (param_2 != 0) {
if (param_2 < 1) {
param_1 = (param_1 * 0x5f4) / (0x5f4U - param_2);
if (0x5f4U - param_2 == 0) {
ASSERT_NOT_REACHED();
}
if (param_2) {
if (param_2 <= 0) {
return 0x5f4 * param_1 / (0x5f4 - param_2);
} else {
param_1 = (param_1 * (param_2 + 0x5f4)) / 0x5f4;
return param_1 * (param_2 + 0x5f4) / 0x5f4;
}
}
return param_1;
}
@@ -1018,61 +761,42 @@ void UnPauseVagStreams() {
}
}
void SetAllVagsVol(int param_1)
{
int iVar1;
VagCmd* cmd;
cmd = VagCmds;
if (param_1 < 0) {
iVar1 = 0;
do {
SetVAGVol(cmd, 1);
iVar1 = iVar1 + 1;
cmd = cmd + 1;
} while (iVar1 < 4);
} else {
iVar1 = 0;
do {
if (cmd->unk_136) {
void SetAllVagsVol(int param_1) {
if (param_1 >= 0) {
for (auto& VagCmd : VagCmds) {
if (VagCmd.sound_handler /* && VagCmd.sound_handler->VolGroup == param_1 */) {
ASSERT_NOT_REACHED();
// if (*(char *)((int)cmd->unk_136 + 0x17) == param_1) {
// SetVAGVol(cmd,1);
// }
cmd = cmd + 1;
SetVAGVol(&VagCmd, 1);
}
iVar1 = iVar1 + 1;
} while (iVar1 < 4);
}
} else {
for (auto& VagCmd : VagCmds) {
SetVAGVol(&VagCmd, 1);
}
}
}
void CalculateVAGVolumes(VagCmd* cmd, int* l_out, int* r_out) {
// int iVar1;
// int iVar2;
// u32 uVar3;
void CalculateVAGVolumes(VagCmd* cmd, u32* l_out, u32* r_out) {
if (cmd->unk_296 == 0) {
u32 vol = (u32)(cmd->vol_multiplier * MasterVolume[VolumeCategory::DIALOGUE]) >> 6;
if (0x3fff < vol) {
if (vol >= 0x4000) {
vol = 0x3fff;
}
*l_out = vol;
*r_out = vol;
} else {
int fo_vol =
CalculateFallofVolume(&cmd->vec3, (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 10,
cmd->fo_curve, cmd->fo_min, cmd->fo_max);
int angle = CalculateAngle(&cmd->vec3);
int uVar4 = 0x276 - angle;
int uVar3 = (uVar4 >> 3) / 0x2d;
auto* pan = (s16*)gPanTable;
*l_out = (u32)(pan[uVar3 * -0x2d0 + uVar4 * 2] * fo_vol) >> 10;
*r_out = (u32)(pan[uVar3 * -0x2d0 + uVar4 * 2 + 1] * fo_vol) >> 10;
if (0x3fff < *l_out) {
CalculateFalloffVolume(&cmd->vec3, (u32)(cmd->vol_multiplier * MasterVolume[2]) >> 10,
cmd->fo_curve, cmd->fo_min, cmd->fo_max);
auto* pan = &gPanTable[(630 - CalculateAngle(&cmd->vec3)) % 360];
*l_out = (pan->left * fo_vol) >> 10;
*r_out = (pan->right * fo_vol) >> 10;
if (*l_out >= 0x4000) {
*l_out = 0x3fff;
}
if (0x3fff < *r_out) {
if (*r_out >= 0x4000) {
*r_out = 0x3fff;
}
}
+3 -3
View File
@@ -40,7 +40,7 @@ struct VagCmd {
int spu_trap_mem_addr; // 124
int voice; // 128
int idx_in_cmd_arr; // 132 (index in VagCmds)
int unk_136; // 136
int sound_handler; // 136 (989snd sound that played this stream)
int unk_140; // 140
int unk_176; // 176
int unk_180; // 180
@@ -95,7 +95,7 @@ struct VagCmd {
int priority; // 284
int unk_288; // 288
int unk_292; // 292
int unk_296; // 296
int unk_296; // 296 (audio has world positioning)
Vec3w vec3; // 300
int fo_min; // 312 (init to 5)
int fo_max; // 316 (init to 316)
@@ -142,4 +142,4 @@ VagCmd* FindVagStreamId(int id);
void SetVAGVol(VagCmd* cmd, int param_2);
void SetAllVagsVol(int vol);
void SetVagStreamsNotScanned();
} // namespace jak2
} // namespace jak2
+1 -1
View File
@@ -235,7 +235,7 @@ void ee_runner(SystemThreadInterface& iface) {
void ee_worker_runner(SystemThreadInterface& iface) {
iface.initialization_complete();
while (!iface.get_want_exit()) {
const auto queues_weres_empty = g_background_worker.process_queues();
const auto queues_weres_empty = !g_background_worker.process_queues();
if (queues_weres_empty) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
+37 -44
View File
@@ -12,19 +12,13 @@ namespace snd {
u64 SoundFlavaHack = 0;
u8 GlobalExcite = 0;
ame_handler::ame_handler(MultiMIDIBlockHeader* block,
voice_manager& vm,
MIDISound& sound,
s32 vol,
s32 pan,
locator& loc,
SoundBank& bank)
: m_sound(sound),
m_bank(bank),
m_header(block),
m_locator(loc),
m_vm(vm),
m_repeats(sound.Repeats) {
AmeHandler::AmeHandler(MultiMidi* block,
VoiceManager& vm,
MusicBank::MIDISound& sound,
s32 vol,
s32 pan,
SoundBank& bank)
: m_sound(sound), m_bank(bank), m_header(block), m_vm(vm), m_repeats(sound.Repeats) {
if (vol == VOLUME_DONT_CHANGE) {
vol = 1024;
}
@@ -41,12 +35,12 @@ ame_handler::ame_handler(MultiMIDIBlockHeader* block,
m_pan = pan;
}
start_segment(0);
StartSegment(0);
};
bool ame_handler::tick() {
bool AmeHandler::Tick() {
for (auto it = m_midis.begin(); it != m_midis.end();) {
bool done = it->second->tick();
bool done = it->second->Tick();
if (done) {
it = m_midis.erase(it);
} else {
@@ -57,48 +51,47 @@ bool ame_handler::tick() {
return m_midis.empty();
};
void ame_handler::start_segment(u32 id) {
void AmeHandler::StartSegment(u32 id) {
if (m_midis.find(id) == m_midis.end()) {
auto midiblock = (MIDIBlockHeader*)(m_header->BlockPtr[id] + (uintptr_t)m_header);
auto sound_handler = (MIDISoundHandler*)((uintptr_t)midiblock + sizeof(MIDIBlockHeader));
auto& midi = m_header->midi[id];
// Skip adding if not midi type
u32 type = (sound_handler->OwnerID >> 24) & 0xf;
u32 type = (midi.SoundHandle >> 24) & 0xf;
if (type == 1 || type == 3) {
m_midis.emplace(id, std::make_unique<midi_handler>(midiblock, m_vm, m_sound, m_vol, m_pan,
m_locator, m_bank, this));
m_midis.emplace(id, std::make_unique<MidiHandler>(static_cast<Midi*>(&midi), m_vm, m_sound,
m_vol, m_pan, m_bank, this));
}
}
}
void ame_handler::stop() {
void AmeHandler::Stop() {
for (auto it = m_midis.begin(); it != m_midis.end();) {
it->second->stop();
it->second->Stop();
it = m_midis.erase(it);
}
}
void ame_handler::stop_segment(u32 id) {
void AmeHandler::StopSegment(u32 id) {
auto m = m_midis.find(id);
if (m == m_midis.end())
return;
m->second->stop();
m->second->Stop();
}
void ame_handler::pause() {
void AmeHandler::Pause() {
for (auto& m : m_midis) {
m.second->pause();
m.second->Pause();
}
}
void ame_handler::unpause() {
void AmeHandler::Unpause() {
for (auto& m : m_midis) {
m.second->unpause();
m.second->Unpause();
}
}
void ame_handler::set_vol_pan(s32 vol, s32 pan) {
void AmeHandler::SetVolPan(s32 vol, s32 pan) {
if (vol >= 0) {
if (vol != VOLUME_DONT_CHANGE) {
m_vol = (m_sound.Vol * vol) >> 10;
@@ -118,13 +111,13 @@ void ame_handler::set_vol_pan(s32 vol, s32 pan) {
}
for (auto& m : m_midis) {
m.second->set_vol_pan(vol, pan);
m.second->SetVolPan(vol, pan);
}
}
void ame_handler::set_pmod(s32 mod) {
void AmeHandler::SetPMod(s32 mod) {
for (auto& m : m_midis) {
m.second->set_pmod(mod);
m.second->SetPMod(mod);
}
}
@@ -141,7 +134,7 @@ void ame_handler::set_pmod(s32 mod) {
; \
stream += (x);
std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
std::pair<bool, u8*> AmeHandler::RunAME(MidiHandler& midi, u8* stream) {
int skip = 0;
bool done = false;
bool cont = true;
@@ -186,7 +179,7 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
} break;
case 0x3: {
AME_BEGIN(op)
stop_segment(stream[0]);
StopSegment(stream[0]);
AME_END(1)
} break;
case 0x4: {
@@ -225,7 +218,7 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
} break;
case 0xc: {
AME_BEGIN(op)
auto [sub_cont, ptr] = run_ame(midi, m_macro[stream[0]]);
auto [sub_cont, ptr] = RunAME(midi, m_macro[stream[0]]);
if (!sub_cont) {
cont = false;
done = true;
@@ -236,12 +229,12 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
AME_BEGIN(op)
cont = false;
done = true;
start_segment(m_register[stream[0]] - 1);
StartSegment(m_register[stream[0]] - 1);
AME_END(1)
} break;
case 0xe: {
AME_BEGIN(op)
start_segment(m_register[stream[0]] - 1);
StartSegment(m_register[stream[0]] - 1);
AME_END(1)
} break;
case 0xf: {
@@ -285,9 +278,9 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
// note : added hack here! :-)
if (!SoundFlavaHack &&
(comp < m_groups[group].excite_min[i] || comp > m_groups[group].excite_max[i])) {
midi.mute_channel(m_groups[group].channel[i]);
midi.MuteChannel(m_groups[group].channel[i]);
} else {
midi.unmute_channel(m_groups[group].channel[i]);
midi.UnmuteChannel(m_groups[group].channel[i]);
}
}
AME_END(1)
@@ -296,12 +289,12 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
AME_BEGIN(op)
done = true;
cont = false;
start_segment(stream[0]);
StartSegment(stream[0]);
AME_END(1)
} break;
case 0x12: {
AME_BEGIN(op)
start_segment(stream[0]);
StartSegment(stream[0]);
AME_END(1)
} break;
case 0x13: {
@@ -334,7 +327,7 @@ std::pair<bool, u8*> ame_handler::run_ame(midi_handler& midi, u8* stream) {
AME_END(2)
} break;
default: {
throw ame_error(fmt::format("Unhandled AME event {:02x}", (u8)op));
throw AMEError(fmt::format("Unhandled AME event {:02x}", (u8)op));
} break;
}
+29 -30
View File
@@ -5,6 +5,7 @@
#include "loader.h"
#include "midi_handler.h"
#include "musicbank.h"
#include "sound_handler.h"
#include "vagvoice.h"
@@ -17,34 +18,33 @@ extern u64 SoundFlavaHack;
extern u8 GlobalExcite;
class midi_handler;
class ame_handler : public sound_handler {
friend class midi_handler;
class MidiHandler;
class AmeHandler : public SoundHandler {
friend class MidiHandler;
public:
ame_handler(MultiMIDIBlockHeader* block,
voice_manager& vm,
MIDISound& sound,
s32 vol,
s32 pan,
locator& loc,
SoundBank& bank);
bool tick() override;
SoundBank& bank() override { return m_bank; };
AmeHandler(MultiMidi* block,
VoiceManager& vm,
MusicBank::MIDISound& sound,
s32 vol,
s32 pan,
SoundBank& bank);
bool Tick() override;
SoundBank& Bank() override { return m_bank; };
void pause() override;
void unpause() override;
void stop() override;
u8 group() override { return m_sound.VolGroup; };
void set_vol_pan(s32 vol, s32 pan) override;
void Pause() override;
void Unpause() override;
void Stop() override;
u8 Group() override { return m_sound.VolGroup; };
void SetVolPan(s32 vol, s32 pan) override;
void set_register(u8 reg, u8 value) override { m_register[reg] = value; }
void set_pmod(s32 mod) override;
void SetRegister(u8 reg, u8 value) override { m_register[reg] = value; }
void SetPMod(s32 mod) override;
private:
struct ame_error : public std::exception {
ame_error(std::string text) : msg(std::move(text)) {}
ame_error() : msg("Unknown AME error") {}
struct AMEError : public std::exception {
AMEError(std::string text) : msg(std::move(text)) {}
AMEError() : msg("Unknown AME error") {}
std::string msg;
const char* what() const noexcept override { return msg.c_str(); }
};
@@ -58,21 +58,20 @@ class ame_handler : public sound_handler {
/* 24 */ s8 excite_max[16];
};
void start_segment(u32 id);
void stop_segment(u32 id);
std::pair<bool, u8*> run_ame(midi_handler&, u8* stream);
void StartSegment(u32 id);
void StopSegment(u32 id);
std::pair<bool, u8*> RunAME(MidiHandler&, u8* stream);
MIDISound& m_sound;
MusicBank::MIDISound& m_sound;
SoundBank& m_bank;
MultiMIDIBlockHeader* m_header{nullptr};
locator& m_locator;
voice_manager& m_vm;
MultiMidi* m_header{nullptr};
VoiceManager& m_vm;
s32 m_vol{0};
s32 m_pan{0};
s8 m_repeats{0};
std::unordered_map<u32, std::unique_ptr<midi_handler>> m_midis;
std::unordered_map<u32, std::unique_ptr<MidiHandler>> m_midis;
std::array<GroupDescription, 16> m_groups{};
std::array<u8, 16> m_register{};
+131 -35
View File
@@ -10,15 +10,111 @@
namespace snd {
std::array<s8, 32> g_block_reg{};
bool blocksound_handler::tick() {
m_voices.remove_if([](std::weak_ptr<blocksound_voice>& p) { return p.expired(); });
BlockSoundHandler::BlockSoundHandler(SoundBank& bank,
SFXBlock::SFX& sfx,
VoiceManager& vm,
s32 sfx_vol,
s32 sfx_pan,
SndPlayParams& params)
: m_group(sfx.VolGroup), m_sfx(sfx), m_vm(vm), m_bank(bank) {
s32 vol, pan, pitch_mod, pitch_bend;
if (sfx_vol == -1) {
sfx_vol = sfx.Vol;
}
if (sfx_pan == -1) {
sfx_pan = sfx.Pan;
}
if (params.vol.has_value()) {
vol = params.vol.value();
} else {
vol = 1024;
}
if (params.pan.has_value()) {
pan = params.pan.value();
} else {
pan = -1;
}
if (params.pitch_mod.has_value()) {
pitch_mod = params.pitch_mod.value();
} else {
pitch_mod = 0;
}
if (params.pitch_bend.has_value()) {
pitch_bend = params.pitch_bend.value();
} else {
pitch_bend = 0;
}
if (vol == VOLUME_DONT_CHANGE) {
vol = 1024;
}
s32 play_vol = (sfx_vol * vol) >> 10;
if (play_vol >= 128) {
play_vol = 127;
}
if (pan == PAN_RESET || pan == PAN_DONT_CHANGE) {
pan = sfx_pan;
}
m_orig_volume = sfx_vol;
m_orig_pan = sfx_pan;
m_cur_volume = play_vol;
m_cur_pan = pan;
m_cur_pb = pitch_bend;
m_cur_pm = pitch_mod;
m_app_volume = vol;
m_app_pan = pan;
m_app_pb = pitch_bend;
m_app_pm = pitch_mod;
m_lfo_volume = 0;
m_lfo_pan = 0;
m_lfo_pb = 0;
m_lfo_pm = 0;
if (params.registers.has_value()) {
m_registers = params.registers.value();
}
// Figure this stuff out properly someday
// if (m_sfx.d.Flags & 2) {
// fmt::print("solo flag\n");
// m_done = true;
// return;
// }
m_next_grain = 0;
m_countdown = m_sfx.Grains[0].Delay;
while (m_countdown <= 0 && !m_done) {
DoGrain();
}
}
BlockSoundHandler::~BlockSoundHandler() {
for (auto& p : m_voices) {
auto v = p.lock();
if (v != nullptr) {
v->Stop();
}
}
}
bool BlockSoundHandler::Tick() {
m_voices.remove_if([](std::weak_ptr<BlockSoundVoice>& p) { return p.expired(); });
for (auto& lfo : m_lfo) {
lfo.tick();
lfo.Tick();
}
for (auto it = m_children.begin(); it != m_children.end();) {
bool done = it->get()->tick();
bool done = it->get()->Tick();
if (done) {
it = m_children.erase(it);
} else {
@@ -39,17 +135,17 @@ bool blocksound_handler::tick() {
m_countdown--;
while (m_countdown <= 0 && !m_done) {
do_grain();
DoGrain();
}
return false;
};
void blocksound_handler::pause() {
void BlockSoundHandler::Pause() {
m_paused = true;
for (auto& c : m_children) {
c->pause();
c->Pause();
}
for (auto& p : m_voices) {
@@ -58,15 +154,15 @@ void blocksound_handler::pause() {
continue;
}
m_vm.pause(voice);
m_vm.Pause(voice);
}
}
void blocksound_handler::unpause() {
void BlockSoundHandler::Unpause() {
m_paused = false;
for (auto& c : m_children) {
c->unpause();
c->Unpause();
}
for (auto& p : m_voices) {
@@ -75,15 +171,15 @@ void blocksound_handler::unpause() {
continue;
}
m_vm.unpause(voice);
m_vm.Unpause(voice);
}
}
void blocksound_handler::stop() {
void BlockSoundHandler::Stop() {
m_done = true;
for (auto& c : m_children) {
c->stop();
c->Stop();
}
for (auto& p : m_voices) {
@@ -92,11 +188,11 @@ void blocksound_handler::stop() {
continue;
}
voice->key_off();
voice->KeyOff();
}
}
void blocksound_handler::set_vol_pan(s32 vol, s32 pan) {
void BlockSoundHandler::SetVolPan(s32 vol, s32 pan) {
if (vol >= 0) {
if (vol != VOLUME_DONT_CHANGE) {
m_app_volume = vol;
@@ -106,7 +202,7 @@ void blocksound_handler::set_vol_pan(s32 vol, s32 pan) {
}
if (pan == PAN_RESET) {
m_app_pan = m_sfx.d.Pan;
m_app_pan = m_sfx.Pan;
} else if (pan != PAN_DONT_CHANGE) {
m_app_pan = pan;
}
@@ -127,7 +223,7 @@ void blocksound_handler::set_vol_pan(s32 vol, s32 pan) {
m_cur_pan = new_pan;
for (auto& c : m_children) {
c->set_vol_pan(m_app_volume * m_orig_volume / 127, pan);
c->SetVolPan(m_app_volume * m_orig_volume / 127, pan);
}
for (auto& p : m_voices) {
@@ -136,16 +232,16 @@ void blocksound_handler::set_vol_pan(s32 vol, s32 pan) {
continue;
}
auto volume = m_vm.make_volume(127, 0, m_cur_volume, m_cur_pan, voice->g_vol, voice->g_pan);
auto left = m_vm.adjust_vol_to_group(volume.left, m_group);
auto right = m_vm.adjust_vol_to_group(volume.right, m_group);
auto volume = m_vm.MakeVolume(127, 0, m_cur_volume, m_cur_pan, voice->g_vol, voice->g_pan);
auto left = m_vm.AdjustVolToGroup(volume.left, m_group);
auto right = m_vm.AdjustVolToGroup(volume.right, m_group);
voice->set_volume(left >> 1, right >> 1);
voice->SetVolume(left >> 1, right >> 1);
}
}
}
void blocksound_handler::update_pitch() {
void BlockSoundHandler::UpdatePitch() {
m_cur_pm = m_app_pm + m_lfo_pm;
m_cur_pb = std::clamp<s32>(m_app_pb + m_lfo_pb, INT16_MIN, INT16_MAX);
@@ -155,34 +251,34 @@ void blocksound_handler::update_pitch() {
continue;
}
auto note = pitchbend(voice->tone, m_cur_pb, m_cur_pm, m_note, m_fine);
auto note = PitchBend(voice->tone, m_cur_pb, m_cur_pm, m_note, m_fine);
auto pitch =
PS1Note2Pitch(voice->tone.CenterNote, voice->tone.CenterFine, note.first, note.second);
voice->set_pitch(pitch);
voice->SetPitch(pitch);
}
}
void blocksound_handler::set_pmod(s32 mod) {
void BlockSoundHandler::SetPMod(s32 mod) {
for (auto& c : m_children) {
c->set_pmod(mod);
c->SetPMod(mod);
}
m_app_pm = mod;
update_pitch();
UpdatePitch();
}
void blocksound_handler::set_pbend(s32 bend) {
void BlockSoundHandler::SetPBend(s32 bend) {
for (auto& c : m_children) {
c->set_pbend(bend);
c->SetPBend(bend);
}
m_app_pb = bend;
update_pitch();
UpdatePitch();
}
void blocksound_handler::do_grain() {
auto& grain = m_sfx.grains[m_next_grain];
void BlockSoundHandler::DoGrain() {
auto& grain = m_sfx.Grains[m_next_grain];
s32 ret = grain->execute(*this);
s32 ret = grain(*this);
if (m_skip_grains) {
m_grains_to_play--;
@@ -193,12 +289,12 @@ void blocksound_handler::do_grain() {
}
m_next_grain++;
if (m_next_grain >= m_sfx.grains.size()) {
if (m_next_grain >= m_sfx.Grains.size()) {
m_done = true;
return;
}
m_countdown = m_sfx.grains[m_next_grain]->delay() + ret;
m_countdown = m_sfx.Grains[m_next_grain].Delay + ret;
}
} // namespace snd
+27 -117
View File
@@ -5,132 +5,44 @@
#include "common/common_types.h"
#include "game/sound/989snd/lfo.h"
#include "sfxblock2.h"
#include "game/sound/989snd/sfxblock.h"
namespace snd {
extern std::array<s8, 32> g_block_reg;
class blocksound_voice : public vag_voice {
class BlockSoundVoice : public VagVoice {
public:
blocksound_voice(Tone& t) : vag_voice(t) {}
BlockSoundVoice(Tone& t) : VagVoice(t) {}
s32 g_vol;
s32 g_pan;
};
class blocksound_handler : public sound_handler {
class BlockSoundHandler : public SoundHandler {
public:
blocksound_handler(SoundBank& bank,
SFX2& sfx,
voice_manager& vm,
s32 sfx_vol,
s32 sfx_pan,
SndPlayParams& params)
: m_group(sfx.d.VolGroup), m_sfx(sfx), m_vm(vm), m_bank(bank) {
s32 vol, pan, pitch_mod, pitch_bend;
if (sfx_vol == -1) {
sfx_vol = sfx.d.Vol;
}
if (sfx_pan == -1) {
sfx_pan = sfx.d.Pan;
}
BlockSoundHandler(SoundBank& bank,
SFXBlock::SFX& sfx,
VoiceManager& vm,
s32 sfx_vol,
s32 sfx_pan,
SndPlayParams& params);
if (params.vol.has_value()) {
vol = params.vol.value();
} else {
vol = 1024;
}
~BlockSoundHandler() override;
bool Tick() override;
SoundBank& Bank() override { return m_bank; };
if (params.pan.has_value()) {
pan = params.pan.value();
} else {
pan = -1;
}
void Pause() override;
void Unpause() override;
void Stop() override;
u8 Group() override { return m_group; };
void SetVolPan(s32 vol, s32 pan) override;
void SetPMod(s32 mod) override;
void SetRegister(u8 reg, u8 value) override { m_registers.at(reg) = value; };
void SetPBend(s32 bend) override;
if (params.pitch_mod.has_value()) {
pitch_mod = params.pitch_mod.value();
} else {
pitch_mod = 0;
}
void DoGrain();
if (params.pitch_bend.has_value()) {
pitch_bend = params.pitch_bend.value();
} else {
pitch_bend = 0;
}
if (vol == VOLUME_DONT_CHANGE) {
vol = 1024;
}
s32 play_vol = (sfx_vol * vol) >> 10;
if (play_vol >= 128) {
play_vol = 127;
}
if (pan == PAN_RESET || pan == PAN_DONT_CHANGE) {
pan = sfx_pan;
}
m_orig_volume = sfx_vol;
m_orig_pan = sfx_pan;
m_cur_volume = play_vol;
m_cur_pan = pan;
m_cur_pb = pitch_bend;
m_cur_pm = pitch_mod;
m_app_volume = vol;
m_app_pan = pan;
m_app_pb = pitch_bend;
m_app_pm = pitch_mod;
m_lfo_volume = 0;
m_lfo_pan = 0;
m_lfo_pb = 0;
m_lfo_pm = 0;
if (params.registers.has_value()) {
m_registers = params.registers.value();
}
// Figure this stuff out properly someday
// if (m_sfx.d.Flags & 2) {
// fmt::print("solo flag\n");
// m_done = true;
// return;
// }
m_next_grain = 0;
m_countdown = m_sfx.grains[0]->delay();
while (m_countdown <= 0 && !m_done) {
do_grain();
}
}
~blocksound_handler() override {
for (auto& p : m_voices) {
auto v = p.lock();
if (v != nullptr) {
v->stop();
}
}
}
bool tick() override;
SoundBank& bank() override { return m_bank; };
void pause() override;
void unpause() override;
void stop() override;
u8 group() override { return m_group; };
void set_vol_pan(s32 vol, s32 pan) override;
void set_pmod(s32 mod) override;
void set_register(u8 reg, u8 value) override { m_registers.at(reg) = value; };
void set_pbend(s32 bend) override;
void do_grain();
void update_pitch();
void UpdatePitch();
bool m_paused{false};
@@ -141,12 +53,12 @@ class blocksound_handler : public sound_handler {
u32 m_grains_to_skip{0};
bool m_skip_grains{false};
SFX2& m_sfx;
voice_manager& m_vm;
SFXBlock::SFX& m_sfx;
VoiceManager& m_vm;
std::list<std::weak_ptr<blocksound_voice>> m_voices;
std::list<std::weak_ptr<BlockSoundVoice>> m_voices;
std::list<std::unique_ptr<sound_handler>> m_children;
std::list<std::unique_ptr<SoundHandler>> m_children;
s32 m_orig_volume{0};
s32 m_orig_pan{0};
@@ -172,8 +84,6 @@ class blocksound_handler : public sound_handler {
std::array<s8, 4> m_registers{};
std::array<LFOTracker, 4> m_lfo{{*this, *this, *this, *this}};
// TODO LFO
s32 m_countdown{0};
u32 m_next_grain{0};
};
+9 -9
View File
@@ -9,24 +9,24 @@
namespace snd {
class id_allocator {
class IdAllocator {
public:
u32 get_id() {
u32 GetId() {
u32 id = 0;
if (m_free_ids.empty()) {
id = next_id++;
if (mFreeIds.empty()) {
id = mNextId++;
} else {
id = m_free_ids.front();
m_free_ids.pop();
id = mFreeIds.front();
mFreeIds.pop();
}
return id;
}
void free_id(u32 id) { m_free_ids.push(id); }
void FreeId(u32 id) { mFreeIds.push(id); }
private:
u32 next_id{1};
std::queue<u32> m_free_ids;
u32 mNextId{1};
std::queue<u32> mFreeIds;
};
} // namespace snd
+33 -33
View File
@@ -7,79 +7,79 @@
namespace snd {
#include "lfo_sine.c.inc"
void LFOTracker::init() {
if (m_type == lfo_type::RAND) {
void LFOTracker::Init() {
if (m_type == LFOType::RAND) {
m_state_hold1 = -(rand() & 0x7fff) * (rand() & 1);
m_state_hold2 = 1;
}
calc_depth();
tick();
CalcDepth();
Tick();
}
void LFOTracker::calc_depth() {
if (m_target == lfo_target::VOLUME) {
m_range = (m_handler.m_sfx.d.Vol * m_depth) >> 10;
void LFOTracker::CalcDepth() {
if (m_target == LFOTarget::VOLUME) {
m_range = (m_handler.m_sfx.Vol * m_depth) >> 10;
}
if (m_target == lfo_target::PAN) {
if (m_target == LFOTarget::PAN) {
m_range = (180 * m_depth) >> 10;
}
if (m_target == lfo_target::PMOD) {
if (m_target == LFOTarget::PMOD) {
m_range = (6096 * m_depth) >> 10;
}
if (m_target == lfo_target::PBEND) {
if (m_target == LFOTarget::PBEND) {
m_range = (0x7fff * m_depth) >> 10;
}
m_last_lfo = 0;
}
void LFOTracker::tick() {
void LFOTracker::Tick() {
m_tick++;
if (m_target == lfo_target::NONE || (m_tick & 1) == 0) {
if (m_target == LFOTarget::NONE || (m_tick & 1) == 0) {
return;
}
switch (m_target) {
case lfo_target::VOLUME: {
s32 vol = (m_range * (get_lfo(2) - 0x7fff)) >> 16;
case LFOTarget::VOLUME: {
s32 vol = (m_range * (GetLFO(2) - 0x7fff)) >> 16;
if (m_handler.m_lfo_volume != vol) {
m_handler.m_lfo_volume = vol;
m_handler.set_vol_pan(VOLUME_DONT_CHANGE, PAN_DONT_CHANGE);
m_handler.SetVolPan(VOLUME_DONT_CHANGE, PAN_DONT_CHANGE);
}
} break;
case lfo_target::PAN: {
s32 pan = (m_range * get_lfo(2)) >> 15;
case LFOTarget::PAN: {
s32 pan = (m_range * GetLFO(2)) >> 15;
if (m_handler.m_lfo_pan != pan) {
m_handler.m_lfo_pan = pan;
m_handler.set_vol_pan(VOLUME_DONT_CHANGE, PAN_DONT_CHANGE);
m_handler.SetVolPan(VOLUME_DONT_CHANGE, PAN_DONT_CHANGE);
}
} break;
case lfo_target::PMOD: {
s32 pm = (get_lfo(2) * m_range) >> 15;
case LFOTarget::PMOD: {
s32 pm = (GetLFO(2) * m_range) >> 15;
if (m_handler.m_lfo_pm != pm) {
m_handler.m_lfo_pm = pm;
m_handler.update_pitch();
m_handler.UpdatePitch();
}
} break;
case lfo_target::PBEND: {
s32 pb = (get_lfo(2) * m_range) >> 15;
case LFOTarget::PBEND: {
s32 pb = (GetLFO(2) * m_range) >> 15;
if (m_handler.m_lfo_pb != pb) {
m_handler.m_lfo_pb = pb;
m_handler.update_pitch();
m_handler.UpdatePitch();
}
} break;
case lfo_target::UNK1: {
case LFOTarget::UNK1: {
} break;
case lfo_target::UNK2: {
case LFOTarget::UNK2: {
} break;
default:
break;
}
}
s32 LFOTracker::get_lfo(s32 step_mult) {
s32 LFOTracker::GetLFO(s32 step_mult) {
s32 step = m_next_step >> 16;
m_next_step += step_mult * m_step_size;
if (m_next_step > 0x7ffffff) {
@@ -89,20 +89,20 @@ s32 LFOTracker::get_lfo(s32 step_mult) {
s32 ret = 0;
switch (m_type) {
case lfo_type::OFF:
case LFOType::OFF:
ret = 0;
break;
case lfo_type::SINE:
case LFOType::SINE:
ret = gLFO_sine.at(step);
break;
case lfo_type::SQUARE:
case LFOType::SQUARE:
if (step >= m_state_hold1) {
ret = -32767;
} else {
ret = 32767;
}
break;
case lfo_type::TRIANGLE:
case LFOType::TRIANGLE:
if (step < 512) {
ret = 0x7fff * step / 512;
} else if (step >= 1536) {
@@ -111,14 +111,14 @@ s32 LFOTracker::get_lfo(s32 step_mult) {
ret = 0x7fff - 65534 * (step - 512) / 1024;
}
break;
case lfo_type::SAW:
case LFOType::SAW:
if (step >= 1024) {
ret = 0x7fff * (step - 1024) / 1024 - 0x7fff;
} else {
ret = 0x7fff * step / 1023;
}
break;
case lfo_type::RAND:
case LFOType::RAND:
if (step >= 1024 && m_state_hold2 == 1) {
m_state_hold2 = 0;
m_state_hold1 = 2 * ((rand() & 0x7fff) - 0x3fff);
+11 -11
View File
@@ -5,16 +5,16 @@
namespace snd {
enum class lfo_type { OFF, SINE, SQUARE, TRIANGLE, SAW, RAND };
enum class lfo_target { NONE, VOLUME, PAN, PMOD, PBEND, UNK1, UNK2 };
enum class LFOType { OFF, SINE, SQUARE, TRIANGLE, SAW, RAND };
enum class LFOTarget { NONE, VOLUME, PAN, PMOD, PBEND, UNK1, UNK2 };
class blocksound_handler;
class BlockSoundHandler;
class LFOTracker {
public:
LFOTracker(blocksound_handler& handler) : m_handler(handler) {}
lfo_type m_type{lfo_type::OFF};
lfo_target m_target{0};
LFOTracker(BlockSoundHandler& handler) : m_handler(handler) {}
LFOType m_type{LFOType::OFF};
LFOTarget m_target{0};
u8 m_target_extra{0};
u8 m_setup_flags{0};
u8 m_running_flags{0};
@@ -30,12 +30,12 @@ class LFOTracker {
u32 m_tick{0};
void init();
void calc_depth();
void tick();
s32 get_lfo(s32 step_mult);
void Init();
void CalcDepth();
void Tick();
s32 GetLFO(s32 step_mult);
blocksound_handler& m_handler;
BlockSoundHandler& m_handler;
};
} // namespace snd
+437 -118
View File
@@ -5,121 +5,462 @@
#include <fstream>
#include <optional>
#include "midi_handler.h"
#include "sfxblock.h"
#include "common/log/log.h"
#include "common/util/BinaryReader.h"
#include "sfxblock2.h"
#include "game/sound/989snd/musicbank.h"
#include "third-party/fmt/core.h"
namespace snd {
enum chunk : u32 { bank, samples, midi };
#define FOURCC(a, b, c, d) ((u32)(((d) << 24) | ((c) << 16) | ((b) << 8) | (a)))
u32 loader::read_bank(std::fstream& in) {
size_t origin = in.tellg();
FileAttributes<3> attr;
in.read((char*)(&attr), sizeof(attr));
if (attr.type != 1 && attr.type != 3) {
lg::error("Error: File type {} not supported.", attr.type);
return -1;
}
/*
* if there's midi data the pointer to the allocated memory is stored
* just before the sound bank data...
if (attr.num_chunks > 2) {
attr.where[chunk::bank].size += 4;
}
*/
// auto pos = in.tellg();
auto bank_buf = std::make_unique<u8[]>(attr.where[chunk::bank].size);
in.seekg(origin + attr.where[chunk::bank].offset, std::fstream::beg);
in.read((char*)bank_buf.get(), attr.where[chunk::bank].size);
auto bank_tag = (BankTag*)bank_buf.get();
u32 bank_id = m_id_allocator.get_id();
std::unique_ptr<SoundBank> bank;
if (bank_tag->DataID == FOURCC('S', 'B', 'v', '2')) {
bank = std::make_unique<MusicBank>(*this, bank_id, bank_tag);
} else if (bank_tag->DataID == FOURCC('S', 'B', 'l', 'k')) {
if (bank_tag->Version < 2) {
bank = std::make_unique<SFXBlock>(*this, bank_id, bank_tag);
} else {
bank = std::make_unique<SFXBlock2>(*this, bank_id, bank_tag);
}
} else {
m_id_allocator.free_id(bank_id);
throw std::runtime_error("Unknown bank ID, bad file?");
}
m_soundbanks.emplace(bank_id, std::move(bank));
if (attr.num_chunks >= 2) {
in.seekg(origin + attr.where[chunk::samples].offset, std::fstream::beg);
auto samples = std::make_unique<u8[]>(attr.where[chunk::samples].size);
in.read((char*)samples.get(), attr.where[chunk::samples].size);
load_samples(bank_id, std::move(samples));
}
if (attr.num_chunks >= 3) {
in.seekg(origin + attr.where[chunk::midi].offset, std::fstream::beg);
load_midi(in);
}
return bank_id;
inline static constexpr u32 fourcc(std::string_view p) {
return p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
}
void loader::load_midi(std::fstream& in) {
FileAttributes<1> attr;
u32 cur = in.tellg();
void FileAttributes::Read(BinaryReader& data) {
type = data.read<u32>();
num_chunks = data.read<u32>();
in.read((char*)&attr, sizeof(attr));
in.seekg(cur + attr.where[0].offset, std::fstream::beg);
auto midi = std::make_unique<u8[]>(attr.where[0].size);
in.read((char*)midi.get(), attr.where[0].size);
auto h = (MIDIBlock*)midi.get();
lg::info("Loaded midi {:.4}", (char*)&h->ID);
m_midi.emplace(h->ID, (MIDIBlock*)midi.get());
m_midi_chunks.emplace_back(std::move(midi));
where.resize(num_chunks);
for (int i = 0; i < num_chunks; i++) {
where[i].offset = data.read<u32>();
where[i].size = data.read<u32>();
}
}
SoundBank* loader::get_bank_by_handle(u32 id) {
if (m_soundbanks.find(id) == m_soundbanks.end()) {
static Tone ReadTone(BinaryReader& data, u8* samples) {
Tone tone{};
tone.Priority = data.read<s8>();
tone.Vol = data.read<s8>();
tone.CenterNote = data.read<s8>();
tone.CenterFine = data.read<s8>();
tone.Pan = data.read<s16>();
tone.MapLow = data.read<s8>();
tone.MapHigh = data.read<s8>();
tone.PBLow = data.read<s8>();
tone.PBHigh = data.read<s8>();
tone.ADSR1 = data.read<u16>();
tone.ADSR2 = data.read<u16>();
tone.Flags = data.read<u16>();
u32 SampleOffset = data.read<u32>();
tone.Sample = &samples[SampleOffset];
data.read<u32>(); // reserved1
return tone;
};
static Midi ReadMidi(BinaryReader& data) {
Midi mid;
u8* base = const_cast<u8*>(data.here());
mid.DataID = data.read<u32>();
mid.Version = data.read<s16>();
mid.Flags = data.read<s8>();
data.read<s8>();
mid.ID = data.read<u32>();
data.read<u32>();
mid.BankID = data.read<u32>();
data.read<u32>();
u32 DataStart = data.read<u32>();
mid.DataStart = base + DataStart;
data.read<u32>();
mid.Tempo = data.read<u32>();
mid.PPQ = data.read<s32>();
return mid;
}
static MultiMidi ReadMultiMidi(BinaryReader& data) {
MultiMidi mmid;
mmid.DataID = data.read<u32>();
mmid.Version = data.read<s16>();
mmid.Flags = data.read<s8>();
s8 NumSegments = data.read<s8>();
mmid.midi.resize(NumSegments);
mmid.ID = data.read<u32>();
data.read<u32>();
for (auto& midi : mmid.midi) {
u32 offset = data.read<u32>();
auto mr = data.at(offset);
midi.Midi::operator=(ReadMidi(mr));
midi.SoundHandle = mr.read<u32>();
}
return mmid;
}
static Grain ReadGrainV1(BinaryReader& data, u8* samples) {
Grain grain{};
u32 pos = data.get_seek();
grain.Type = static_cast<GrainType>(data.read<u32>());
grain.Delay = data.read<s32>();
switch (grain.Type) {
case GrainType::TONE:
case GrainType::TONE2: {
grain.data = ReadTone(data, samples);
} break;
case GrainType::LFO_SETTINGS: {
grain.data = data.read<LFOParams>();
} break;
case GrainType::BRANCH:
case GrainType::STARTCHILDSOUND:
case GrainType::STOPCHILDSOUND:
grain.data = data.read<PlaySoundParams>();
break;
case GrainType::PLUGIN_MESSAGE:
grain.data = data.read<PluginParams>();
break;
case GrainType::RAND_DELAY:
grain.data = data.read<RandDelayParams>();
break;
default:
grain.data = data.read<ControlParams>();
break;
}
data.set_seek(pos);
data.ffwd(0x28);
return grain;
};
static Grain ReadGrainV2(BinaryReader& data, BinaryReader grainData, u8* samples) {
union OpcodeData {
struct {
s8 arg[3];
u8 type;
};
u32 Opcode;
} op;
Grain grain{};
op = data.read<OpcodeData>();
grain.Type = static_cast<GrainType>(op.type);
grain.Delay = data.read<s32>();
u32 value = op.Opcode & 0xFFFFFF;
switch (grain.Type) {
case GrainType::TONE:
case GrainType::TONE2: {
grainData.set_seek(value);
grain.data = ReadTone(grainData, samples);
} break;
case GrainType::LFO_SETTINGS: {
grainData.set_seek(value);
grain.data = grainData.read<LFOParams>();
} break;
case GrainType::BRANCH:
case GrainType::STARTCHILDSOUND:
case GrainType::STOPCHILDSOUND:
grainData.set_seek(value);
grain.data = grainData.read<PlaySoundParams>();
break;
case GrainType::PLUGIN_MESSAGE:
grainData.set_seek(value);
grain.data = grainData.read<PluginParams>();
break;
case GrainType::RAND_DELAY:
RandDelayParams rp;
rp.Amount = (s32)value + 1;
grain.data = rp;
break;
default:
ControlParams p;
p.param[0] = op.arg[0];
p.param[1] = op.arg[1];
p.param[2] = op.arg[2];
grain.data = p;
break;
}
return grain;
};
SFXBlock* SFXBlock::ReadBlock(nonstd::span<u8> bank_data, nonstd::span<u8> samples) {
BinaryReader data(bank_data);
// auto block = std::make_unique<SFXBlock>();
auto block = new SFXBlock();
block->DataID = data.read<u32>();
if (block->DataID != fourcc("SBlk")) {
return nullptr;
}
return m_soundbanks[id].get();
}
block->SampleData = std::make_unique<u8[]>(samples.size());
std::copy(samples.begin(), samples.end(), block->SampleData.get());
MusicBank* loader::get_bank_by_id(u32 id) {
for (auto& b : m_soundbanks) {
if (b.second->type == BankType::Music) {
auto* bank = static_cast<MusicBank*>(b.second.get());
if (bank->bank_name == id) {
return bank;
block->Version = data.read<u32>();
block->Flags.flags = data.read<u32>();
block->BankID = data.read<u32>();
block->BankNum = data.read<s8>();
// discard padding
data.read<s8>();
data.read<s16>();
data.read<s16>();
s16 NumSounds = data.read<s16>();
block->Sounds.resize(NumSounds);
s16 NumGrains = data.read<s16>();
s16 NumVAGs = data.read<s16>();
u32 FirstSound = data.read<u32>();
u32 FirstGrain = data.read<u32>();
u32 VagsInSR = data.read<u32>();
u32 VagDataSize = data.read<u32>();
u32 SRAMAllocSize = data.read<u32>();
u32 NextBlock = data.read<u32>();
u32 GrainData = 0;
if (block->Version >= 2) {
GrainData = data.read<u32>();
}
u32 BlockNames = data.read<u32>();
u32 SFXUD = data.read<u32>();
data.set_seek(FirstSound);
for (auto& sfx : block->Sounds) {
sfx.Vol = data.read<s8>();
sfx.VolGroup = data.read<s8>();
sfx.Pan = data.read<s16>();
s8 NumGrains = data.read<s8>();
sfx.Grains.resize(NumGrains);
sfx.InstanceLimit = data.read<s8>();
sfx.Flags.flags = data.read<u16>();
u32 FirstSFXGrain = data.read<u32>();
if (NumGrains) {
auto grains = data.at(FirstGrain + FirstSFXGrain);
for (auto& grain : sfx.Grains) {
if (block->Version < 2) {
grain = ReadGrainV1(grains, block->SampleData.get());
} else {
grain = ReadGrainV2(grains, data.at(GrainData), block->SampleData.get());
}
}
}
}
if (block->Flags.hasNames()) {
struct SFXBlockNames { // 0x98
/* 0x00 */ u32 BlockName[2];
/* 0x08 */ u32 SFXNameTableOffset;
/* 0x0c */ u32 VAGNameTableOffset;
/* 0x10 */ u32 VAGImportsTableOffset;
/* 0x14 */ u32 VAGExportsTableOffset;
/* 0x18 */ s16 SFXHashOffsets[32];
/* 0x58 */ s16 VAGHashOffsets[32];
};
struct SFXName { // 0x14
/* 0x00 */ u32 Name[4];
/* 0x10 */ s16 Index;
/* 0x12 */ s16 reserved;
};
data.set_seek(BlockNames);
auto names = data.read<SFXBlockNames>();
char buf[17];
buf[16] = 0;
strncpy(buf, (char*)names.BlockName, 8);
block->Name = buf;
data.set_seek(BlockNames + names.SFXNameTableOffset);
auto name_table = (SFXName*)(data.here());
for (auto SFXHashOffset : names.SFXHashOffsets) {
auto name = &name_table[SFXHashOffset];
while (name->Name[0] != 0) {
strncpy(buf, (char*)name->Name, 16);
std::string str(buf);
if (block->Names.find(str) == block->Names.end()) {
block->Names[str] = name->Index;
}
name++;
}
}
}
if (block->Flags.hasUserdata()) {
data.set_seek(SFXUD);
for (auto& sfx : block->Sounds) {
sfx.UserData.data[0] = data.read<u32>();
sfx.UserData.data[1] = data.read<u32>();
sfx.UserData.data[2] = data.read<u32>();
sfx.UserData.data[3] = data.read<u32>();
}
}
return block;
}
MusicBank* MusicBank::ReadBank(nonstd::span<u8> bank_data,
nonstd::span<u8> samples,
nonstd::span<u8> midi_data) {
BinaryReader data(bank_data);
// auto bank = std::make_unique<MusicBank>();
auto bank = new MusicBank();
bank->DataID = data.read<u32>();
if (bank->DataID != fourcc("SBv2")) {
return nullptr;
}
bank->SampleData = std::make_unique<u8[]>(samples.size_bytes());
std::copy(samples.begin(), samples.end(), bank->SampleData.get());
bank->SeqData = std::make_unique<u8[]>(midi_data.size_bytes());
std::copy(midi_data.begin(), midi_data.end(), bank->SeqData.get());
bank->Version = data.read<u32>();
bank->Flags.flags = data.read<u32>();
bank->BankID = data.read<u32>();
bank->BankNum = data.read<s8>();
// discard padding
data.read<s8>();
data.read<s16>();
s16 NumSounds = data.read<s16>();
bank->Sounds.resize(NumSounds);
s16 NumProgs = data.read<s16>();
bank->Progs.resize(NumProgs);
s16 NumTones = data.read<s16>();
s16 NumVAGs = data.read<s16>();
u32 FirstSound = data.read<u32>();
u32 FirstProg = data.read<u32>();
u32 FirstTone = data.read<u32>();
// vagsinsr
data.read<u32>();
// vagdatasize
data.read<u32>();
data.set_seek(FirstSound);
for (auto& sound : bank->Sounds) {
sound.Type = data.read<s32>();
data.read<u32>(); // bankptr
data.read<u32>(); // ogbankptr
sound.MIDIID = data.read<s32>();
sound.Vol = data.read<s16>();
sound.Repeats = data.read<s8>();
sound.VolGroup = data.read<s8>();
sound.Pan = data.read<s16>();
sound.Index = data.read<s8>();
sound.Flags = data.read<u8>();
data.read<u32>(); // midiblockptr
sound.Bank = bank;
sound.OrigBank = bank;
}
data.set_seek(FirstProg);
for (auto& prog : bank->Progs) {
s8 NumTones = data.read<s8>();
prog.Vol = data.read<s8>();
prog.Pan = data.read<s16>();
u32 FirstTone = data.read<u32>();
prog.Tones.resize(NumTones);
auto tones = data.at(FirstTone);
for (auto& tone : prog.Tones) {
tone = ReadTone(tones, bank->SampleData.get());
}
}
auto seq_buf = nonstd::span<u8>(bank->SeqData.get(), midi_data.size_bytes());
BinaryReader seq_data(seq_buf);
FileAttributes fa;
fa.Read(seq_data);
BinaryReader midi(seq_buf.subspan(fa.where[0].offset));
u32 id = midi.read<u32>();
midi.set_seek(0);
if (id == fourcc("MID ")) {
bank->MidiData = ReadMidi(midi);
} else if (id == fourcc("MMID")) {
bank->MidiData = ReadMultiMidi(midi);
} else {
lg::error("Invalid midi\n");
}
return bank;
}
BankHandle Loader::BankLoad(nonstd::span<u8> bank) {
BinaryReader reader(bank);
FileAttributes fa;
fa.Read(reader);
if (fa.type != 1 && fa.type != 3) {
fmt::print("bad file type\n");
return nullptr;
}
reader.set_seek(fa.where[0].offset);
u32 fourcc = reader.read<u32>();
nonstd::span<u8> bank_data(nonstd::span<u8>(bank).subspan(fa.where[0].offset, fa.where[0].size));
nonstd::span<u8> sample_data(
nonstd::span<u8>(bank).subspan(fa.where[1].offset, fa.where[1].size));
if (fourcc == snd::fourcc("SBv2")) {
if (fa.num_chunks != 3) {
fmt::print("SBv2 without midi data not supported\n");
return 0;
}
nonstd::span<u8> midi_data(
nonstd::span<u8>(bank).subspan(fa.where[2].offset, fa.where[2].size));
auto bank = MusicBank::ReadBank(bank_data, sample_data, midi_data);
mBanks.emplace_back(bank);
return bank;
} else if (fourcc == snd::fourcc("SBlk")) {
auto block = SFXBlock::ReadBlock(bank_data, sample_data);
mBanks.emplace_back(block);
return block;
}
return nullptr;
}
SoundBank* loader::get_bank_by_name(const char* name) {
for (auto& b : m_soundbanks) {
auto bankname = b.second->get_name();
SoundBank* Loader::GetBankByHandle(BankHandle handle) {
auto bank = std::find_if(mBanks.begin(), mBanks.end(),
[handle](auto& bank) { return bank.get() == handle; });
if (bank == mBanks.end()) {
return nullptr;
}
return bank->get();
}
SoundBank* Loader::GetBankByName(const char* name) {
for (auto& b : mBanks) {
auto bankname = b->GetName();
if (bankname.has_value()) {
if (bankname->compare(name) == 0) {
return b.second.get();
return b.get();
}
}
}
@@ -127,45 +468,23 @@ SoundBank* loader::get_bank_by_name(const char* name) {
return nullptr;
}
SoundBank* loader::get_bank_with_sound(const char* name) {
for (auto& b : m_soundbanks) {
auto sound = b.second->get_sound_by_name(name);
SoundBank* Loader::GetBankWithSound(const char* name) {
for (auto& b : mBanks) {
auto sound = b->GetSoundByName(name);
if (sound.has_value()) {
return b.second.get();
return b.get();
}
}
return nullptr;
}
MIDIBlock* loader::get_midi(u32 id) {
return m_midi.at(id);
}
u8* loader::get_bank_samples(u32 id) {
return m_soundbanks.at(id).get()->sampleBuf.get();
}
void loader::load_samples(u32 bank_id, std::unique_ptr<u8[]> samples) {
auto& bank = m_soundbanks.at(bank_id);
bank->sampleBuf = std::move(samples);
}
void loader::unload_bank(u32 id) {
fmt::print("Deleting bank {}\n", id);
for (auto it = m_midi_chunks.begin(); it != m_midi_chunks.end();) {
bool del = false;
// FIXME delete midi
if (del) {
it = m_midi_chunks.erase(it);
} else {
++it;
}
void Loader::UnloadBank(BankHandle handle) {
auto bank = std::find_if(mBanks.begin(), mBanks.end(),
[handle](auto& bank) { return bank.get() == handle; });
if (bank != mBanks.end()) {
mBanks.erase(bank);
}
m_soundbanks.erase(id);
m_id_allocator.free_id(id);
}
} // namespace snd
+21 -38
View File
@@ -5,58 +5,41 @@
#include <memory>
#include <vector>
#include "handle_allocator.h"
#include "musicbank.h"
#include "sfxblock.h"
#include "sound_handler.h"
#include "soundbank.h"
#include "common/common_types.h"
#include "common/util/BinaryReader.h"
#include "../common/synth.h"
#include "third-party/span.hpp"
namespace snd {
#define FOURCC(a, b, c, d) ((u32)(((d) << 24) | ((c) << 16) | ((b) << 8) | (a)))
struct LocAndSize {
/* 0 */ u32 offset;
/* 4 */ u32 size;
};
using BankHandle = SoundBank*;
template <size_t chunks>
struct FileAttributes {
/* 0 */ u32 type;
/* 4 */ u32 num_chunks;
/* 8 */ LocAndSize where[chunks];
};
class loader : public locator {
class FileAttributes {
public:
SoundBank* get_bank_by_handle(u32 id) override;
MusicBank* get_bank_by_id(u32 id) override;
MIDIBlock* get_midi(u32 id) override;
u8* get_bank_samples(u32 id) override;
struct LocAndSize {
u32 offset;
u32 size;
};
SoundBank* get_bank_by_name(const char* name);
SoundBank* get_bank_with_sound(const char* name);
u32 type;
u32 num_chunks;
std::vector<LocAndSize> where;
void Read(BinaryReader& data);
};
void unload_bank(u32 id);
class Loader {
public:
SoundBank* GetBankByHandle(BankHandle id);
SoundBank* GetBankByName(const char* name);
SoundBank* GetBankWithSound(const char* name);
u32 read_bank(std::fstream& in);
void load_midi(std::fstream& in);
void UnloadBank(BankHandle id);
bool read_midi();
BankHandle BankLoad(nonstd::span<u8> bank);
private:
void load_samples(u32 bank, std::unique_ptr<u8[]> samples);
id_allocator m_id_allocator;
std::unordered_map<u32, std::unique_ptr<SoundBank>> m_soundbanks;
std::vector<std::unique_ptr<u8[]>> m_midi_chunks;
std::unordered_map<u32, MIDIBlock*> m_midi;
u32 m_next_id{0};
std::vector<std::unique_ptr<SoundBank>> mBanks;
};
} // namespace snd
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include "common/common_types.h"
namespace snd {
class MusicBank;
class SoundBank;
struct MIDIBlock;
class locator {
public:
virtual ~locator() = default;
virtual SoundBank* get_bank_by_handle(u32 id) = 0;
virtual MusicBank* get_bank_by_id(u32 id) = 0;
virtual u8* get_bank_samples(u32 id) = 0;
virtual MIDIBlock* get_midi(u32 id) = 0;
};
} // namespace snd
+79 -85
View File
@@ -22,19 +22,13 @@ namespace snd {
**
*/
midi_handler::midi_handler(MIDIBlockHeader* block,
voice_manager& vm,
MIDISound& sound,
s32 vol,
s32 pan,
locator& loc,
SoundBank& bank)
: m_sound(sound),
m_locator(loc),
m_repeats(sound.Repeats),
m_bank(bank),
m_header(block),
m_vm(vm) {
MidiHandler::MidiHandler(Midi* block,
VoiceManager& vm,
MusicBank::MIDISound& sound,
s32 vol,
s32 pan,
SoundBank& bank)
: m_sound(sound), m_repeats(sound.Repeats), m_bank(bank), m_header(block), m_vm(vm) {
if (vol == VOLUME_DONT_CHANGE) {
vol = 1024;
}
@@ -50,31 +44,29 @@ midi_handler::midi_handler(MIDIBlockHeader* block,
m_pan = pan;
}
init_midi();
InitMidi();
}
midi_handler::midi_handler(MIDIBlockHeader* block,
voice_manager& vm,
MIDISound& sound,
s32 vol,
s32 pan,
locator& loc,
SoundBank& bank,
std::optional<ame_handler*> parent)
MidiHandler::MidiHandler(Midi* block,
VoiceManager& vm,
MusicBank::MIDISound& sound,
s32 vol,
s32 pan,
SoundBank& bank,
std::optional<AmeHandler*> parent)
: m_parent(parent),
m_sound(sound),
m_locator(loc),
m_vol(vol),
m_pan(pan),
m_repeats(sound.Repeats),
m_bank(bank),
m_header(block),
m_vm(vm) {
init_midi();
InitMidi();
}
void midi_handler::init_midi() {
m_seq_data_start = (u8*)((uintptr_t)m_header + (uintptr_t)m_header->DataStart);
void MidiHandler::InitMidi() {
m_seq_data_start = m_header->DataStart;
m_seq_ptr = m_seq_data_start;
m_tempo = m_header->Tempo;
m_ppq = m_header->PPQ;
@@ -82,7 +74,7 @@ void midi_handler::init_midi() {
m_chanpan.fill(0);
}
std::pair<size_t, u32> midi_handler::read_vlq(u8* value) {
std::pair<size_t, u32> MidiHandler::ReadVLQ(u8* value) {
size_t len = 1;
u32 out = *value & 0x7f;
// fmt::print("starting with {:x}\n", *value);
@@ -98,7 +90,7 @@ std::pair<size_t, u32> midi_handler::read_vlq(u8* value) {
return {len, out};
}
void midi_handler::pause() {
void MidiHandler::Pause() {
m_paused = true;
for (auto& p : m_voices) {
@@ -107,11 +99,11 @@ void midi_handler::pause() {
continue;
}
m_vm.pause(voice);
m_vm.Pause(voice);
}
}
void midi_handler::unpause() {
void MidiHandler::Unpause() {
m_paused = false;
for (auto& p : m_voices) {
@@ -120,11 +112,11 @@ void midi_handler::unpause() {
continue;
}
m_vm.unpause(voice);
m_vm.Unpause(voice);
}
}
void midi_handler::stop() {
void MidiHandler::Stop() {
m_track_complete = true;
for (auto& p : m_voices) {
@@ -133,11 +125,11 @@ void midi_handler::stop() {
continue;
}
voice->key_off();
voice->KeyOff();
}
}
void midi_handler::set_vol_pan(s32 vol, s32 pan) {
void MidiHandler::SetVolPan(s32 vol, s32 pan) {
if (vol != VOLUME_DONT_CHANGE) {
if (vol >= 0) {
m_vol = (m_sound.Vol * vol) >> 10;
@@ -170,16 +162,16 @@ void midi_handler::set_vol_pan(s32 vol, s32 pan) {
}
voice->basevol =
m_vm.make_volume_b(m_vol, voice->velocity * m_chanvol[voice->channel] / 127, pan,
voice->prog.Vol, voice->prog.Pan, voice->tone.Vol, voice->tone.Pan);
m_vm.MakeVolumeB(m_vol, voice->velocity * m_chanvol[voice->channel] / 127, pan,
voice->prog.Vol, voice->prog.Pan, voice->tone.Vol, voice->tone.Pan);
auto left = m_vm.adjust_vol_to_group(voice->basevol.left, voice->group);
auto right = m_vm.adjust_vol_to_group(voice->basevol.right, voice->group);
voice->set_volume(left >> 1, right >> 1);
auto left = m_vm.AdjustVolToGroup(voice->basevol.left, voice->group);
auto right = m_vm.AdjustVolToGroup(voice->basevol.right, voice->group);
voice->SetVolume(left >> 1, right >> 1);
}
}
void midi_handler::set_pmod(s32 mod) {
void MidiHandler::SetPMod(s32 mod) {
m_cur_pm = mod;
for (auto& v : m_voices) {
@@ -189,31 +181,31 @@ void midi_handler::set_pmod(s32 mod) {
}
voice->current_pm = m_cur_pm;
auto note = pitchbend(voice->tone, voice->current_pb, voice->current_pm, voice->start_note,
auto note = PitchBend(voice->tone, voice->current_pb, voice->current_pm, voice->start_note,
voice->start_fine);
auto pitch =
PS1Note2Pitch(voice->tone.CenterNote, voice->tone.CenterFine, note.first, note.second);
voice->set_pitch(pitch);
voice->SetPitch(pitch);
}
}
void midi_handler::mute_channel(u8 channel) {
void MidiHandler::MuteChannel(u8 channel) {
// fmt::print("{:x} ame muting channel {}\n", (u64)this, channel);
m_mute_state[channel] = true;
}
void midi_handler::unmute_channel(u8 channel) {
void MidiHandler::UnmuteChannel(u8 channel) {
// fmt::print("{:x} ame unmuting channel {}\n", (u64)this, channel);
m_mute_state[channel] = false;
}
void midi_handler::note_on() {
void MidiHandler::NoteOn() {
u8 channel = m_status & 0xf;
u8 note = m_seq_ptr[0];
u8 velocity = m_seq_ptr[1];
if (velocity == 0) {
note_off();
NoteOff();
return;
}
@@ -226,19 +218,21 @@ void midi_handler::note_on() {
// velocity);
// Key on all the applicable tones for the program
auto bank = dynamic_cast<MusicBank*>(m_locator.get_bank_by_id(m_header->BankID));
auto& program = bank->m_programs[m_programs[channel]];
// FIXME bank from midi
// auto bank = dynamic_cast<MusicBank*>(m_locator.get_bank_by_id(m_header->BankID));
auto bank = static_cast<MusicBank*>(&m_bank);
auto& program = bank->Progs[m_programs[channel]];
for (auto& t : program.tones) {
for (auto& t : program.Tones) {
if (note >= t.MapLow && note <= t.MapHigh) {
s16 pan = m_chanpan[channel] + m_pan;
if (pan >= 360) {
pan -= 360;
}
auto voice = std::make_shared<midi_voice>(t, program.d);
voice->basevol = m_vm.make_volume_b(m_vol, (velocity * m_chanvol[channel]) / 0x7f, pan,
program.d.Vol, program.d.Pan, t.Vol, t.Pan);
auto voice = std::make_shared<midi_voice>(t, program);
voice->basevol = m_vm.MakeVolumeB(m_vol, (velocity * m_chanvol[channel]) / 0x7f, pan,
program.Vol, program.Pan, t.Vol, t.Pan);
voice->note = note;
voice->channel = channel;
@@ -251,7 +245,7 @@ void midi_handler::note_on() {
voice->current_pb = m_cur_pm;
voice->group = m_sound.VolGroup;
m_vm.start_tone(voice, m_bank.bank_id);
m_vm.StartTone(voice);
m_voices.emplace_front(voice);
}
}
@@ -259,7 +253,7 @@ void midi_handler::note_on() {
m_seq_ptr += 2;
}
void midi_handler::note_off() {
void MidiHandler::NoteOff() {
u8 channel = m_status & 0xf;
u8 note = m_seq_ptr[0];
// Yep, no velocity for note-offs
@@ -275,14 +269,14 @@ void midi_handler::note_off() {
}
if (voice->channel == channel && voice->note == note) {
voice->key_off();
voice->KeyOff();
}
}
m_seq_ptr += 2;
}
void midi_handler::program_change() {
void MidiHandler::ProgramChange() {
u8 channel = m_status & 0xf;
u8 program = m_seq_ptr[0];
@@ -293,7 +287,7 @@ void midi_handler::program_change() {
m_seq_ptr += 1;
}
void midi_handler::channel_pressure() {
void MidiHandler::ChannelPressure() {
u8 channel = m_status & 0xf;
u8 note = m_seq_ptr[0];
// fmt::print("{}: channel pressure {:02x} {:02x}\n", m_time, m_status, m_seq_ptr[0]);
@@ -305,14 +299,14 @@ void midi_handler::channel_pressure() {
}
if (voice->channel == channel && voice->note == note) {
voice->key_off();
voice->KeyOff();
}
}
m_seq_ptr += 1;
}
void midi_handler::channel_pitch() {
void MidiHandler::ChannelPitch() {
u8 channel = m_status & 0xF;
s32 pitch = 0xFFFF * ((m_seq_ptr[0] & 0x7f) | ((m_seq_ptr[1] & 0x7f) << 7)) / 0x3FFF;
// lg::debug("{}: pitch ch{:01x} {:04x}", m_time, channel, pitch);
@@ -326,18 +320,18 @@ void midi_handler::channel_pitch() {
if (voice->channel == channel) {
voice->current_pb = m_pitch_bend[channel];
auto note = pitchbend(voice->tone, voice->current_pb, voice->current_pm, voice->start_note,
auto note = PitchBend(voice->tone, voice->current_pb, voice->current_pm, voice->start_note,
voice->start_fine);
auto pitch =
PS1Note2Pitch(voice->tone.CenterNote, voice->tone.CenterFine, note.first, note.second);
voice->set_pitch(pitch);
voice->SetPitch(pitch);
}
}
m_seq_ptr += 2;
}
void midi_handler::meta_event() {
void MidiHandler::MetaEvent() {
// fmt::print("{}: meta event {:02x}\n", m_time, *m_seq_ptr);
size_t len = m_seq_ptr[1];
@@ -373,7 +367,7 @@ static s16 midiTo360Pan(u8 pan) {
}
}
void midi_handler::controller_change() {
void MidiHandler::ControllerChange() {
u8 channel = m_status & 0xf;
u8 controller = m_seq_ptr[0];
u8 value = m_seq_ptr[1];
@@ -388,21 +382,21 @@ void midi_handler::controller_change() {
} break;
// case 0x40: {} break; // TODO damper
default:
throw midi_error(fmt::format("invalid midi controller change {}", controller));
throw MidiError(fmt::format("invalid midi controller change {}", controller));
break;
}
m_seq_ptr += 2;
}
void midi_handler::system_event() {
void MidiHandler::SystemEvent() {
// fmt::print("{}: system event {:02x}\n", m_time, *m_seq_ptr);
switch (*m_seq_ptr) {
case 0x75:
m_seq_ptr++;
if (m_parent.has_value()) {
auto [cont, ptr] = m_parent.value()->run_ame(*this, m_seq_ptr);
auto [cont, ptr] = m_parent.value()->RunAME(*this, m_seq_ptr);
m_seq_ptr = ptr;
if (!cont) {
@@ -410,23 +404,23 @@ void midi_handler::system_event() {
m_track_complete = true;
}
} else {
throw midi_error("MIDI tried to run AME without an AME handler");
throw MidiError("MIDI tried to run AME without an AME handler");
}
break;
default:
throw midi_error(fmt::format("Unknown system message {:02x}", *m_seq_ptr));
throw MidiError(fmt::format("Unknown system message {:02x}", *m_seq_ptr));
}
}
bool midi_handler::tick() {
bool MidiHandler::Tick() {
if (m_paused) {
return m_track_complete;
}
try {
m_voices.remove_if([](auto& v) { return v.expired(); });
step();
} catch (midi_error& e) {
Step();
} catch (MidiError& e) {
m_track_complete = true;
lg::error("MIDI Error: {}", e.what());
fmt::print("Sequence following: ");
@@ -439,8 +433,8 @@ bool midi_handler::tick() {
return m_track_complete;
}
void midi_handler::new_delta() {
auto [len, delta] = read_vlq(m_seq_ptr);
void MidiHandler::NewDelta() {
auto [len, delta] = ReadVLQ(m_seq_ptr);
m_seq_ptr += len;
m_time += delta;
@@ -457,9 +451,9 @@ void midi_handler::new_delta() {
}
}
void midi_handler::step() {
void MidiHandler::Step() {
if (m_get_delta) {
new_delta();
NewDelta();
m_get_delta = false;
} else {
m_tick_countdown--;
@@ -474,40 +468,40 @@ void midi_handler::step() {
switch (m_status >> 4) {
case 0x8:
note_off();
NoteOff();
break;
case 0x9:
note_on();
NoteOn();
break;
case 0xB:
controller_change();
ControllerChange();
break;
case 0xD:
channel_pressure();
ChannelPressure();
break;
case 0xC:
program_change();
ProgramChange();
break;
case 0xE:
channel_pitch();
ChannelPitch();
break;
case 0xF:
// normal meta-event
if (m_status == 0xFF) {
meta_event();
MetaEvent();
break;
}
if (m_status == 0xF0) {
system_event();
SystemEvent();
break;
}
[[fallthrough]];
default:
throw midi_error(fmt::format("invalid status {}", m_status));
throw MidiError(fmt::format("invalid status {}", m_status));
return;
}
new_delta();
NewDelta();
}
}
+52 -67
View File
@@ -9,7 +9,7 @@
#include <utility>
#include "ame_handler.h"
#include "loader.h"
#include "musicbank.h"
#include "sound_handler.h"
#include "vagvoice.h"
@@ -17,87 +17,72 @@
namespace snd {
struct ProgData {
/* 0 */ s8 NumTones;
/* 1 */ s8 Vol;
/* 2 */ s16 Pan;
/* 4 */ /*Tone**/ u32 FirstTone;
};
struct Prog {
ProgData d;
std::vector<Tone> tones;
};
class midi_voice : public vag_voice {
class midi_voice : public VagVoice {
public:
midi_voice(Tone& t, ProgData& prog) : vag_voice(t), prog(prog) {}
midi_voice(Tone& t, MusicBank::Prog& _prog) : VagVoice(t), prog(_prog) {}
u8 note{0};
u8 channel{0};
u8 velocity{0};
ProgData& prog;
MusicBank::Prog& prog;
};
class ame_handler;
class midi_handler : public sound_handler {
class AmeHandler;
class MidiHandler : public SoundHandler {
public:
midi_handler(MIDIBlockHeader* block,
voice_manager& vm,
MIDISound& sound,
s32 vol,
s32 pan,
locator& loc,
SoundBank& bank);
MidiHandler(Midi* block,
VoiceManager& vm,
MusicBank::MIDISound& sound,
s32 vol,
s32 pan,
SoundBank& bank);
midi_handler(MIDIBlockHeader* block,
voice_manager& vm,
MIDISound& sound,
s32 vol,
s32 pan,
locator& loc,
SoundBank& bank,
std::optional<ame_handler*> parent);
MidiHandler(Midi* block,
VoiceManager& vm,
MusicBank::MIDISound& sound,
s32 vol,
s32 pan,
SoundBank& bank,
std::optional<AmeHandler*> parent);
~midi_handler() override {
~MidiHandler() override {
for (auto& p : m_voices) {
auto v = p.lock();
if (v != nullptr) {
v->stop();
v->Stop();
}
}
}
void init_midi();
void start();
bool tick() override;
void mute_channel(u8 channel);
void unmute_channel(u8 channel);
SoundBank& bank() override { return m_bank; };
void InitMidi();
void Start();
bool Tick() override;
void MuteChannel(u8 channel);
void UnmuteChannel(u8 channel);
SoundBank& Bank() override { return m_bank; };
void pause() override;
void stop() override;
void unpause() override;
u8 group() override { return m_sound.VolGroup; }
void set_vol_pan(s32 vol, s32 pan) override;
void Pause() override;
void Stop() override;
void Unpause() override;
u8 Group() override { return m_sound.VolGroup; }
void SetVolPan(s32 vol, s32 pan) override;
bool complete() { return m_track_complete; };
void set_pmod(s32 mod) override;
bool Complete() { return m_track_complete; };
void SetPMod(s32 mod) override;
private:
static constexpr int tickrate = 240;
static constexpr int mics_per_tick = 1000000 / tickrate;
struct midi_error : public std::exception {
midi_error(std::string text) : msg(std::move(text)) {}
midi_error() : msg("Unknown MIDI error") {}
struct MidiError : public std::exception {
MidiError(std::string text) : msg(std::move(text)) {}
MidiError() : msg("Unknown MIDI error") {}
std::string msg;
const char* what() const noexcept override { return msg.c_str(); }
};
std::optional<ame_handler*> m_parent;
std::optional<AmeHandler*> m_parent;
std::list<std::weak_ptr<midi_voice>> m_voices;
MIDISound& m_sound;
locator& m_locator;
MusicBank::MIDISound& m_sound;
s32 m_vol{0x7f};
s32 m_pan{0};
s32 m_cur_pm{0};
@@ -106,7 +91,7 @@ class midi_handler : public sound_handler {
bool m_paused{false};
MIDIBlockHeader* m_header{nullptr};
Midi* m_header{nullptr};
std::array<bool, 16> m_mute_state{};
std::array<s8, 16> m_chanvol{};
@@ -130,20 +115,20 @@ class midi_handler : public sound_handler {
std::array<u8, 16> m_programs{};
voice_manager& m_vm;
VoiceManager& m_vm;
void step();
void new_delta();
void Step();
void NewDelta();
void note_on();
void note_off();
void controller_change();
void channel_pressure();
void program_change();
void meta_event();
void system_event();
void channel_pitch();
void NoteOn();
void NoteOff();
void ControllerChange();
void ChannelPressure();
void ProgramChange();
void MetaEvent();
void SystemEvent();
void ChannelPitch();
static std::pair<size_t, u32> read_vlq(u8* value);
static std::pair<size_t, u32> ReadVLQ(u8* value);
};
} // namespace snd
+27 -43
View File
@@ -3,50 +3,34 @@
#include "ame_handler.h"
#include "midi_handler.h"
#include "../common/synth.h"
#include "common/log/log.h"
namespace snd {
MusicBank::MusicBank(locator& loc, u32 id, BankTag* tag)
: SoundBank(id, BankType::Music), m_locator(loc) {
auto data = (SoundBankData*)tag;
std::optional<std::unique_ptr<SoundHandler>> MusicBank::MakeHandler(VoiceManager& vm,
u32 sound_id,
s32 vol,
s32 pan,
s32 pm,
s32 pb) {
auto& sound = Sounds[sound_id];
auto sound = (MIDISound*)((uintptr_t)data + data->FirstSound);
for (int i = 0; i < data->NumSounds; i++) {
m_sounds.emplace_back(sound[i]);
}
// FIXME: global midi list
// search only local bank for now
// (always the case in jak games anyway)
auto progdata = (ProgData*)((uintptr_t)data + data->FirstProg);
for (int i = 0; i < data->NumProgs; i++) {
Prog prog;
prog.d = progdata[i];
m_programs.emplace_back(std::move(prog));
}
for (auto& prog : m_programs) {
auto tonedata = (Tone*)((uintptr_t)data + prog.d.FirstTone);
for (int i = 0; i < prog.d.NumTones; i++) {
prog.tones.emplace_back(tonedata[i]);
if (sound.Type == 4) {
auto& midi = std::get<Midi>(MidiData);
if (sound.MIDIID == midi.ID) {
return std::make_unique<MidiHandler>(&midi, vm, sound, vol, pan, *this);
}
}
bank_name = data->BankID;
}
std::optional<std::unique_ptr<sound_handler>> MusicBank::make_handler(voice_manager& vm,
u32 sound_id,
s32 vol,
s32 pan,
s32 pm,
s32 pb) {
auto& sound = m_sounds[sound_id];
if (sound.Type == 4) { // midi
auto midi = static_cast<MIDIBlockHeader*>(m_locator.get_midi(sound.MIDIID));
return std::make_unique<midi_handler>(midi, vm, sound, vol, pan, m_locator, *this);
} else if (sound.Type == 5) { // ame
auto midi = static_cast<MultiMIDIBlockHeader*>(m_locator.get_midi(sound.MIDIID));
return std::make_unique<ame_handler>(midi, vm, sound, vol, pan, m_locator, *this);
return std::nullopt;
} else if (sound.Type == 5) {
auto& midi = std::get<MultiMidi>(MidiData);
if (sound.MIDIID == midi.ID) {
return std::make_unique<AmeHandler>(&midi, vm, sound, vol, pan, *this);
}
return std::nullopt;
} else {
lg::error("Invalid music sound type");
return std::nullopt;
@@ -54,11 +38,11 @@ std::optional<std::unique_ptr<sound_handler>> MusicBank::make_handler(voice_mana
}
}
std::optional<std::unique_ptr<sound_handler>> MusicBank::make_handler(voice_manager& vm,
u32 sound_id,
s32 vol,
s32 pan,
SndPlayParams& params) {
std::optional<std::unique_ptr<SoundHandler>> MusicBank::MakeHandler(VoiceManager& vm,
u32 sound_id,
s32 vol,
s32 pan,
SndPlayParams& params) {
return std::nullopt;
}
+64 -69
View File
@@ -1,88 +1,83 @@
#pragma once
#include <variant>
#include <vector>
#include "soundbank.h"
#include "third-party/span.hpp"
namespace snd {
struct SoundBankData : BankTag {
/* 10 */ s8 BankNum;
/* 11 */ s8 pad1;
/* 12 */ s16 pad2;
/* 14 */ s16 NumSounds;
/* 16 */ s16 NumProgs;
/* 18 */ s16 NumTones;
/* 1a */ s16 NumVAGs;
/* 1c */ /*Sound**/ u32 FirstSound;
/* 20 */ /*Prog**/ u32 FirstProg;
/* 24 */ /*Tone**/ u32 FirstTone;
/* 28 */ /*void**/ u32 VagsInSR;
/* 2c */ u32 VagDataSize;
/* 30 */ /*SoundBank**/ u32 NextBank;
struct Midi {
u32 DataID;
s16 Version;
s8 Flags;
u32 ID;
u32 BankID;
u8* DataStart;
u32 Tempo;
s32 PPQ;
};
struct MIDIBlock {
/* 0 */ u32 DataID;
/* 4 */ s16 Version;
/* 6 */ s8 Flags;
/* 7 */ s8 NumMIDIBlocks;
/* 8 */ u32 ID;
struct MidiSegment : Midi {
// For MultiMidi data where the sound handler struct is baked into the
// file, we need to know the handler type to determine if we should
// play the segment. For unknown reasons the files contain segments
// that have invalid/unknown handler types that should not be played as midi.
u32 SoundHandle;
};
struct MIDIBlockHeader : MIDIBlock {
/* c */ /*void**/ u32 NextMIDIBlock;
/* 10 */ u32 BankID;
/* 14 */ /*SoundBank**/ u32 BankPtr;
/* 18 */ /*s8**/ u32 DataStart;
/* 1c */ /*s8**/ u32 MultiMIDIParent;
/* 20 */ u32 Tempo;
/* 24 */ u32 PPQ;
struct MultiMidi {
u32 DataID;
u32 Version;
s8 Flags;
u32 ID;
std::vector<MidiSegment> midi;
};
struct MultiMIDIBlockHeader : MIDIBlock {
/* c */ /*void**/ u32 NextMIDIBlock;
/* 10 */ /*s8**/ u32 BlockPtr[0];
};
struct MIDISound {
/* 0 */ s32 Type;
/* 4 */ /*SoundBank**/ u32 Bank;
/* 8 */ /*void**/ u32 OrigBank;
/* c */ u32 MIDIID;
/* 10 */ s16 Vol;
/* 12 */ s8 Repeats;
/* 13 */ s8 VolGroup;
/* 14 */ s16 Pan;
/* 16 */ s8 Index;
/* 17 */ s8 Flags;
/* 18 */ /*void**/ u32 MIDIBlock;
};
// Annoyingly enough we need some data out of this struct
struct MIDISoundHandler {
u32 OwnerID;
};
struct Prog;
class MusicBank : public SoundBank {
public:
MusicBank(locator& loc, u32 id, BankTag* tag);
std::optional<std::unique_ptr<sound_handler>> make_handler(voice_manager& vm,
u32 sound_id,
s32 vol,
s32 pan,
s32 pm,
s32 pb) override;
struct MIDISound { // 0x1c
s32 Type;
SoundBank* Bank;
void* OrigBank;
u32 MIDIID;
s16 Vol;
s8 Repeats;
s8 VolGroup;
s16 Pan;
s8 Index;
u8 Flags;
};
std::optional<std::unique_ptr<sound_handler>> make_handler(voice_manager& vm,
u32 sound_id,
s32 vol,
s32 pan,
SndPlayParams& params) override;
struct Prog {
s8 Vol;
s16 Pan;
std::vector<Tone> Tones;
};
std::vector<Prog> m_programs;
std::vector<MIDISound> m_sounds;
std::vector<MIDISound> Sounds;
std::vector<Prog> Progs;
std::unique_ptr<u8[]> SampleData;
std::unique_ptr<u8[]> SeqData;
std::variant<Midi, MultiMidi> MidiData;
private:
locator& m_locator;
static MusicBank* ReadBank(nonstd::span<u8> bank_data,
nonstd::span<u8> samples,
nonstd::span<u8> midi_data);
std::optional<std::unique_ptr<SoundHandler>> MakeHandler(VoiceManager& vm,
u32 sound_id,
s32 vol,
s32 pan,
s32 pm,
s32 pb) override;
std::optional<std::unique_ptr<SoundHandler>> MakeHandler(VoiceManager& vm,
u32 sound_id,
s32 vol,
s32 pan,
SndPlayParams& params) override;
};
} // namespace snd
+132 -129
View File
@@ -4,9 +4,12 @@
#include <fstream>
#include "sfxblock.h"
#include "third-party/fmt/core.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <combaseapi.h>
#include <windows.h>
#endif
@@ -16,15 +19,15 @@ namespace snd {
u8 g_global_excite = 0;
player::player() : m_vmanager(m_synth, m_loader) {
init_cubeb();
Player::Player() : mVmanager(mSynth) {
InitCubeb();
}
player::~player() {
destroy_cubeb();
Player::~Player() {
DestroyCubeb();
}
void player::init_cubeb() {
void Player::InitCubeb() {
#ifdef _WIN32
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
m_coinitialized = SUCCEEDED(hr);
@@ -35,7 +38,7 @@ void player::init_cubeb() {
}
#endif
cubeb_init(&m_ctx, "OpenGOAL", nullptr);
cubeb_init(&mCtx, "OpenGOAL", nullptr);
cubeb_stream_params outparam = {};
outparam.channels = 2;
@@ -46,30 +49,30 @@ void player::init_cubeb() {
s32 err = 0;
u32 latency = 0;
err = cubeb_get_min_latency(m_ctx, &outparam, &latency);
err = cubeb_get_min_latency(mCtx, &outparam, &latency);
if (err != CUBEB_OK) {
lg::error("Cubeb init failed");
return;
}
err = cubeb_stream_init(m_ctx, &m_stream, "OpenGOAL", nullptr, nullptr, nullptr, &outparam,
latency, &sound_callback, &state_callback, this);
err = cubeb_stream_init(mCtx, &mStream, "OpenGOAL", nullptr, nullptr, nullptr, &outparam, latency,
&sound_callback, &state_callback, this);
if (err != CUBEB_OK) {
lg::error("Cubeb init failed");
return;
}
err = cubeb_stream_start(m_stream);
err = cubeb_stream_start(mStream);
if (err != CUBEB_OK) {
lg::error("Cubeb init failed");
return;
}
}
void player::destroy_cubeb() {
cubeb_stream_stop(m_stream);
cubeb_stream_destroy(m_stream);
cubeb_destroy(m_ctx);
void Player::DestroyCubeb() {
cubeb_stream_stop(mStream);
cubeb_stream_destroy(mStream);
cubeb_destroy(mCtx);
#ifdef _WIN32
if (m_coinitialized) {
CoUninitialize();
@@ -78,34 +81,35 @@ void player::destroy_cubeb() {
#endif
}
long player::sound_callback([[maybe_unused]] cubeb_stream* stream,
long Player::sound_callback([[maybe_unused]] cubeb_stream* stream,
void* user,
[[maybe_unused]] const void* input,
void* output_buffer,
long nframes) {
((player*)user)->tick((s16_output*)output_buffer, nframes);
((Player*)user)->Tick((s16Output*)output_buffer, nframes);
return nframes;
}
void player::state_callback([[maybe_unused]] cubeb_stream* stream,
void Player::state_callback([[maybe_unused]] cubeb_stream* stream,
[[maybe_unused]] void* user,
[[maybe_unused]] cubeb_state state) {}
void player::tick(s16_output* stream, int samples) {
std::scoped_lock lock(m_ticklock);
m_tick++;
void Player::Tick(s16Output* stream, int samples) {
std::scoped_lock lock(mTickLock);
static int htick = 200;
static int stick = 48000;
for (int i = 0; i < samples; i++) {
// The handlers expect to tick at 240hz
// 48000/240 = 200
if (htick == 200) {
for (auto it = m_handlers.begin(); it != m_handlers.end();) {
bool done = it->second->tick();
mTick++;
for (auto it = mHandlers.begin(); it != mHandlers.end();) {
bool done = it->second->Tick();
if (done) {
// fmt::print("erasing handler\n");
m_handle_allocator.free_id(it->first);
it = m_handlers.erase(it);
mHandleAllocator.FreeId(it->first);
it = mHandlers.erase(it);
} else {
++it;
}
@@ -121,45 +125,45 @@ void player::tick(s16_output* stream, int samples) {
stick++;
htick++;
*stream++ = m_synth.tick();
*stream++ = mSynth.Tick();
}
}
u32 player::play_sound(u32 bank_id, u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb) {
std::scoped_lock lock(m_ticklock);
auto bank = m_loader.get_bank_by_handle(bank_id);
u32 Player::PlaySound(BankHandle bank_id, u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb) {
std::scoped_lock lock(mTickLock);
auto bank = mLoader.GetBankByHandle(bank_id);
if (bank == nullptr) {
lg::error("play_sound: Bank {} does not exist", bank_id);
lg::error("play_sound: Bank {} does not exist", static_cast<void*>(bank_id));
return 0;
}
auto handler = bank->make_handler(m_vmanager, sound_id, vol, pan, pm, pb);
auto handler = bank->MakeHandler(mVmanager, sound_id, vol, pan, pm, pb);
if (!handler.has_value()) {
return 0;
}
u32 handle = m_handle_allocator.get_id();
m_handlers.emplace(handle, std::move(handler.value()));
u32 handle = mHandleAllocator.GetId();
mHandlers.emplace(handle, std::move(handler.value()));
// fmt::print("play_sound {}:{} - {}\n", bank_id, sound_id, handle);
return handle;
}
u32 player::play_sound_by_name(u32 bank_id,
char* bank_name,
char* sound_name,
s32 vol,
s32 pan,
s32 pm,
s32 pb) {
std::scoped_lock lock(m_ticklock);
u32 Player::PlaySoundByName(BankHandle bank_id,
char* bank_name,
char* sound_name,
s32 vol,
s32 pan,
s32 pm,
s32 pb) {
std::scoped_lock lock(mTickLock);
SoundBank* bank = nullptr;
if (bank_id == 0 && bank_name != nullptr) {
bank = m_loader.get_bank_by_name(bank_name);
bank = mLoader.GetBankByName(bank_name);
} else if (bank_id != 0) {
bank = m_loader.get_bank_by_handle(bank_id);
bank = mLoader.GetBankByHandle(bank_id);
} else {
bank = m_loader.get_bank_with_sound(sound_name);
bank = mLoader.GetBankWithSound(sound_name);
}
if (bank == nullptr) {
@@ -167,9 +171,9 @@ u32 player::play_sound_by_name(u32 bank_id,
return 0;
}
auto sound = bank->get_sound_by_name(sound_name);
auto sound = bank->GetSoundByName(sound_name);
if (sound.has_value()) {
return play_sound(bank->bank_id, sound.value(), vol, pan, pm, pb);
return PlaySound(bank, sound.value(), vol, pan, pm, pb);
}
// lg::error("play_sound_by_name: failed to find sound {}", sound_name);
@@ -177,41 +181,41 @@ u32 player::play_sound_by_name(u32 bank_id,
return 0;
}
void player::stop_sound(u32 sound_id) {
std::scoped_lock lock(m_ticklock);
auto handler = m_handlers.find(sound_id);
if (handler == m_handlers.end())
void Player::StopSound(u32 sound_id) {
std::scoped_lock lock(mTickLock);
auto handler = mHandlers.find(sound_id);
if (handler == mHandlers.end())
return;
handler->second->stop();
handler->second->Stop();
// m_handle_allocator.free_id(sound_id);
// m_handlers.erase(sound_id);
}
void player::set_sound_reg(u32 sound_id, u8 reg, u8 value) {
std::scoped_lock lock(m_ticklock);
if (m_handlers.find(sound_id) == m_handlers.end()) {
void Player::SetSoundReg(u32 sound_id, u8 reg, u8 value) {
std::scoped_lock lock(mTickLock);
if (mHandlers.find(sound_id) == mHandlers.end()) {
// fmt::print("set_midi_reg: Handler {} does not exist\n", sound_id);
return;
}
auto* handler = m_handlers.at(sound_id).get();
handler->set_register(reg, value);
auto* handler = mHandlers.at(sound_id).get();
handler->SetRegister(reg, value);
}
bool player::sound_still_active(u32 sound_id) {
std::scoped_lock lock(m_ticklock);
auto handler = m_handlers.find(sound_id);
if (handler == m_handlers.end())
bool Player::SoundStillActive(u32 sound_id) {
std::scoped_lock lock(mTickLock);
auto handler = mHandlers.find(sound_id);
if (handler == mHandlers.end())
return false;
// fmt::print("sound_still_active {}\n", sound_id);
return true;
}
void player::set_master_volume(u32 group, s32 volume) {
std::scoped_lock lock(m_ticklock);
void Player::SetMasterVolume(u32 group, s32 volume) {
std::scoped_lock lock(mTickLock);
if (volume > 0x400)
volume = 0x400;
@@ -221,125 +225,124 @@ void player::set_master_volume(u32 group, s32 volume) {
if (group == 15)
return;
m_vmanager.set_master_vol(group, volume);
mVmanager.SetMasterVol(group, volume);
// Master volume
if (group == 16) {
m_synth.set_master_vol(0x3ffff * volume / 0x400);
mSynth.SetMasterVol(0x3ffff * volume / 0x400);
}
}
u32 player::load_bank(fs::path& filepath, size_t offset) {
std::scoped_lock lock(m_ticklock);
std::fstream in(filepath, std::fstream::binary | std::fstream::in);
in.seekg(offset, std::fstream::beg);
return m_loader.read_bank(in);
BankHandle Player::LoadBank(nonstd::span<u8> bank) {
std::scoped_lock lock(mTickLock);
return mLoader.BankLoad(bank);
}
void player::unload_bank(u32 bank_handle) {
std::scoped_lock lock(m_ticklock);
auto* bank = m_loader.get_bank_by_handle(bank_handle);
void Player::UnloadBank(BankHandle bank_handle) {
std::scoped_lock lock(mTickLock);
auto* bank = mLoader.GetBankByHandle(bank_handle);
if (bank == nullptr)
return;
for (auto it = m_handlers.begin(); it != m_handlers.end();) {
if (it->second->bank().bank_id == bank_handle) {
m_handle_allocator.free_id(it->first);
it = m_handlers.erase(it);
for (auto it = mHandlers.begin(); it != mHandlers.end();) {
if (&it->second->Bank() == bank_handle) {
mHandleAllocator.FreeId(it->first);
it = mHandlers.erase(it);
} else {
++it;
}
}
m_loader.unload_bank(bank_handle);
mLoader.UnloadBank(bank_handle);
}
void player::set_pan_table(vol_pair* pantable) {
std::scoped_lock lock(m_ticklock);
m_vmanager.set_pan_table(pantable);
void Player::SetPanTable(VolPair* pantable) {
std::scoped_lock lock(mTickLock);
mVmanager.SetPanTable(pantable);
}
void player::set_playback_mode(s32 mode) {
std::scoped_lock lock(m_ticklock);
m_vmanager.set_playback_mode(mode);
void Player::SetPlaybackMode(s32 mode) {
std::scoped_lock lock(mTickLock);
mVmanager.SetPlaybackMode(mode);
}
void player::pause_sound(s32 sound_id) {
std::scoped_lock lock(m_ticklock);
auto handler = m_handlers.find(sound_id);
if (handler == m_handlers.end())
void Player::PauseSound(s32 sound_id) {
std::scoped_lock lock(mTickLock);
auto handler = mHandlers.find(sound_id);
if (handler == mHandlers.end())
return;
handler->second->pause();
handler->second->Pause();
}
void player::continue_sound(s32 sound_id) {
std::scoped_lock lock(m_ticklock);
auto handler = m_handlers.find(sound_id);
if (handler == m_handlers.end())
void Player::ContinueSound(s32 sound_id) {
std::scoped_lock lock(mTickLock);
auto handler = mHandlers.find(sound_id);
if (handler == mHandlers.end())
return;
handler->second->unpause();
handler->second->Unpause();
}
void player::pause_all_sounds_in_group(u8 group) {
std::scoped_lock lock(m_ticklock);
void Player::PauseAllSoundsInGroup(u8 group) {
std::scoped_lock lock(mTickLock);
for (auto& h : m_handlers) {
if ((1 << h.second->group()) & group) {
h.second->pause();
for (auto& h : mHandlers) {
if ((1 << h.second->Group()) & group) {
h.second->Pause();
}
}
}
void player::continue_all_sounds_in_group(u8 group) {
std::scoped_lock lock(m_ticklock);
void Player::ContinueAllSoundsInGroup(u8 group) {
std::scoped_lock lock(mTickLock);
for (auto& h : m_handlers) {
if ((1 << h.second->group()) & group) {
h.second->unpause();
for (auto& h : mHandlers) {
if ((1 << h.second->Group()) & group) {
h.second->Unpause();
}
}
}
void player::set_sound_vol_pan(s32 sound_id, s32 vol, s32 pan) {
std::scoped_lock lock(m_ticklock);
auto handler = m_handlers.find(sound_id);
if (handler == m_handlers.end())
void Player::SetSoundVolPan(s32 sound_id, s32 vol, s32 pan) {
std::scoped_lock lock(mTickLock);
auto handler = mHandlers.find(sound_id);
if (handler == mHandlers.end())
return;
handler->second->set_vol_pan(vol, pan);
handler->second->SetVolPan(vol, pan);
}
void player::set_sound_pmod(s32 sound_handle, s32 mod) {
auto handler = m_handlers.find(sound_handle);
if (handler == m_handlers.end())
void Player::SetSoundPmod(s32 sound_handle, s32 mod) {
std::scoped_lock lock(mTickLock);
auto handler = mHandlers.find(sound_handle);
if (handler == mHandlers.end())
return;
handler->second->set_pmod(mod);
handler->second->SetPMod(mod);
}
void player::stop_all_sounds() {
for (auto it = m_handlers.begin(); it != m_handlers.end();) {
m_handle_allocator.free_id(it->first);
it = m_handlers.erase(it);
void Player::StopAllSounds() {
std::scoped_lock lock(mTickLock);
for (auto it = mHandlers.begin(); it != mHandlers.end();) {
mHandleAllocator.FreeId(it->first);
it = mHandlers.erase(it);
}
}
s32 player::get_sound_user_data(s32 block_handle,
char* block_name,
s32 sound_id,
char* sound_name,
SFXUserData* dst) {
std::scoped_lock lock(m_ticklock);
s32 Player::GetSoundUserData(BankHandle block_handle,
char* block_name,
s32 sound_id,
char* sound_name,
SFXUserData* dst) {
std::scoped_lock lock(mTickLock);
SoundBank* bank = nullptr;
if (block_handle == 0 && block_name != nullptr) {
bank = m_loader.get_bank_by_name(block_name);
} else if (block_handle != 0) {
bank = m_loader.get_bank_by_handle(block_handle);
if (block_handle == nullptr && block_name != nullptr) {
bank = mLoader.GetBankByName(block_name);
} else if (block_handle != nullptr) {
bank = mLoader.GetBankByHandle(block_handle);
} else {
bank = m_loader.get_bank_with_sound(sound_name);
bank = mLoader.GetBankWithSound(sound_name);
}
if (bank == nullptr) {
@@ -347,7 +350,7 @@ s32 player::get_sound_user_data(s32 block_handle,
}
if (sound_id == -1) {
auto sound = bank->get_sound_by_name(sound_name);
auto sound = bank->GetSoundByName(sound_name);
if (sound.has_value()) {
sound_id = sound.value();
} else {
@@ -355,7 +358,7 @@ s32 player::get_sound_user_data(s32 block_handle,
}
}
auto ud = bank->get_sound_user_data(sound_id);
auto ud = bank->GetSoundUserData(sound_id);
if (ud.has_value()) {
dst->data[0] = ud.value()->data[0];
dst->data[1] = ud.value()->data[1];
+49 -50
View File
@@ -10,82 +10,81 @@
#include "ame_handler.h"
#include "handle_allocator.h"
#include "loader.h"
#include "midi_handler.h"
#include "sound_handler.h"
#include "common/common_types.h"
#include "common/util/FileUtil.h"
#include "../common/synth.h"
#include "game/sound/989snd/vagvoice.h"
#include "third-party/cubeb/cubeb/include/cubeb/cubeb.h"
#include "third-party/span.hpp"
namespace snd {
class player {
class Player {
public:
player();
~player();
player(const player&) = delete;
player operator=(const player&) = delete;
Player();
~Player();
Player(const Player&) = delete;
Player operator=(const Player&) = delete;
// player(player&& other) noexcept = default;
// player& operator=(player&& other) noexcept = default;
u32 load_bank(fs::path& path, size_t offset);
BankHandle LoadBank(nonstd::span<u8> bank);
u32 play_sound(u32 bank, u32 sound, s32 vol, s32 pan, s32 pm, s32 pb);
u32 play_sound_by_name(u32 bank,
char* bank_name,
char* sound_name,
s32 vol,
s32 pan,
s32 pm,
s32 pb);
void set_sound_reg(u32 sound_id, u8 reg, u8 value);
void set_global_excite(u8 value) { GlobalExcite = value; };
bool sound_still_active(u32 sound_id);
void set_master_volume(u32 group, s32 volume);
void unload_bank(u32 bank_handle);
void stop_sound(u32 sound_handle);
void set_pan_table(vol_pair* pantable);
void set_playback_mode(s32 mode);
void pause_sound(s32 sound_handle);
void continue_sound(s32 sound_handle);
void pause_all_sounds_in_group(u8 group);
void continue_all_sounds_in_group(u8 group);
void set_sound_vol_pan(s32 sound_handle, s32 vol, s32 pan);
void submit_voice(std::shared_ptr<voice>& voice) { m_synth.add_voice(voice); };
void set_sound_pmod(s32 sound_handle, s32 mod);
void init_cubeb();
void destroy_cubeb();
s32 get_tick() { return m_tick; };
void stop_all_sounds();
s32 get_sound_user_data(s32 block_handle,
char* block_name,
s32 sound_id,
char* sound_name,
SFXUserData* dst);
u32 PlaySound(BankHandle bank, u32 sound, s32 vol, s32 pan, s32 pm, s32 pb);
u32 PlaySoundByName(BankHandle bank,
char* bank_name,
char* sound_name,
s32 vol,
s32 pan,
s32 pm,
s32 pb);
void SetSoundReg(u32 sound_id, u8 reg, u8 value);
void SetGlobalExcite(u8 value) { GlobalExcite = value; };
bool SoundStillActive(u32 sound_id);
void SetMasterVolume(u32 group, s32 volume);
void UnloadBank(BankHandle bank_handle);
void StopSound(u32 sound_handle);
void SetPanTable(VolPair* pantable);
void SetPlaybackMode(s32 mode);
void PauseSound(s32 sound_handle);
void ContinueSound(s32 sound_handle);
void PauseAllSoundsInGroup(u8 group);
void ContinueAllSoundsInGroup(u8 group);
void SetSoundVolPan(s32 sound_handle, s32 vol, s32 pan);
void SubmitVoice(std::shared_ptr<Voice>& voice) { mSynth.AddVoice(voice); };
void SetSoundPmod(s32 sound_handle, s32 mod);
void InitCubeb();
void DestroyCubeb();
s32 GetTick() { return mTick; };
void StopAllSounds();
s32 GetSoundUserData(BankHandle block_handle,
char* block_name,
s32 sound_id,
char* sound_name,
SFXUserData* dst);
private:
std::recursive_mutex m_ticklock; // TODO does not need to recursive with some light restructuring
id_allocator m_handle_allocator;
std::unordered_map<u32, std::unique_ptr<sound_handler>> m_handlers;
std::recursive_mutex mTickLock; // TODO does not need to recursive with some light restructuring
IdAllocator mHandleAllocator;
std::unordered_map<u32, std::unique_ptr<SoundHandler>> mHandlers;
void tick(s16_output* stream, int samples);
void Tick(s16Output* stream, int samples);
#ifdef _WIN32
bool m_coinitialized = false;
#endif
loader m_loader;
synth m_synth;
voice_manager m_vmanager;
s32 m_tick{0};
Loader mLoader;
Synth mSynth;
VoiceManager mVmanager;
s32 mTick{0};
cubeb* m_ctx{nullptr};
cubeb_stream* m_stream{nullptr};
cubeb* mCtx{nullptr};
cubeb_stream* mStream{nullptr};
static long sound_callback(cubeb_stream* stream,
void* user,
Loaded 100 of 582 files, more files were not shown because too many files have changed in this diff. Show more