Compare commits

...

10 Commits

Author SHA1 Message Date
Oliver 933bc4ceb0 fix: AudioImportTool NPE when run outside Play mode
Replace AudioExtendSettings.Instance with local AssetDatabase-loaded field to avoid nullref when AudioSystem hasn't yet initialized.
2026-06-05 11:59:25 +08:00
Oliver faba10b33e 更新说明 2026-06-04 19:10:50 +08:00
Oliver 9d34a8b556 增加测试文件,修改buffer size解决淡变时会爆音的问题 2026-05-28 19:50:58 +08:00
Oliver 25919b3f79 Update binary data. 2026-05-26 10:12:29 +08:00
Oliver 0fa6236211 chore: comment out debug log 2026-05-26 10:12:10 +08:00
Oliver a46b450ef0 feat: 音效、音量、触感开关控制 2026-05-22 20:40:35 +08:00
Oliver 5ceffa4d61 closed: streaming support 2026-05-19 12:07:48 +08:00
Oliver 106256cc32 关掉节拍器 2026-05-19 12:07:21 +08:00
Oliver 005af5c2b8 update: Playersettings 2026-05-19 12:07:13 +08:00
Oliver 9dc4228b5c feat: 在Unity内支持直接调整音频文件进行混音 2026-05-19 12:04:31 +08:00
64 changed files with 327 additions and 126 deletions
+19
View File
@@ -170,6 +170,25 @@ SfxSystem manages: throttle (`ThrottleCount`), min interval (`MinInterval`), pri
- `HapticSystem.Instance.Stop(uint? hapticId = null)` — stops current haptic playback - `HapticSystem.Instance.Stop(uint? hapticId = null)` — stops current haptic playback
- Supports four `HapticType`s: `Preset`, `Emphasis`, `Constant`, `Advance` (`.haptic` file) - Supports four `HapticType`s: `Preset`, `Emphasis`, `Constant`, `Advance` (`.haptic` file)
#### Device capability & fallback
`HapticController.Play()` (`Lofelt/.../HapticController.cs:350`) uses a three-tier decision chain:
1. **Advanced device** (`DeviceCapabilities.meetsAdvancedRequirements`) → full `.haptic` playback via `LofeltHaptics`
2. **Gamepad** (`GamepadRumbler.CanPlay()`) → gamepad rumble
3. **Basic OS support** (`DeviceCapabilities.isVersionSupported`) → **always falls back to a Preset**
4. None of above → silent no-op
**Advance (`.haptic` file) fallback is Preset-only** — it never degrades to Emphasis or Constant. The fallback Preset is configured via `HapticObject.FallbackPreset` in the data table.
| HapticType | Advanced | Android basic | iOS basic |
|------------|----------|---------------|-----------|
| **Advance** | Full `.haptic` | → Preset | → Preset |
| **Emphasis** | JSON clip | 50ms max-amplitude pulse | → amplitude-mapped Preset |
| **Constant** | JSON clip with modulation | max-amplitude for `duration` | → hardcoded `HeavyImpact` |
Emphasis and Constant have their own internal fallback chains (template-based JSON clips on advanced, raw motor patterns or Presets on basic), but these are independent direct-invoke paths — they are never used as fallback targets for Advance.
--- ---
## Interactive Music System ## Interactive Music System
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -7,9 +7,9 @@ AudioImporter:
serializedVersion: 2 serializedVersion: 2
loadType: 2 loadType: 2
sampleRateSetting: 2 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 0.13 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 1 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
+2 -2
View File
@@ -7,9 +7,9 @@ AudioImporter:
serializedVersion: 2 serializedVersion: 2
loadType: 2 loadType: 2
sampleRateSetting: 2 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 0.13 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 1 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
+2 -2
View File
@@ -7,9 +7,9 @@ AudioImporter:
serializedVersion: 2 serializedVersion: 2
loadType: 2 loadType: 2
sampleRateSetting: 2 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 0.13 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 1 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
+2 -2
View File
@@ -7,9 +7,9 @@ AudioImporter:
serializedVersion: 2 serializedVersion: 2
loadType: 2 loadType: 2
sampleRateSetting: 2 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 0.13 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 1 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
+7
View File
@@ -249,8 +249,14 @@ AudioMixerController:
m_EnableSuspend: 1 m_EnableSuspend: 1
m_UpdateMode: 0 m_UpdateMode: 0
m_ExposedParameters: m_ExposedParameters:
- guid: d66e5a701962f484baca61ea5f29bab9
name: MusicVolume
- guid: 9b4461d5598de4602b001fc9d34f76a7 - guid: 9b4461d5598de4602b001fc9d34f76a7
name: LowpassFreq name: LowpassFreq
- guid: f9b2498f18d9c4346b50d00374df58fc
name: SFXVolume
- guid: 15cd4cd29b1a64dacb39ca2eda4de378
name: SFXAccentVolume
m_AudioMixerGroupViews: m_AudioMixerGroupViews:
- guids: - guids:
- 3ef0a681afabf403eae42ddfe3bed37e - 3ef0a681afabf403eae42ddfe3bed37e
@@ -319,6 +325,7 @@ AudioMixerSnapshotController:
676d0e59581a446dfb975928b4b3a4ea: 22000 676d0e59581a446dfb975928b4b3a4ea: 22000
0053647b950eb4d8abf883dc07d6b4ef: 1 0053647b950eb4d8abf883dc07d6b4ef: 1
47b8a12e60a1c4cf18d0d0c28f12866d: 440 47b8a12e60a1c4cf18d0d0c28f12866d: 440
f9b2498f18d9c4346b50d00374df58fc: 0
c31161cf8dc3a48478fe71156b990b48: 1333 c31161cf8dc3a48478fe71156b990b48: 1333
d171c8cff3d664001b51b62c1b77ab53: 0 d171c8cff3d664001b51b62c1b77ab53: 0
m_TransitionOverrides: {} m_TransitionOverrides: {}
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -11,7 +11,7 @@ AudioImporter:
compressionFormat: 1 compressionFormat: 1
quality: 0.5 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c5826c32750024cf0a317c781cbd9c49 guid: e1e3771c46788490d96beed6956a6c03
AudioImporter: AudioImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 7 serializedVersion: 7
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 0279ce4eacbbf45d0b332f1996c7715c guid: 49b7f87b4607c4005aa6739e4a777f60
AudioImporter: AudioImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 7 serializedVersion: 7
@@ -6,10 +6,10 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 0
platformSettingOverrides: {} platformSettingOverrides: {}
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,10 +6,10 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 0
platformSettingOverrides: {} platformSettingOverrides: {}
@@ -6,10 +6,10 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 0
platformSettingOverrides: {} platformSettingOverrides: {}
@@ -6,10 +6,10 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 0
platformSettingOverrides: {} platformSettingOverrides: {}
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,10 +6,10 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 0
platformSettingOverrides: {} platformSettingOverrides: {}
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,12 +6,12 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 1
platformSettingOverrides: {} platformSettingOverrides: {}
forceToMono: 0 forceToMono: 0
normalize: 1 normalize: 1
@@ -6,10 +6,10 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 0
platformSettingOverrides: {} platformSettingOverrides: {}
@@ -6,10 +6,10 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 0
platformSettingOverrides: {} platformSettingOverrides: {}
@@ -6,10 +6,10 @@ AudioImporter:
defaultSettings: defaultSettings:
serializedVersion: 2 serializedVersion: 2
loadType: 0 loadType: 0
sampleRateSetting: 0 sampleRateSetting: 2
sampleRateOverride: 44100 sampleRateOverride: 22050
compressionFormat: 1 compressionFormat: 1
quality: 1 quality: 0.5
conversionMode: 0 conversionMode: 0
preloadAudioData: 0 preloadAudioData: 0
platformSettingOverrides: {} platformSettingOverrides: {}
+1 -1
View File
@@ -971,7 +971,7 @@ GameObject:
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 1 m_IsActive: 0
--- !u!114 &660842743 --- !u!114 &660842743
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -0,0 +1,52 @@
using UnityEditor.Build;
using UnityEditor;
using System.IO;
using UnityEditor.Build.Reporting;
using UnityEngine;
namespace OCES.Editor
{
#if false
public class CopyWavesForMixing : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder
{
get { return 0; }
}
static string _audioStreamingPath;
public void OnPreprocessBuild(BuildReport report)
{
const string guid = "de80878c933394e2da0966a1466fd793";
Audio.AudioExtendSettings audioSettings =
AssetDatabase.LoadAssetAtPath<Audio.AudioExtendSettings>(AssetDatabase.GUIDToAssetPath(guid));
string audioPath = Path.Combine("Assets", "Resources",audioSettings.audioResourcePath);
DirectoryInfo directoryInfo = new(audioPath);
_audioStreamingPath = Path.Combine(Application.streamingAssetsPath, "Audios");
if (Directory.Exists(_audioStreamingPath)) Directory.Delete(_audioStreamingPath, true);
Directory.CreateDirectory(_audioStreamingPath);
foreach (FileInfo file in directoryInfo.GetFiles())
{
if (file.Extension is ".wav" or ".mp3")
{
file.CopyTo(Path.Combine(_audioStreamingPath, file.Name), true);
}
}
Debug.Log(_audioStreamingPath);
}
public void OnPostprocessBuild(BuildReport report)
{
if (Directory.Exists(_audioStreamingPath)) Directory.Delete(_audioStreamingPath, true);
}
}
#endif
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e2d7bb1448fb4a7897840c63d350e597
timeCreated: 1779103933
@@ -21,10 +21,13 @@ namespace OCES
[CanBeNull] [CanBeNull]
internal T LoadSync<T>(string path) where T : Object internal T LoadSync<T>(string path) where T : Object
{ {
#if !AUDIO_MIXING
if (this.m_cachedObjects.TryGetValue(path, out Object cachedObject)) if (this.m_cachedObjects.TryGetValue(path, out Object cachedObject))
{ {
return cachedObject as T; return cachedObject as T;
} }
#endif
T newObject; T newObject;
if (this.m_assetProvider is not null) if (this.m_assetProvider is not null)
@@ -37,7 +40,9 @@ namespace OCES
Debug.LogWarning($"[ResourceLoader] No IAssetProvider set, falling back to Resources.Load for '{path}'"); Debug.LogWarning($"[ResourceLoader] No IAssetProvider set, falling back to Resources.Load for '{path}'");
} }
#if !AUDIO_MIXING
this.m_cachedObjects.Add(path, newObject); this.m_cachedObjects.Add(path, newObject);
#endif
return newObject; return newObject;
} }
@@ -23,11 +23,10 @@ namespace OCES
{ {
if (typeof(T) != typeof(AudioClip)) if (typeof(T) != typeof(AudioClip))
{ {
Debug.LogError($"[StreamingAssetProvider] Load<{typeof(T).Name}> 不支持,仅支持 AudioClip"); return Resources.Load<T>(path);
return null;
} }
string fullPath = Path.Combine(Application.streamingAssetsPath, path); string fullPath = Path.Combine("Audios", Application.streamingAssetsPath, path) + ".wav";
if (!File.Exists(fullPath)) if (!File.Exists(fullPath))
{ {
Debug.LogError($"[StreamingAssetProvider] 文件 {fullPath} 不存在。"); Debug.LogError($"[StreamingAssetProvider] 文件 {fullPath} 不存在。");
@@ -48,25 +47,26 @@ namespace OCES
{ {
if (typeof(T) != typeof(AudioClip)) if (typeof(T) != typeof(AudioClip))
{ {
Debug.LogError($"[StreamingAssetProvider] LoadAsync<{typeof(T).Name}> 不支持,仅支持 AudioClip"); ResourceRequest resourceRequest = Resources.LoadAsync<T>(path);
onComplete?.Invoke(null); yield return resourceRequest;
onComplete?.Invoke(resourceRequest.asset as T);
yield break; yield break;
} }
string fullPath = Path.Combine(Application.streamingAssetsPath, path); string fullPath = Path.Combine("Audios", Application.streamingAssetsPath, path);
string url = "file://" + fullPath; string url = "file://" + fullPath;
using UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.WAV); using UnityWebRequest webRequest = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.WAV);
yield return request.SendWebRequest(); yield return webRequest.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success) if (webRequest.result == UnityWebRequest.Result.Success)
{ {
AudioClip clip = DownloadHandlerAudioClip.GetContent(request); AudioClip clip = DownloadHandlerAudioClip.GetContent(webRequest);
onComplete?.Invoke(clip as T); onComplete?.Invoke(clip as T);
} }
else else
{ {
Debug.LogError($"[StreamingAssetProvider] 加载失败: {url}, 错误: {request.error}"); Debug.LogError($"[StreamingAssetProvider] 加载失败: {url}, 错误: {webRequest.error}");
onComplete?.Invoke(null); onComplete?.Invoke(null);
} }
} }
@@ -127,6 +127,27 @@ namespace OCES.Audio
).SetEase(Ease.OutCubic); ).SetEase(Ease.OutCubic);
} }
public void SetMusicVolume(float targetVolume)
{
this.m_mixer.SetFloat("MusicVolume", targetVolume);
}
public void SetSFXVolume(float targetVolume)
{
this.m_mixer.SetFloat("SFXVolume", targetVolume);
this.m_mixer.SetFloat("SFXAccentVolume", targetVolume);
}
public void SetMusicState(bool enable)
{
SetMusicVolume(enable ? 0 : -80);
}
public void SetSFXState(bool enable)
{
SetSFXVolume(enable ? 0 : -80);
}
/// <summary> /// <summary>
/// 更新游戏状态,驱动音乐与环境音系统切换。 /// 更新游戏状态,驱动音乐与环境音系统切换。
/// 调用示例:AudioSystem.Instance.SetState(GameState.Game); /// 调用示例:AudioSystem.Instance.SetState(GameState.Game);
@@ -9,9 +9,26 @@ namespace OCES.Audio
public static class AudioImportTool public static class AudioImportTool
{ {
static AudioExtendSettings s_settings;
static AudioExtendSettings Settings
{
get
{
if (s_settings == null)
{
s_settings = AssetDatabase.LoadAssetAtPath<AudioExtendSettings>(
"Assets/Settings/AudioExtendSettings.asset");
if (s_settings == null)
Debug.LogError("[AudioImportTool] 无法加载 AudioExtendSettings.asset,请确保资产存在于 Assets/Settings/ 目录");
}
return s_settings;
}
}
static string ConfigAbsolutePath static string ConfigAbsolutePath
{ {
get { return Path.Combine(Application.dataPath, "Resources", AudioExtendSettings.Instance.audioConfigPath); } get { return Path.Combine(Application.dataPath, "Resources", Settings.audioConfigPath); }
} }
[MenuItem("Tools/OCES/Audio/Apply Audio Import Settings")] [MenuItem("Tools/OCES/Audio/Apply Audio Import Settings")]
@@ -19,7 +36,7 @@ namespace OCES.Audio
{ {
if (EditorUtility.DisplayDialog( if (EditorUtility.DisplayDialog(
"Apply Audio Import Settings", "Apply Audio Import Settings",
$"将对 {AudioExtendSettings.Instance.FullAudioResourcePath} 下所有文件重新应用导入设置,确认继续?", $"将对 {Settings.FullAudioResourcePath} 下所有文件重新应用导入设置,确认继续?",
"确认", "取消")) "确认", "取消"))
{ {
Run(); Run();
@@ -43,10 +60,10 @@ namespace OCES.Audio
{ {
// 1. 加载配置表 // 1. 加载配置表
var audioObjectConfig = var audioObjectConfig =
AudioConfigLoader.Load<AudioObjectConfig>(AudioExtendSettings.Instance.FullAudioConfigPath, AudioConfigLoader.Load<AudioObjectConfig>(Settings.FullAudioConfigPath,
"AudioObject.bytes"); "AudioObject.bytes");
var musicSegmentConfig = var musicSegmentConfig =
AudioConfigLoader.Load<MusicSegmentConfig>(AudioExtendSettings.Instance.FullAudioConfigPath, AudioConfigLoader.Load<MusicSegmentConfig>(Settings.FullAudioConfigPath,
"MusicSegment.bytes"); "MusicSegment.bytes");
if (audioObjectConfig == null || musicSegmentConfig == null) if (audioObjectConfig == null || musicSegmentConfig == null)
{ {
@@ -56,7 +73,7 @@ namespace OCES.Audio
// 2. 扫描文件 // 2. 扫描文件
List<string> supportedExtensions = new() { ".wav", ".ogg" }; List<string> supportedExtensions = new() { ".wav", ".ogg" };
DirectoryInfo dir = new(AudioExtendSettings.Instance.FullAudioResourcePath); DirectoryInfo dir = new(Settings.FullAudioResourcePath);
FileInfo[] files = dir.GetFiles().Where(f => supportedExtensions.Contains(f.Extension.ToLower())).ToArray(); FileInfo[] files = dir.GetFiles().Where(f => supportedExtensions.Contains(f.Extension.ToLower())).ToArray();
int total = files.Length, processed = 0, failed = 0; int total = files.Length, processed = 0, failed = 0;
@@ -116,20 +133,20 @@ namespace OCES.Audio
importer.ClearSampleSettingOverride("iOS"); importer.ClearSampleSettingOverride("iOS");
AudioImporterSampleSettings settings = importer.defaultSampleSettings; AudioImporterSampleSettings settings = importer.defaultSampleSettings;
settings.compressionFormat = AudioExtendSettings.Instance.compressionFormat; settings.compressionFormat = Settings.compressionFormat;
settings.sampleRateSetting = AudioSampleRateSetting.OverrideSampleRate; settings.sampleRateSetting = AudioSampleRateSetting.OverrideSampleRate;
settings.preloadAudioData = audioObject?.Haptic != 0; settings.preloadAudioData = audioObject?.Haptic != 0;
switch (category) switch (category)
{ {
case AudioCategory.Music: case AudioCategory.Music:
settings.sampleRateOverride = AudioExtendSettings.Instance.musicSampleRate; settings.sampleRateOverride = Settings.musicSampleRate;
settings.quality = AudioExtendSettings.Instance.musicQuality; settings.quality = Settings.musicQuality;
if (duration <= AudioExtendSettings.Instance.decompressThreshold) if (duration <= Settings.decompressThreshold)
{ {
settings.loadType = AudioClipLoadType.DecompressOnLoad; settings.loadType = AudioClipLoadType.DecompressOnLoad;
}else if (duration >= AudioExtendSettings.Instance.streamingThreshold) }else if (duration >= Settings.streamingThreshold)
{ {
settings.loadType = AudioClipLoadType.Streaming; settings.loadType = AudioClipLoadType.Streaming;
} }
@@ -141,10 +158,10 @@ namespace OCES.Audio
case AudioCategory.Voice: case AudioCategory.Voice:
case AudioCategory.SFX: case AudioCategory.SFX:
default: default:
settings.sampleRateOverride = AudioExtendSettings.Instance.sfxSampleRate; // 音效2022.3.62f3没有32kHz这一档,要是有的话这一档其实最合适 settings.sampleRateOverride = Settings.sfxSampleRate; // 音效2022.3.62f3没有32kHz这一档,要是有的话这一档其实最合适
settings.quality = AudioExtendSettings.Instance.sfxQuality; settings.quality = Settings.sfxQuality;
settings.loadType = duration >= AudioExtendSettings.Instance.streamingThreshold settings.loadType = duration >= Settings.streamingThreshold
? AudioClipLoadType.Streaming ? AudioClipLoadType.Streaming
: AudioClipLoadType.DecompressOnLoad; : AudioClipLoadType.DecompressOnLoad;
break; break;
@@ -0,0 +1,57 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Build;
namespace OCES.Audio.HandWritten.Editor
{
public static class MixingHelper
{
static readonly List<NamedBuildTarget> s_selectedBuildTargets = new()
{
NamedBuildTarget.Android,
NamedBuildTarget.iOS,
NamedBuildTarget.Standalone,
};
static readonly AudioExtendSettings s_audioExtendSettings = AssetDatabase.LoadAssetAtPath<AudioExtendSettings>(AssetDatabase.GUIDToAssetPath("de80878c933394e2da0966a1466fd793"));
[MenuItem("Tools/OCES/Audio/Enable Mixing")]
public static void EnableMixing()
{
if (s_audioExtendSettings is not null && s_audioExtendSettings.useAssetBundle)
{
EditorUtility.DisplayDialog("Mixing", "已启用Asset Bundle。\n对音频文件的调整不会生效。", "好吧");
}
foreach (NamedBuildTarget buildTarget in s_selectedBuildTargets)
{
PlayerSettings.GetScriptingDefineSymbols(buildTarget, out string[] defineArray);
List<string> defineList = defineArray.ToList();
if (!defineArray.Contains("AUDIO_MIXING"))
{
defineList.Add("AUDIO_MIXING");
PlayerSettings.SetScriptingDefineSymbols(buildTarget, defineList.ToArray());
}
}
}
[MenuItem("Tools/OCES/Audio/Disable Mixing")]
public static void DisableMixing()
{
foreach (NamedBuildTarget buildTarget in s_selectedBuildTargets)
{
PlayerSettings.GetScriptingDefineSymbols(buildTarget, out string[] defineArray);
List<string> defineList = defineArray.ToList();
if (defineList.Contains("AUDIO_MIXING"))
{
defineList.Remove("AUDIO_MIXING");
PlayerSettings.SetScriptingDefineSymbols(buildTarget, defineList.ToArray());
}
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 388d2124804048c1a9ea3c403820b443
timeCreated: 1779159928
@@ -29,7 +29,7 @@ namespace OCES.Audio
internal void Restart(MusicContainer container, float inheritedBpm, double dspTime, double startOffset = 0d) internal void Restart(MusicContainer container, float inheritedBpm, double dspTime, double startOffset = 0d)
{ {
Debug.Log($"[BeatClock] Restarting {container.Id}, inheritedBpm = {inheritedBpm}, dspTime = {dspTime}"); //Debug.Log($"[BeatClock] Restarting {container.Id}, inheritedBpm = {inheritedBpm}, dspTime = {dspTime}");
StopAll(); StopAll();
this.m_blendError = this.m_stopped = false; this.m_blendError = this.m_stopped = false;
this.m_containerId = container.Id; this.m_containerId = container.Id;
@@ -354,7 +354,7 @@ namespace OCES.Audio
source.loop = false; source.loop = false;
source.volume = volumeScale; source.volume = volumeScale;
source.Play(); source.Play();
Debug.Log($"[LongAudioContainerPlayer] Playing {segment.Name} at {AudioSettings.dspTime}"); //Debug.Log($"[LongAudioContainerPlayer] Playing {segment.Name} at {AudioSettings.dspTime}");
if (isLoop && segment.StartOffset > 0) if (isLoop && segment.StartOffset > 0)
{ {
@@ -105,6 +105,11 @@ namespace OCES.Haptic
HapticController.Stop(); HapticController.Stop();
} }
public void EnableHaptic(bool enable)
{
HapticController.hapticsEnabled = enable;
}
void Awake() void Awake()
{ {
HapticSettings.Instance = this.hapticSettings; HapticSettings.Instance = this.hapticSettings;
+1 -1
View File
@@ -15,7 +15,7 @@ MonoBehaviour:
audioConfigPath: AudioData audioConfigPath: AudioData
audioResourcePath: Audios audioResourcePath: Audios
audioMixerPath: Audios/Master audioMixerPath: Audios/Master
useAssetBundle: 1 useAssetBundle: 0
audioBundlePath: Bundles/audios.ab audioBundlePath: Bundles/audios.ab
sfxGroupPath: Master/Regular/SFX sfxGroupPath: Master/Regular/SFX
voiceGroupPath: Master/Regular/Voice voiceGroupPath: Master/Regular/Voice
+2 -2
View File
@@ -9,7 +9,7 @@ AudioManager:
Doppler Factor: 1 Doppler Factor: 1
Default Speaker Mode: 2 Default Speaker Mode: 2
m_SampleRate: 44100 m_SampleRate: 44100
m_DSPBufferSize: 256 m_DSPBufferSize: 512
m_VirtualVoiceCount: 512 m_VirtualVoiceCount: 512
m_RealVoiceCount: 32 m_RealVoiceCount: 32
m_EnableOutputSuspension: 0 m_EnableOutputSuspension: 0
@@ -17,4 +17,4 @@ AudioManager:
m_AmbisonicDecoderPlugin: m_AmbisonicDecoderPlugin:
m_DisableAudio: 0 m_DisableAudio: 0
m_VirtualizeEffects: 1 m_VirtualizeEffects: 1
m_RequestedDSPBufferSize: 256 m_RequestedDSPBufferSize: 512
+6 -6
View File
@@ -20,7 +20,7 @@ PlayerSettings:
m_ShowUnitySplashScreen: 1 m_ShowUnitySplashScreen: 1
m_ShowUnitySplashLogo: 1 m_ShowUnitySplashLogo: 1
m_SplashScreenOverlayOpacity: 1 m_SplashScreenOverlayOpacity: 1
m_SplashScreenAnimation: 1 m_SplashScreenAnimation: 0
m_SplashScreenLogoStyle: 1 m_SplashScreenLogoStyle: 1
m_SplashScreenDrawMode: 0 m_SplashScreenDrawMode: 0
m_SplashScreenBackgroundAnimationZoom: 1 m_SplashScreenBackgroundAnimationZoom: 1
@@ -42,8 +42,8 @@ PlayerSettings:
m_SplashScreenLogos: [] m_SplashScreenLogos: []
m_VirtualRealitySplashScreen: {fileID: 0} m_VirtualRealitySplashScreen: {fileID: 0}
m_HolographicTrackingLossScreen: {fileID: 0} m_HolographicTrackingLossScreen: {fileID: 0}
defaultScreenWidth: 1920 defaultScreenWidth: 540
defaultScreenHeight: 1080 defaultScreenHeight: 1200
defaultScreenWidthWeb: 960 defaultScreenWidthWeb: 960
defaultScreenHeightWeb: 600 defaultScreenHeightWeb: 600
m_StereoRenderingPath: 0 m_StereoRenderingPath: 0
@@ -80,7 +80,7 @@ PlayerSettings:
androidPredictiveBackSupport: 1 androidPredictiveBackSupport: 1
defaultIsNativeResolution: 1 defaultIsNativeResolution: 1
macRetinaSupport: 1 macRetinaSupport: 1
runInBackground: 0 runInBackground: 1
captureSingleScreen: 0 captureSingleScreen: 0
muteOtherAudioSources: 0 muteOtherAudioSources: 0
Prepare IOS For Recording: 0 Prepare IOS For Recording: 0
@@ -104,8 +104,8 @@ PlayerSettings:
xboxEnableKinectAutoTracking: 0 xboxEnableKinectAutoTracking: 0
xboxEnableFitness: 0 xboxEnableFitness: 0
visibleInBackground: 1 visibleInBackground: 1
allowFullscreenSwitch: 1 allowFullscreenSwitch: 0
fullscreenMode: 1 fullscreenMode: 3
xboxSpeechDB: 0 xboxSpeechDB: 0
xboxEnableHeadOrientation: 0 xboxEnableHeadOrientation: 0
xboxEnableGuest: 0 xboxEnableGuest: 0
+12
View File
@@ -72,6 +72,18 @@ AudioSystem.Instance.SetState(MyCustomEnum.SomeState); // 需先通过 StateGro
- 游戏启动时的首次状态设置**必须放在 `Start` 内**,晚一点可以,早了容易出问题。 - 游戏启动时的首次状态设置**必须放在 `Start` 内**,晚一点可以,早了容易出问题。
- 若需在其他位置进行首次初始化,请注释掉 `AudioSystem.Start()` 中的相关代码。 - 若需在其他位置进行首次初始化,请注释掉 `AudioSystem.Start()` 中的相关代码。
### 开关
```csharp
AudioSystem.Instance.SetMusicVolume(float tatgetVolume) //设置音乐音量 -800
AudioSystem.Instance.SetSFXVolume(float tatgetVolume) //设置音效音量 -800
AudioSystem.Instance.SetMusicState(bool enable) // 启用/禁用音乐
AudioSystem.Instance.SetSFXState(bool enable) // 启用/禁用音效
HapticSytem.Instance.EnableHaptic(bool enable) // 启用/禁用触感系统
```
### Inspector 参数 ### Inspector 参数
| 字段 | 说明 | | 字段 | 说明 |