Merge pull request '优化模拟器提交过来的元素转换为Unity Texture2D数据的代码' (#20) from Alienjack/AxibugEmuOnline:dev_4VirtualNes into dev_4VirtualNes
Reviewed-on: #20
This commit is contained in:
commit
c465f1a66e
@ -26,7 +26,7 @@ RenderSettings:
|
|||||||
m_AmbientIntensity: 1
|
m_AmbientIntensity: 1
|
||||||
m_AmbientMode: 0
|
m_AmbientMode: 0
|
||||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||||
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
m_SkyboxMaterial: {fileID: 0}
|
||||||
m_HaloStrength: 0.5
|
m_HaloStrength: 0.5
|
||||||
m_FlareStrength: 1
|
m_FlareStrength: 1
|
||||||
m_FlareFadeSpeed: 3
|
m_FlareFadeSpeed: 3
|
||||||
@ -38,7 +38,7 @@ RenderSettings:
|
|||||||
m_ReflectionIntensity: 1
|
m_ReflectionIntensity: 1
|
||||||
m_CustomReflection: {fileID: 0}
|
m_CustomReflection: {fileID: 0}
|
||||||
m_Sun: {fileID: 0}
|
m_Sun: {fileID: 0}
|
||||||
m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
|
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
m_UseRadianceAmbientProbe: 0
|
m_UseRadianceAmbientProbe: 0
|
||||||
--- !u!157 &3
|
--- !u!157 &3
|
||||||
LightmapSettings:
|
LightmapSettings:
|
||||||
@ -123,99 +123,6 @@ NavMeshSettings:
|
|||||||
debug:
|
debug:
|
||||||
m_Flags: 0
|
m_Flags: 0
|
||||||
m_NavMeshData: {fileID: 0}
|
m_NavMeshData: {fileID: 0}
|
||||||
--- !u!1 &708549044
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 708549046}
|
|
||||||
- component: {fileID: 708549045}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Directional Light
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!108 &708549045
|
|
||||||
Light:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 708549044}
|
|
||||||
m_Enabled: 1
|
|
||||||
serializedVersion: 10
|
|
||||||
m_Type: 1
|
|
||||||
m_Shape: 0
|
|
||||||
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
|
||||||
m_Intensity: 1
|
|
||||||
m_Range: 10
|
|
||||||
m_SpotAngle: 30
|
|
||||||
m_InnerSpotAngle: 21.80208
|
|
||||||
m_CookieSize: 10
|
|
||||||
m_Shadows:
|
|
||||||
m_Type: 2
|
|
||||||
m_Resolution: -1
|
|
||||||
m_CustomResolution: -1
|
|
||||||
m_Strength: 1
|
|
||||||
m_Bias: 0.05
|
|
||||||
m_NormalBias: 0.4
|
|
||||||
m_NearPlane: 0.2
|
|
||||||
m_CullingMatrixOverride:
|
|
||||||
e00: 1
|
|
||||||
e01: 0
|
|
||||||
e02: 0
|
|
||||||
e03: 0
|
|
||||||
e10: 0
|
|
||||||
e11: 1
|
|
||||||
e12: 0
|
|
||||||
e13: 0
|
|
||||||
e20: 0
|
|
||||||
e21: 0
|
|
||||||
e22: 1
|
|
||||||
e23: 0
|
|
||||||
e30: 0
|
|
||||||
e31: 0
|
|
||||||
e32: 0
|
|
||||||
e33: 1
|
|
||||||
m_UseCullingMatrixOverride: 0
|
|
||||||
m_Cookie: {fileID: 0}
|
|
||||||
m_DrawHalo: 0
|
|
||||||
m_Flare: {fileID: 0}
|
|
||||||
m_RenderMode: 0
|
|
||||||
m_CullingMask:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Bits: 4294967295
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_Lightmapping: 4
|
|
||||||
m_LightShadowCasterMode: 0
|
|
||||||
m_AreaSize: {x: 1, y: 1}
|
|
||||||
m_BounceIntensity: 1
|
|
||||||
m_ColorTemperature: 6570
|
|
||||||
m_UseColorTemperature: 0
|
|
||||||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
|
||||||
m_UseBoundingSphereOverride: 0
|
|
||||||
m_UseViewFrustumForShadowCasterCull: 1
|
|
||||||
m_ShadowRadius: 0
|
|
||||||
m_ShadowAngle: 0
|
|
||||||
--- !u!4 &708549046
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 708549044}
|
|
||||||
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
|
||||||
m_LocalPosition: {x: 0, y: 3, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
|
||||||
--- !u!1 &1232273651
|
--- !u!1 &1232273651
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -252,7 +159,7 @@ Camera:
|
|||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_ClearFlags: 1
|
m_ClearFlags: 1
|
||||||
m_BackGroundColor: {r: 1, g: 1, b: 1, a: 0}
|
m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0}
|
||||||
m_projectionMatrixMode: 1
|
m_projectionMatrixMode: 1
|
||||||
m_GateFitMode: 2
|
m_GateFitMode: 2
|
||||||
m_FOVAxisMode: 0
|
m_FOVAxisMode: 0
|
||||||
@ -297,7 +204,7 @@ Transform:
|
|||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 2
|
m_RootOrder: 1
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &1359344831
|
--- !u!1 &1359344831
|
||||||
GameObject:
|
GameObject:
|
||||||
@ -363,7 +270,7 @@ Transform:
|
|||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 1
|
m_RootOrder: 0
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1001 &4232056520998800727
|
--- !u!1001 &4232056520998800727
|
||||||
PrefabInstance:
|
PrefabInstance:
|
||||||
@ -374,7 +281,7 @@ PrefabInstance:
|
|||||||
m_Modifications:
|
m_Modifications:
|
||||||
- target: {fileID: 4232056521131536011, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
- target: {fileID: 4232056521131536011, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
||||||
propertyPath: m_RootOrder
|
propertyPath: m_RootOrder
|
||||||
value: 3
|
value: 2
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 4232056521131536011, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
- target: {fileID: 4232056521131536011, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
||||||
propertyPath: m_LocalPosition.x
|
propertyPath: m_LocalPosition.x
|
||||||
@ -420,5 +327,17 @@ PrefabInstance:
|
|||||||
propertyPath: m_Name
|
propertyPath: m_Name
|
||||||
value: NesEmulator
|
value: NesEmulator
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4232056521759880274, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
||||||
|
propertyPath: m_Enabled
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4232056521759880274, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
||||||
|
propertyPath: m_Texture
|
||||||
|
value:
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4232056521759880276, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
||||||
|
propertyPath: m_IsActive
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
m_RemovedComponents: []
|
m_RemovedComponents: []
|
||||||
m_SourcePrefab: {fileID: 100100000, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
m_SourcePrefab: {fileID: 100100000, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using UnityEngine;
|
||||||
|
using VirtualNes.Core;
|
||||||
|
|
||||||
|
public class AudioProvider : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField]
|
||||||
|
private AudioSource m_as;
|
||||||
|
|
||||||
|
private SoundBuffer _buffer = new SoundBuffer(4096);
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
var dummy = AudioClip.Create("dummy", 1, 1, AudioSettings.outputSampleRate, false);
|
||||||
|
|
||||||
|
dummy.SetData(new float[] { 1 }, 0);
|
||||||
|
m_as.clip = dummy; //just to let unity play the audiosource
|
||||||
|
m_as.loop = true;
|
||||||
|
m_as.spatialBlend = 1;
|
||||||
|
m_as.Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnAudioFilterRead(float[] data, int channels)
|
||||||
|
{
|
||||||
|
int step = channels;
|
||||||
|
|
||||||
|
var bufferCount = _buffer.Available();
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Length; i += step)
|
||||||
|
{
|
||||||
|
float rawFloat = 0;
|
||||||
|
if (_buffer.TryRead(out byte rawData))
|
||||||
|
rawFloat = rawData / 255f;
|
||||||
|
|
||||||
|
data[i] = rawFloat;
|
||||||
|
for (int fill = 1; fill < step; fill++)
|
||||||
|
data[i + fill] = rawFloat;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessSound(NES nes)
|
||||||
|
{
|
||||||
|
nes.apu.Process(_buffer, (uint)(Supporter.Config.sound.nRate * Time.deltaTime));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a6a09b6a4cf4c2d4f994a13fd7e89d6f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using VirtualNes.Core;
|
using VirtualNes.Core;
|
||||||
using VirtualNes.Core.Debug;
|
using VirtualNes.Core.Debug;
|
||||||
@ -11,9 +10,11 @@ namespace AxibugEmuOnline.Client
|
|||||||
private NES m_nesIns;
|
private NES m_nesIns;
|
||||||
|
|
||||||
public VideoProvider VideoProvider;
|
public VideoProvider VideoProvider;
|
||||||
|
public AudioProvider AudioProvider;
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
|
Application.targetFrameRate = 60;
|
||||||
StartGame("Kirby.nes");
|
StartGame("Kirby.nes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,8 +51,9 @@ namespace AxibugEmuOnline.Client
|
|||||||
|
|
||||||
var screenBuffer = m_nesIns.ppu.GetScreenPtr();
|
var screenBuffer = m_nesIns.ppu.GetScreenPtr();
|
||||||
var lineColorMode = m_nesIns.ppu.GetLineColorMode();
|
var lineColorMode = m_nesIns.ppu.GetLineColorMode();
|
||||||
|
|
||||||
VideoProvider.SetDrawData(screenBuffer, lineColorMode, 256, 240);
|
VideoProvider.SetDrawData(screenBuffer, lineColorMode, 256, 240);
|
||||||
|
|
||||||
|
AudioProvider.ProcessSound(m_nesIns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,146 @@
|
|||||||
%YAML 1.1
|
%YAML 1.1
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &9760340517325694
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 4785916497946256520}
|
||||||
|
- component: {fileID: 9003897287163669553}
|
||||||
|
- component: {fileID: 7558824780418593440}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: AudioProvider
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &4785916497946256520
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9760340517325694}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 4232056521131536011}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &9003897287163669553
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9760340517325694}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: a6a09b6a4cf4c2d4f994a13fd7e89d6f, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_as: {fileID: 7558824780418593440}
|
||||||
|
--- !u!82 &7558824780418593440
|
||||||
|
AudioSource:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 9760340517325694}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 4
|
||||||
|
OutputAudioMixerGroup: {fileID: 0}
|
||||||
|
m_audioClip: {fileID: 0}
|
||||||
|
m_PlayOnAwake: 1
|
||||||
|
m_Volume: 1
|
||||||
|
m_Pitch: 1
|
||||||
|
Loop: 0
|
||||||
|
Mute: 0
|
||||||
|
Spatialize: 0
|
||||||
|
SpatializePostEffects: 0
|
||||||
|
Priority: 128
|
||||||
|
DopplerLevel: 1
|
||||||
|
MinDistance: 1
|
||||||
|
MaxDistance: 500
|
||||||
|
Pan2D: 0
|
||||||
|
rolloffMode: 0
|
||||||
|
BypassEffects: 0
|
||||||
|
BypassListenerEffects: 0
|
||||||
|
BypassReverbZones: 0
|
||||||
|
rolloffCustomCurve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: 1
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0.33333334
|
||||||
|
outWeight: 0.33333334
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 1
|
||||||
|
value: 0
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0.33333334
|
||||||
|
outWeight: 0.33333334
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
|
panLevelCustomCurve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: 0
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0.33333334
|
||||||
|
outWeight: 0.33333334
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
|
spreadCustomCurve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: 0
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0.33333334
|
||||||
|
outWeight: 0.33333334
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
|
reverbZoneMixCustomCurve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: 1
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0.33333334
|
||||||
|
outWeight: 0.33333334
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
--- !u!1 &4232056520112715746
|
--- !u!1 &4232056520112715746
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -174,6 +315,7 @@ Transform:
|
|||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 4232056520112715745}
|
- {fileID: 4232056520112715745}
|
||||||
|
- {fileID: 4785916497946256520}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 0
|
m_RootOrder: 0
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
@ -190,6 +332,7 @@ MonoBehaviour:
|
|||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
VideoProvider: {fileID: 4232056520112715744}
|
VideoProvider: {fileID: 4232056520112715744}
|
||||||
|
AudioProvider: {fileID: 9003897287163669553}
|
||||||
--- !u!1 &4232056521759880276
|
--- !u!1 &4232056521759880276
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!84 &8400000
|
|
||||||
RenderTexture:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_Name: New Render Texture
|
|
||||||
m_ImageContentsHash:
|
|
||||||
serializedVersion: 2
|
|
||||||
Hash: 00000000000000000000000000000000
|
|
||||||
m_ForcedFallbackFormat: 4
|
|
||||||
m_DownscaleFallback: 0
|
|
||||||
m_IsAlphaChannelOptional: 0
|
|
||||||
serializedVersion: 3
|
|
||||||
m_Width: 272
|
|
||||||
m_Height: 240
|
|
||||||
m_AntiAliasing: 1
|
|
||||||
m_MipCount: -1
|
|
||||||
m_DepthFormat: 2
|
|
||||||
m_ColorFormat: 8
|
|
||||||
m_MipMap: 0
|
|
||||||
m_GenerateMips: 1
|
|
||||||
m_SRGB: 0
|
|
||||||
m_UseDynamicScale: 0
|
|
||||||
m_BindMS: 0
|
|
||||||
m_EnableCompatibleFormat: 1
|
|
||||||
m_TextureSettings:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_FilterMode: 1
|
|
||||||
m_Aniso: 0
|
|
||||||
m_MipBias: 0
|
|
||||||
m_WrapU: 1
|
|
||||||
m_WrapV: 1
|
|
||||||
m_WrapW: 1
|
|
||||||
m_Dimension: 2
|
|
||||||
m_VolumeDepth: 1
|
|
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: ffe34aaf87e4b9942b4c2ac05943d444
|
|
||||||
NativeFormatImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
mainObjectFileID: 8400000
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
@ -1,13 +1,7 @@
|
|||||||
using AxibugEmuOnline.Client.Assets.Script.NesEmulator;
|
using AxibugEmuOnline.Client.Assets.Script.NesEmulator;
|
||||||
using Codice.CM.Client.Differences;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Playables;
|
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using VirtualNes.Core;
|
using VirtualNes.Core;
|
||||||
|
|
||||||
@ -17,23 +11,29 @@ namespace AxibugEmuOnline.Client
|
|||||||
{
|
{
|
||||||
public RawImage Image;
|
public RawImage Image;
|
||||||
|
|
||||||
private Color32[] wrapTexBuffer;
|
private UInt32[] wrapTexBuffer;
|
||||||
private IntPtr wrapTexBufferPointer;
|
private IntPtr wrapTexBufferPointer;
|
||||||
private Texture2D wrapTex;
|
private Texture2D wrapTex;
|
||||||
|
private int TexBufferSize;
|
||||||
|
|
||||||
|
private uint[] pPal;
|
||||||
public void SetDrawData(byte[] screenData, byte[] lineColorMode, int screenWidth, int screenHeight)
|
public void SetDrawData(byte[] screenData, byte[] lineColorMode, int screenWidth, int screenHeight)
|
||||||
{
|
{
|
||||||
if (wrapTex == null)
|
if (wrapTex == null)
|
||||||
{
|
{
|
||||||
wrapTex = new Texture2D(screenWidth, screenHeight, TextureFormat.BGRA32, false);
|
wrapTex = new Texture2D(screenWidth, screenHeight, TextureFormat.BGRA32, false);
|
||||||
wrapTexBuffer = new Color32[screenWidth * screenHeight];
|
wrapTexBuffer = new UInt32[screenWidth * screenHeight];
|
||||||
// 固定数组,防止垃圾回收器移动它
|
// 固定数组,防止垃圾回收器移动它
|
||||||
GCHandle handle = GCHandle.Alloc(wrapTexBuffer, GCHandleType.Pinned);
|
GCHandle handle = GCHandle.Alloc(wrapTexBuffer, GCHandleType.Pinned);
|
||||||
// 获取数组的指针
|
// 获取数组的指针
|
||||||
wrapTexBufferPointer = handle.AddrOfPinnedObject();
|
wrapTexBufferPointer = handle.AddrOfPinnedObject();
|
||||||
|
|
||||||
|
Image.texture = wrapTex;
|
||||||
|
pPal = PaletteDefine.m_cnPalette[0];
|
||||||
|
|
||||||
|
TexBufferSize = wrapTexBuffer.Length * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint[] pPal;
|
|
||||||
int pScn = 0;
|
int pScn = 0;
|
||||||
int width;
|
int width;
|
||||||
|
|
||||||
@ -42,41 +42,26 @@ namespace AxibugEmuOnline.Client
|
|||||||
|
|
||||||
for (int line = 0; line < screenHeight; line++)
|
for (int line = 0; line < screenHeight; line++)
|
||||||
{
|
{
|
||||||
if ((lineColorMode[line] & 0x80) == 0)
|
|
||||||
{
|
|
||||||
pPal = PaletteDefine.m_cnPalette[lineColorMode[line] & 0x07];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pPal = PaletteDefine.m_mnPalette[lineColorMode[line] & 0x07];
|
|
||||||
}
|
|
||||||
|
|
||||||
width = screenWidth;
|
width = screenWidth;
|
||||||
|
|
||||||
while (width > 0)
|
while (width > 0)
|
||||||
{
|
{
|
||||||
var edx = screenData[pScn + 8];
|
var edx = screenData[pScn + 8];
|
||||||
|
|
||||||
byte index = (byte)(edx & 0xFF);
|
int index = edx & 0xFF;
|
||||||
var colorData = pPal[index];
|
var colorData = pPal[index];
|
||||||
var rawData = BitConverter.GetBytes(colorData);
|
Dst[pDst] = 0xFF000000 | colorData;
|
||||||
Dst[pDst] = new Color32(rawData[0], rawData[1], rawData[2], 255);
|
|
||||||
|
|
||||||
pScn += 1;
|
pScn += 1;
|
||||||
pDst += 1;
|
pDst += 1;
|
||||||
width -= 1;
|
width -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pScn += PPU.SCREEN_WIDTH - screenWidth;
|
pScn += 16;// PPU.SCREEN_WIDTH - screenWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
//wrapTex.SetPixels32(wrapTexBuffer);
|
wrapTex.LoadRawTextureData(wrapTexBufferPointer, TexBufferSize);
|
||||||
wrapTex.LoadRawTextureData(wrapTexBufferPointer, screenWidth * screenHeight * 4);
|
|
||||||
wrapTex.Apply();
|
wrapTex.Apply();
|
||||||
|
|
||||||
Graphics.Blit(wrapTex, Image.mainTexture as RenderTexture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
public class RingBuffer<T>
|
public class RingBuffer<T>
|
||||||
|
11
AxibugEmuOnline.Client/Assets/Script/SoundBuffer.cs
Normal file
11
AxibugEmuOnline.Client/Assets/Script/SoundBuffer.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using VirtualNes.Core;
|
||||||
|
|
||||||
|
public class SoundBuffer : RingBuffer<byte>, ISoundDataBuffer
|
||||||
|
{
|
||||||
|
public SoundBuffer(int capacity) : base(capacity) { }
|
||||||
|
|
||||||
|
public void WriteByte(byte value)
|
||||||
|
{
|
||||||
|
Write(value);
|
||||||
|
}
|
||||||
|
}
|
11
AxibugEmuOnline.Client/Assets/Script/SoundBuffer.cs.meta
Normal file
11
AxibugEmuOnline.Client/Assets/Script/SoundBuffer.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c5f491c577bed63478340426f7698563
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -1,4 +1,9 @@
|
|||||||
using System;
|
using Codice.CM.Client.Differences;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using UnityEngine;
|
||||||
|
using VirtualNes.Core;
|
||||||
using VirtualNes.Core.Debug;
|
using VirtualNes.Core.Debug;
|
||||||
|
|
||||||
namespace VirtualNes.Core
|
namespace VirtualNes.Core
|
||||||
@ -7,6 +12,20 @@ namespace VirtualNes.Core
|
|||||||
{
|
{
|
||||||
public const uint QUEUE_LENGTH = 8192;
|
public const uint QUEUE_LENGTH = 8192;
|
||||||
|
|
||||||
|
// Volume adjust
|
||||||
|
// Internal sounds
|
||||||
|
public const uint RECTANGLE_VOL = 0x0F0;
|
||||||
|
public const uint TRIANGLE_VOL = 0x130;
|
||||||
|
public const uint NOISE_VOL = 0x0C0;
|
||||||
|
public const uint DPCM_VOL = 0x0F0;
|
||||||
|
// Extra sounds
|
||||||
|
public const uint VRC6_VOL = 0x0F0;
|
||||||
|
public const uint VRC7_VOL = 0x130;
|
||||||
|
public const uint FDS_VOL = 0x0F0;
|
||||||
|
public const uint MMC5_VOL = 0x0F0;
|
||||||
|
public const uint N106_VOL = 0x088;
|
||||||
|
public const uint FME7_VOL = 0x130;
|
||||||
|
|
||||||
private NES nes;
|
private NES nes;
|
||||||
private byte exsound_select;
|
private byte exsound_select;
|
||||||
private APU_INTERNAL @internal = new APU_INTERNAL();
|
private APU_INTERNAL @internal = new APU_INTERNAL();
|
||||||
@ -41,8 +60,319 @@ namespace VirtualNes.Core
|
|||||||
m_bMute[i] = true;
|
m_bMute[i] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose() { }
|
||||||
|
|
||||||
|
private int[] vol = new int[24];
|
||||||
|
static double cutofftemp = (2.0 * 3.141592653579 * 40.0);
|
||||||
|
static double tmp = 0.0;
|
||||||
|
|
||||||
|
public void Process(ISoundDataBuffer lpBuffer, uint dwSize)
|
||||||
{
|
{
|
||||||
|
int nBits = Supporter.Config.sound.nBits;
|
||||||
|
uint dwLength = (uint)(dwSize / (nBits / 8));
|
||||||
|
int output;
|
||||||
|
QUEUEDATA q = default;
|
||||||
|
uint writetime;
|
||||||
|
|
||||||
|
var pSoundBuf = m_SoundBuffer;
|
||||||
|
int nCcount = 0;
|
||||||
|
|
||||||
|
int nFilterType = Supporter.Config.sound.nFilterType;
|
||||||
|
|
||||||
|
if (!Supporter.Config.sound.bEnable)
|
||||||
|
{
|
||||||
|
byte empty = (byte)(Supporter.Config.sound.nRate == 8 ? 128 : 0);
|
||||||
|
for (int i = 0; i < dwSize; i++)
|
||||||
|
lpBuffer.WriteByte(empty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume setup
|
||||||
|
// 0:Master
|
||||||
|
// 1:Rectangle 1
|
||||||
|
// 2:Rectangle 2
|
||||||
|
// 3:Triangle
|
||||||
|
// 4:Noise
|
||||||
|
// 5:DPCM
|
||||||
|
// 6:VRC6
|
||||||
|
// 7:VRC7
|
||||||
|
// 8:FDS
|
||||||
|
// 9:MMC5
|
||||||
|
// 10:N106
|
||||||
|
// 11:FME7
|
||||||
|
MemoryUtility.ZEROMEMORY(vol, vol.Length);
|
||||||
|
|
||||||
|
var bMute = m_bMute;
|
||||||
|
var nVolume = Supporter.Config.sound.nVolume;
|
||||||
|
|
||||||
|
int nMasterVolume = bMute[0] ? nVolume[0] : 0;
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
vol[0] = (int)(bMute[1] ? (RECTANGLE_VOL * nVolume[1] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[1] = (int)(bMute[2] ? (RECTANGLE_VOL * nVolume[2] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[2] = (int)(bMute[3] ? (TRIANGLE_VOL * nVolume[3] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[3] = (int)(bMute[4] ? (NOISE_VOL * nVolume[4] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[4] = (int)(bMute[5] ? (DPCM_VOL * nVolume[5] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
|
||||||
|
// VRC6
|
||||||
|
vol[5] = (int)(bMute[6] ? (VRC6_VOL * nVolume[6] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[6] = (int)(bMute[7] ? (VRC6_VOL * nVolume[6] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[7] = (int)(bMute[8] ? (VRC6_VOL * nVolume[6] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
|
||||||
|
// VRC7
|
||||||
|
vol[8] = (int)(bMute[6] ? (VRC7_VOL * nVolume[7] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
|
||||||
|
// FDS
|
||||||
|
vol[9] = (int)(bMute[6] ? (FDS_VOL * nVolume[8] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
|
||||||
|
// MMC5
|
||||||
|
vol[10] = (int)(bMute[6] ? (MMC5_VOL * nVolume[9] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[11] = (int)(bMute[7] ? (MMC5_VOL * nVolume[9] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[12] = (int)(bMute[8] ? (MMC5_VOL * nVolume[9] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
|
||||||
|
// N106
|
||||||
|
vol[13] = (int)(bMute[6] ? (N106_VOL * nVolume[10] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[14] = (int)(bMute[7] ? (N106_VOL * nVolume[10] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[15] = (int)(bMute[8] ? (N106_VOL * nVolume[10] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[16] = (int)(bMute[9] ? (N106_VOL * nVolume[10] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[17] = (int)(bMute[10] ? (N106_VOL * nVolume[10] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[18] = (int)(bMute[11] ? (N106_VOL * nVolume[10] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[19] = (int)(bMute[12] ? (N106_VOL * nVolume[10] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[20] = (int)(bMute[13] ? (N106_VOL * nVolume[10] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
|
||||||
|
// FME7
|
||||||
|
vol[21] = (int)(bMute[6] ? (FME7_VOL * nVolume[11] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[22] = (int)(bMute[7] ? (FME7_VOL * nVolume[11] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
vol[23] = (int)(bMute[8] ? (FME7_VOL * nVolume[11] * nMasterVolume) / (100 * 100) : 0);
|
||||||
|
|
||||||
|
// double cycle_rate = ((double)FRAME_CYCLES*60.0/12.0)/(double)Config.sound.nRate;
|
||||||
|
double cycle_rate = (nes.nescfg.FrameCycles * 60.0 / 12.0) / Supporter.Config.sound.nRate;
|
||||||
|
|
||||||
|
// CPUサイクル数がループしてしまった時の対策処理
|
||||||
|
if (elapsed_time > nes.cpu.GetTotalCycles())
|
||||||
|
{
|
||||||
|
QueueFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((dwLength--) != 0)
|
||||||
|
{
|
||||||
|
writetime = (uint)elapsed_time;
|
||||||
|
|
||||||
|
while (GetQueue((int)writetime, ref q))
|
||||||
|
{
|
||||||
|
WriteProcess(q.addr, q.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (GetExQueue((int)writetime, ref q))
|
||||||
|
{
|
||||||
|
WriteExProcess(q.addr, q.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0-4:internal 5-7:VRC6 8:VRC7 9:FDS 10-12:MMC5 13-20:N106 21-23:FME7
|
||||||
|
output = 0;
|
||||||
|
output += @internal.Process(0) * vol[0];
|
||||||
|
output += @internal.Process(1) * vol[1];
|
||||||
|
output += @internal.Process(2) * vol[2];
|
||||||
|
output += @internal.Process(3) * vol[3];
|
||||||
|
output += @internal.Process(4) * vol[4];
|
||||||
|
|
||||||
|
if ((exsound_select & 0x01) != 0)
|
||||||
|
{
|
||||||
|
output += vrc6.Process(0) * vol[5];
|
||||||
|
output += vrc6.Process(1) * vol[6];
|
||||||
|
output += vrc6.Process(2) * vol[7];
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x02) != 0)
|
||||||
|
{
|
||||||
|
output += vrc7.Process(0) * vol[8];
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x04) != 0)
|
||||||
|
{
|
||||||
|
output += fds.Process(0) * vol[9];
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x08) != 0)
|
||||||
|
{
|
||||||
|
output += mmc5.Process(0) * vol[10];
|
||||||
|
output += mmc5.Process(1) * vol[11];
|
||||||
|
output += mmc5.Process(2) * vol[12];
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x10) != 0)
|
||||||
|
{
|
||||||
|
output += n106.Process(0) * vol[13];
|
||||||
|
output += n106.Process(1) * vol[14];
|
||||||
|
output += n106.Process(2) * vol[15];
|
||||||
|
output += n106.Process(3) * vol[16];
|
||||||
|
output += n106.Process(4) * vol[17];
|
||||||
|
output += n106.Process(5) * vol[18];
|
||||||
|
output += n106.Process(6) * vol[19];
|
||||||
|
output += n106.Process(7) * vol[20];
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x20) != 0)
|
||||||
|
{
|
||||||
|
fme7.Process(3); // Envelope & Noise
|
||||||
|
output += fme7.Process(0) * vol[21];
|
||||||
|
output += fme7.Process(1) * vol[22];
|
||||||
|
output += fme7.Process(2) * vol[23];
|
||||||
|
}
|
||||||
|
|
||||||
|
output >>= 8;
|
||||||
|
|
||||||
|
if (nFilterType == 1)
|
||||||
|
{
|
||||||
|
//ローパスフィルターTYPE 1(Simple)
|
||||||
|
output = (lowpass_filter[0] + output) / 2;
|
||||||
|
lowpass_filter[0] = output;
|
||||||
|
}
|
||||||
|
else if (nFilterType == 2)
|
||||||
|
{
|
||||||
|
//ローパスフィルターTYPE 2(Weighted type 1)
|
||||||
|
output = (lowpass_filter[1] + lowpass_filter[0] + output) / 3;
|
||||||
|
lowpass_filter[1] = lowpass_filter[0];
|
||||||
|
lowpass_filter[0] = output;
|
||||||
|
}
|
||||||
|
else if (nFilterType == 3)
|
||||||
|
{
|
||||||
|
//ローパスフィルターTYPE 3(Weighted type 2)
|
||||||
|
output = (lowpass_filter[2] + lowpass_filter[1] + lowpass_filter[0] + output) / 4;
|
||||||
|
lowpass_filter[2] = lowpass_filter[1];
|
||||||
|
lowpass_filter[1] = lowpass_filter[0];
|
||||||
|
lowpass_filter[0] = output;
|
||||||
|
}
|
||||||
|
else if (nFilterType == 4)
|
||||||
|
{
|
||||||
|
//ローパスフィルターTYPE 4(Weighted type 3)
|
||||||
|
output = (lowpass_filter[1] + lowpass_filter[0] * 2 + output) / 4;
|
||||||
|
lowpass_filter[1] = lowpass_filter[0];
|
||||||
|
lowpass_filter[0] = output;
|
||||||
|
}
|
||||||
|
// DC成分のカット(HPF TEST)
|
||||||
|
{
|
||||||
|
// static double cutoff = (2.0*3.141592653579*40.0/44100.0);
|
||||||
|
double cutoff = cutofftemp / Supporter.Config.sound.nRate;
|
||||||
|
double @in, @out;
|
||||||
|
|
||||||
|
@in = output;
|
||||||
|
@out = (@in - tmp);
|
||||||
|
tmp = tmp + cutoff * @out;
|
||||||
|
|
||||||
|
output = (int)@out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit
|
||||||
|
if (output > 0x7FFF)
|
||||||
|
{
|
||||||
|
output = 0x7FFF;
|
||||||
|
}
|
||||||
|
else if (output < -0x8000)
|
||||||
|
{
|
||||||
|
output = -0x8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nBits != 8)
|
||||||
|
{
|
||||||
|
byte highByte = (byte)(output >> 8); // 获取高8位
|
||||||
|
byte lowByte = (byte)(output & 0xFF); // 获取低8位
|
||||||
|
lpBuffer.WriteByte(highByte);
|
||||||
|
lpBuffer.WriteByte(lowByte);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lpBuffer.WriteByte((byte)((output >> 8) ^ 0x80));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nCcount < 0x0100)
|
||||||
|
pSoundBuf[nCcount++] = (short)output;
|
||||||
|
|
||||||
|
// elapsedtime += cycle_rate;
|
||||||
|
elapsed_time += cycle_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (elapsed_time > ((nes.nescfg.FrameCycles / 24) + nes.cpu.GetTotalCycles()))
|
||||||
|
{
|
||||||
|
elapsed_time = nes.cpu.GetTotalCycles();
|
||||||
|
}
|
||||||
|
if ((elapsed_time + (nes.nescfg.FrameCycles / 6)) < nes.cpu.GetTotalCycles())
|
||||||
|
{
|
||||||
|
elapsed_time = nes.cpu.GetTotalCycles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GetExQueue(int writetime, ref QUEUEDATA ret)
|
||||||
|
{
|
||||||
|
if (exqueue.wrptr == exqueue.rdptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (exqueue.data[exqueue.rdptr].time <= writetime)
|
||||||
|
{
|
||||||
|
ret = exqueue.data[exqueue.rdptr];
|
||||||
|
exqueue.rdptr++;
|
||||||
|
exqueue.rdptr = (int)(exqueue.rdptr & (QUEUE_LENGTH - 1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void QueueFlush()
|
||||||
|
{
|
||||||
|
while (queue.wrptr != queue.rdptr)
|
||||||
|
{
|
||||||
|
WriteProcess(queue.data[queue.rdptr].addr, queue.data[queue.rdptr].data);
|
||||||
|
queue.rdptr++;
|
||||||
|
queue.rdptr = (int)(queue.rdptr & (QUEUE_LENGTH - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (exqueue.wrptr != exqueue.rdptr)
|
||||||
|
{
|
||||||
|
WriteExProcess(exqueue.data[exqueue.rdptr].addr, exqueue.data[exqueue.rdptr].data);
|
||||||
|
exqueue.rdptr++;
|
||||||
|
exqueue.rdptr = (int)(exqueue.rdptr & (QUEUE_LENGTH - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteExProcess(ushort addr, byte data)
|
||||||
|
{
|
||||||
|
if ((exsound_select & 0x01) != 0)
|
||||||
|
{
|
||||||
|
vrc6.Write(addr, data);
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x02) != 0)
|
||||||
|
{
|
||||||
|
vrc7.Write(addr, data);
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x04) != 0)
|
||||||
|
{
|
||||||
|
fds.Write(addr, data);
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x08) != 0)
|
||||||
|
{
|
||||||
|
mmc5.Write(addr, data);
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x10) != 0)
|
||||||
|
{
|
||||||
|
if (addr == 0x0000)
|
||||||
|
{
|
||||||
|
byte dummy = n106.Read(addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n106.Write(addr, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((exsound_select & 0x20) != 0)
|
||||||
|
{
|
||||||
|
fme7.Write(addr, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteProcess(ushort addr, byte data)
|
||||||
|
{
|
||||||
|
// $4018はVirtuaNES固有ポート
|
||||||
|
if (addr >= 0x4000 && addr <= 0x401F)
|
||||||
|
{
|
||||||
|
@internal.Write(addr, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SyncDPCM(int cycles)
|
internal void SyncDPCM(int cycles)
|
||||||
|
@ -1,7 +1,32 @@
|
|||||||
|
using Codice.CM.Client.Differences;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace VirtualNes.Core
|
namespace VirtualNes.Core
|
||||||
{
|
{
|
||||||
public class APU_INTERNAL : APU_INTERFACE
|
public class APU_INTERNAL : APU_INTERFACE
|
||||||
{
|
{
|
||||||
|
// Volume shift
|
||||||
|
public const int RECTANGLE_VOL_SHIFT = 8;
|
||||||
|
public const int TRIANGLE_VOL_SHIFT = 9;
|
||||||
|
public const int NOISE_VOL_SHIFT = 8;
|
||||||
|
public const int DPCM_VOL_SHIFT = 8;
|
||||||
|
|
||||||
|
// Tables
|
||||||
|
static public int[] freq_limit = new int[8]
|
||||||
|
{
|
||||||
|
0x03FF, 0x0555, 0x0666, 0x071C, 0x0787, 0x07C1, 0x07E0, 0x07F0
|
||||||
|
};
|
||||||
|
static public int[] duty_lut = new int[4]
|
||||||
|
{
|
||||||
|
2, 4, 8, 12
|
||||||
|
};
|
||||||
|
static public int[] noise_freq = new int[16]{
|
||||||
|
4, 8, 16, 32, 64, 96, 128, 160,
|
||||||
|
202, 254, 380, 508, 762, 1016, 2034, 4068
|
||||||
|
};
|
||||||
|
|
||||||
private static int[] vbl_length = new int[32]
|
private static int[] vbl_length = new int[32]
|
||||||
{
|
{
|
||||||
5, 127, 10, 1, 19, 2, 40, 3,
|
5, 127, 10, 1, 19, 2, 40, 3,
|
||||||
@ -37,9 +62,23 @@ namespace VirtualNes.Core
|
|||||||
private NOISE ch3 = new NOISE();
|
private NOISE ch3 = new NOISE();
|
||||||
private DPCM ch4 = new DPCM();
|
private DPCM ch4 = new DPCM();
|
||||||
|
|
||||||
|
// Sound
|
||||||
|
private float cpu_clock;
|
||||||
|
private int sampling_rate;
|
||||||
|
private int cycle_rate;
|
||||||
|
|
||||||
// $4015 Reg
|
// $4015 Reg
|
||||||
private byte reg4015, sync_reg4015;
|
private byte reg4015, sync_reg4015;
|
||||||
|
|
||||||
|
private const int TONEDATA_MAX = 16;
|
||||||
|
private const int TONEDATA_LEN = 32;
|
||||||
|
private const int CHANNEL_MAX = 3;
|
||||||
|
private const int TONE_MAX = 4;
|
||||||
|
|
||||||
|
bool[] bToneTableEnable = new bool[TONEDATA_MAX];
|
||||||
|
int[,] ToneTable = new int[TONEDATA_MAX, TONEDATA_LEN];
|
||||||
|
int[,] ChannelTone = new int[CHANNEL_MAX, TONE_MAX];
|
||||||
|
|
||||||
public void SetParent(NES parent)
|
public void SetParent(NES parent)
|
||||||
{
|
{
|
||||||
nes = parent;
|
nes = parent;
|
||||||
@ -127,23 +166,737 @@ namespace VirtualNes.Core
|
|||||||
|
|
||||||
public override void Reset(float fClock, int nRate)
|
public override void Reset(float fClock, int nRate)
|
||||||
{
|
{
|
||||||
//todo : 实现
|
ch0.ZeroMemory();
|
||||||
|
ch1.ZeroMemory();
|
||||||
|
ch2.ZeroMemory();
|
||||||
|
ch3.ZeroMemory();
|
||||||
|
|
||||||
|
Array.Clear(bToneTableEnable, 0, bToneTableEnable.Length);
|
||||||
|
Array.Clear(ToneTable, 0, ToneTable.Length);
|
||||||
|
Array.Clear(ChannelTone, 0, ChannelTone.Length);
|
||||||
|
|
||||||
|
reg4015 = sync_reg4015 = 0;
|
||||||
|
|
||||||
|
// Sweep complement
|
||||||
|
ch0.complement = 0x00;
|
||||||
|
ch1.complement = 0xFF;
|
||||||
|
|
||||||
|
// Noise shift register
|
||||||
|
ch3.shift_reg = 0x4000;
|
||||||
|
|
||||||
|
Setup(fClock, nRate);
|
||||||
|
|
||||||
|
// $4011反場ヽ趙仄卅中
|
||||||
|
ushort addr;
|
||||||
|
for (addr = 0x4000; addr <= 0x4010; addr++)
|
||||||
|
{
|
||||||
|
Write(addr, 0x00);
|
||||||
|
SyncWrite(addr, 0x00);
|
||||||
|
}
|
||||||
|
// Write( 0x4001, 0x08 ); // Reset媆反inc乒奈玉卞卅月?
|
||||||
|
// Write( 0x4005, 0x08 ); // Reset媆反inc乒奈玉卞卅月?
|
||||||
|
Write(0x4012, 0x00);
|
||||||
|
Write(0x4013, 0x00);
|
||||||
|
Write(0x4015, 0x00);
|
||||||
|
SyncWrite(0x4012, 0x00);
|
||||||
|
SyncWrite(0x4013, 0x00);
|
||||||
|
SyncWrite(0x4015, 0x00);
|
||||||
|
|
||||||
|
// $4017反𤩸五煋心匹場ヽ趙仄卅中(場ヽ乒奈玉互0匹丐月及毛ヽ渾仄凶末白玄互丐月鮋)
|
||||||
|
FrameIRQ = 0xC0;
|
||||||
|
FrameCycle = 0;
|
||||||
|
FrameIRQoccur = 0;
|
||||||
|
FrameCount = 0;
|
||||||
|
FrameType = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Setup(float fClock, int nRate)
|
public override void Setup(float fClock, int nRate)
|
||||||
{
|
{
|
||||||
//todo : 实现
|
cpu_clock = fClock;
|
||||||
|
sampling_rate = nRate;
|
||||||
|
|
||||||
|
cycle_rate = (int)(fClock * 65536.0f / nRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(ushort addr, byte data)
|
public override void Write(ushort addr, byte data)
|
||||||
{
|
{
|
||||||
//todo : 实现
|
switch (addr)
|
||||||
|
{
|
||||||
|
// CH0,1 rectangle
|
||||||
|
case 0x4000:
|
||||||
|
case 0x4001:
|
||||||
|
case 0x4002:
|
||||||
|
case 0x4003:
|
||||||
|
case 0x4004:
|
||||||
|
case 0x4005:
|
||||||
|
case 0x4006:
|
||||||
|
case 0x4007:
|
||||||
|
WriteRectangle((addr < 0x4004) ? 0 : 1, addr, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// CH2 triangle
|
||||||
|
case 0x4008:
|
||||||
|
case 0x4009:
|
||||||
|
case 0x400A:
|
||||||
|
case 0x400B:
|
||||||
|
WriteTriangle(addr, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// CH3 noise
|
||||||
|
case 0x400C:
|
||||||
|
case 0x400D:
|
||||||
|
case 0x400E:
|
||||||
|
case 0x400F:
|
||||||
|
WriteNoise(addr, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// CH4 DPCM
|
||||||
|
case 0x4010:
|
||||||
|
case 0x4011:
|
||||||
|
case 0x4012:
|
||||||
|
case 0x4013:
|
||||||
|
WriteDPCM(addr, data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4015:
|
||||||
|
reg4015 = data;
|
||||||
|
|
||||||
|
if ((data & (1 << 0)) == 0)
|
||||||
|
{
|
||||||
|
ch0.enable = 0;
|
||||||
|
ch0.len_count = 0;
|
||||||
|
}
|
||||||
|
if ((data & (1 << 1)) == 0)
|
||||||
|
{
|
||||||
|
ch1.enable = 0;
|
||||||
|
ch1.len_count = 0;
|
||||||
|
}
|
||||||
|
if ((data & (1 << 2)) == 0)
|
||||||
|
{
|
||||||
|
ch2.enable = 0;
|
||||||
|
ch2.len_count = 0;
|
||||||
|
ch2.lin_count = 0;
|
||||||
|
ch2.counter_start = 0;
|
||||||
|
}
|
||||||
|
if ((data & (1 << 3)) == 0)
|
||||||
|
{
|
||||||
|
ch3.enable = 0;
|
||||||
|
ch3.len_count = 0;
|
||||||
|
}
|
||||||
|
if ((data & (1 << 4)) == 0)
|
||||||
|
{
|
||||||
|
ch4.enable = 0;
|
||||||
|
ch4.dmalength = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch4.enable = 0xFF;
|
||||||
|
if (ch4.dmalength == 0)
|
||||||
|
{
|
||||||
|
ch4.address = ch4.cache_addr;
|
||||||
|
ch4.dmalength = ch4.cache_dmalength;
|
||||||
|
ch4.phaseacc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4017:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// VirtuaNES嘐衄禾奈玄
|
||||||
|
case 0x4018:
|
||||||
|
UpdateRectangle(ch0, data);
|
||||||
|
UpdateRectangle(ch1, data);
|
||||||
|
UpdateTriangle(data);
|
||||||
|
UpdateNoise(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateNoise(int type)
|
||||||
|
{
|
||||||
|
if (ch3.enable == 0 || ch3.len_count <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update Length
|
||||||
|
if (ch3.holdnote == 0)
|
||||||
|
{
|
||||||
|
// Holdnote
|
||||||
|
if ((type & 1) == 0 && ch3.len_count != 0)
|
||||||
|
{
|
||||||
|
ch3.len_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Envelope
|
||||||
|
if (ch3.env_count != 0)
|
||||||
|
{
|
||||||
|
ch3.env_count--;
|
||||||
|
}
|
||||||
|
if (ch3.env_count == 0)
|
||||||
|
{
|
||||||
|
ch3.env_count = ch3.env_decay;
|
||||||
|
|
||||||
|
// Holdnote
|
||||||
|
if (ch3.holdnote != 0)
|
||||||
|
{
|
||||||
|
ch3.env_vol = (ch3.env_vol - 1) & 0x0F;
|
||||||
|
}
|
||||||
|
else if (ch3.env_vol != 0)
|
||||||
|
{
|
||||||
|
ch3.env_vol--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch3.env_fixed == 0)
|
||||||
|
{
|
||||||
|
ch3.nowvolume = ch3.env_vol << RECTANGLE_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTriangle(int type)
|
||||||
|
{
|
||||||
|
if (ch2.enable == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((type & 1) == 0 && ch2.holdnote == 0)
|
||||||
|
{
|
||||||
|
if (ch2.len_count != 0)
|
||||||
|
{
|
||||||
|
ch2.len_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if( !ch2.len_count ) {
|
||||||
|
// ch2.lin_count = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Update Length/Linear
|
||||||
|
if (ch2.counter_start != 0)
|
||||||
|
{
|
||||||
|
ch2.lin_count = ch2.reg[0] & 0x7F;
|
||||||
|
}
|
||||||
|
else if (ch2.lin_count != 0)
|
||||||
|
{
|
||||||
|
ch2.lin_count--;
|
||||||
|
}
|
||||||
|
if (ch2.holdnote == 0 && ch2.lin_count != 0)
|
||||||
|
{
|
||||||
|
ch2.counter_start = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateRectangle(RECTANGLE ch, int type)
|
||||||
|
{
|
||||||
|
if (ch.enable == 0 || ch.len_count <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update Length/Sweep
|
||||||
|
if ((type & 1) == 0)
|
||||||
|
{
|
||||||
|
// Update Length
|
||||||
|
if (ch.len_count != 0 && ch.holdnote == 0)
|
||||||
|
{
|
||||||
|
// Holdnote
|
||||||
|
if (ch.len_count != 0)
|
||||||
|
{
|
||||||
|
ch.len_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Sweep
|
||||||
|
if (ch.swp_on != 0 && ch.swp_shift != 0)
|
||||||
|
{
|
||||||
|
if (ch.swp_count != 0)
|
||||||
|
{
|
||||||
|
ch.swp_count--;
|
||||||
|
}
|
||||||
|
if (ch.swp_count == 0)
|
||||||
|
{
|
||||||
|
ch.swp_count = ch.swp_decay;
|
||||||
|
if (ch.swp_inc != 0)
|
||||||
|
{
|
||||||
|
// Sweep increment(to higher frequency)
|
||||||
|
if (ch.complement == 0)
|
||||||
|
ch.freq += ~(ch.freq >> ch.swp_shift); // CH 0
|
||||||
|
else
|
||||||
|
ch.freq -= (ch.freq >> ch.swp_shift); // CH 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Sweep decrement(to lower frequency)
|
||||||
|
ch.freq += (ch.freq >> ch.swp_shift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Envelope
|
||||||
|
if (ch.env_count != 0)
|
||||||
|
{
|
||||||
|
ch.env_count--;
|
||||||
|
}
|
||||||
|
if (ch.env_count == 0)
|
||||||
|
{
|
||||||
|
ch.env_count = ch.env_decay;
|
||||||
|
|
||||||
|
// Holdnote
|
||||||
|
if (ch.holdnote != 0)
|
||||||
|
{
|
||||||
|
ch.env_vol = (ch.env_vol - 1) & 0x0F;
|
||||||
|
}
|
||||||
|
else if (ch.env_vol != 0)
|
||||||
|
{
|
||||||
|
ch.env_vol--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch.env_fixed == 0)
|
||||||
|
{
|
||||||
|
ch.nowvolume = ch.env_vol << RECTANGLE_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteDPCM(ushort addr, byte data)
|
||||||
|
{
|
||||||
|
ch4.reg[addr & 3] = data;
|
||||||
|
switch (addr & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ch4.freq = INT2FIX(nes.GetVideoMode() ? dpcm_cycles_pal[data & 0x0F] : dpcm_cycles[data & 0x0F]);
|
||||||
|
// ch4.freq = INT2FIX( dpcm_cycles[data&0x0F] );
|
||||||
|
//// ch4.freq = INT2FIX( (dpcm_cycles[data&0x0F]-((data&0x0F)^0x0F)*2-2) );
|
||||||
|
ch4.looping = (byte)(data & 0x40);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ch4.dpcm_value = (byte)((data & 0x7F) >> 1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ch4.cache_addr = (ushort)(0xC000 + (ushort)(data << 6));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ch4.cache_dmalength = ((data << 4) + 1) << 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteNoise(ushort addr, byte data)
|
||||||
|
{
|
||||||
|
ch3.reg[addr & 3] = data;
|
||||||
|
switch (addr & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ch3.holdnote = (byte)(data & 0x20);
|
||||||
|
ch3.volume = (byte)(data & 0x0F);
|
||||||
|
ch3.env_fixed = (byte)(data & 0x10);
|
||||||
|
ch3.env_decay = (byte)((data & 0x0F) + 1);
|
||||||
|
break;
|
||||||
|
case 1: // Unused
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ch3.freq = INT2FIX(noise_freq[data & 0x0F]);
|
||||||
|
ch3.xor_tap = (byte)((data & 0x80) != 0 ? 0x40 : 0x02);
|
||||||
|
break;
|
||||||
|
case 3: // Master
|
||||||
|
ch3.len_count = vbl_length[data >> 3] * 2;
|
||||||
|
ch3.env_vol = 0x0F;
|
||||||
|
ch3.env_count = (byte)(ch3.env_decay + 1);
|
||||||
|
|
||||||
|
if ((reg4015 & (1 << 3)) != 0)
|
||||||
|
ch3.enable = 0xFF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteTriangle(ushort addr, byte data)
|
||||||
|
{
|
||||||
|
ch2.reg[addr & 3] = data;
|
||||||
|
switch (addr & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ch2.holdnote = (byte)(data & 0x80);
|
||||||
|
break;
|
||||||
|
case 1: // Unused
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ch2.freq = INT2FIX(((ch2.reg[3] & 0x07) << 8) + data + 1);
|
||||||
|
break;
|
||||||
|
case 3: // Master
|
||||||
|
ch2.freq = INT2FIX((((data & 0x07) << 8) + ch2.reg[2] + 1));
|
||||||
|
ch2.len_count = vbl_length[data >> 3] * 2;
|
||||||
|
ch2.counter_start = 0x80;
|
||||||
|
|
||||||
|
if ((reg4015 & (1 << 2)) != 0)
|
||||||
|
ch2.enable = 0xFF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteRectangle(int no, ushort addr, byte data)
|
||||||
|
{
|
||||||
|
RECTANGLE ch = (no == 0) ? ch0 : ch1;
|
||||||
|
|
||||||
|
ch.reg[addr & 3] = data;
|
||||||
|
switch (addr & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ch.holdnote = (byte)(data & 0x20);
|
||||||
|
ch.volume = (byte)(data & 0x0F);
|
||||||
|
ch.env_fixed = (byte)(data & 0x10);
|
||||||
|
ch.env_decay = (byte)((data & 0x0F) + 1);
|
||||||
|
ch.duty = duty_lut[data >> 6];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ch.swp_on = (byte)(data & 0x80);
|
||||||
|
ch.swp_inc = (byte)(data & 0x08);
|
||||||
|
ch.swp_shift = (byte)(data & 0x07);
|
||||||
|
ch.swp_decay = (byte)(((data >> 4) & 0x07) + 1);
|
||||||
|
ch.freqlimit = freq_limit[data & 0x07];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ch.freq = (ch.freq & (~0xFF)) + data;
|
||||||
|
break;
|
||||||
|
case 3: // Master
|
||||||
|
ch.freq = ((data & 0x07) << 8) + (ch.freq & 0xFF);
|
||||||
|
ch.len_count = vbl_length[data >> 3] * 2;
|
||||||
|
ch.env_vol = 0x0F;
|
||||||
|
ch.env_count = (byte)(ch.env_decay + 1);
|
||||||
|
ch.adder = 0;
|
||||||
|
|
||||||
|
if ((reg4015 & (1 << no)) != 0)
|
||||||
|
ch.enable = 0xFF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Process(int channel)
|
public override int Process(int channel)
|
||||||
{
|
{
|
||||||
//todo : 实现
|
switch (channel)
|
||||||
return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return RenderRectangle(ch0);
|
||||||
|
case 1:
|
||||||
|
return RenderRectangle(ch1);
|
||||||
|
case 2:
|
||||||
|
return RenderTriangle();
|
||||||
|
case 3:
|
||||||
|
return RenderNoise();
|
||||||
|
case 4:
|
||||||
|
return RenderDPCM();
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RenderDPCM()
|
||||||
|
{
|
||||||
|
if (ch4.dmalength != 0)
|
||||||
|
{
|
||||||
|
ch4.phaseacc -= cycle_rate;
|
||||||
|
|
||||||
|
while (ch4.phaseacc < 0)
|
||||||
|
{
|
||||||
|
ch4.phaseacc += ch4.freq;
|
||||||
|
if ((ch4.dmalength & 7) == 0)
|
||||||
|
{
|
||||||
|
ch4.cur_byte = nes.Read(ch4.address);
|
||||||
|
if (0xFFFF == ch4.address)
|
||||||
|
ch4.address = 0x8000;
|
||||||
|
else
|
||||||
|
ch4.address++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((--ch4.dmalength) == 0)
|
||||||
|
{
|
||||||
|
if (ch4.looping != 0)
|
||||||
|
{
|
||||||
|
ch4.address = ch4.cache_addr;
|
||||||
|
ch4.dmalength = ch4.cache_dmalength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch4.enable = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// positive delta
|
||||||
|
if ((ch4.cur_byte & (1 << ((ch4.dmalength & 7) ^ 7))) != 0)
|
||||||
|
{
|
||||||
|
if (ch4.dpcm_value < 0x3F)
|
||||||
|
ch4.dpcm_value += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// negative delta
|
||||||
|
if (ch4.dpcm_value > 1)
|
||||||
|
ch4.dpcm_value -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 奶件民平堪中皿民用奶朮市永玄(TEST)
|
||||||
|
ch4.dpcm_output_real = ((ch4.reg[1] & 0x01) + ch4.dpcm_value * 2) - 0x40;
|
||||||
|
if (Math.Abs(ch4.dpcm_output_real - ch4.dpcm_output_fake) <= 8)
|
||||||
|
{
|
||||||
|
ch4.dpcm_output_fake = ch4.dpcm_output_real;
|
||||||
|
ch4.output = ch4.dpcm_output_real << DPCM_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ch4.dpcm_output_real > ch4.dpcm_output_fake)
|
||||||
|
ch4.dpcm_output_fake += 8;
|
||||||
|
else
|
||||||
|
ch4.dpcm_output_fake -= 8;
|
||||||
|
ch4.output = ch4.dpcm_output_fake << DPCM_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
return ch4.output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RenderNoise()
|
||||||
|
{
|
||||||
|
if (ch3.enable == 0 || ch3.len_count <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ch3.env_fixed != 0)
|
||||||
|
{
|
||||||
|
ch3.nowvolume = ch3.volume << RECTANGLE_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vol = 256 - ((ch4.reg[1] & 0x01) + ch4.dpcm_value * 2);
|
||||||
|
|
||||||
|
ch3.phaseacc -= cycle_rate;
|
||||||
|
if (ch3.phaseacc >= 0)
|
||||||
|
return ch3.output * vol / 256;
|
||||||
|
|
||||||
|
if (ch3.freq > cycle_rate)
|
||||||
|
{
|
||||||
|
ch3.phaseacc += ch3.freq;
|
||||||
|
if (NoiseShiftreg(ch3.xor_tap))
|
||||||
|
ch3.output = ch3.nowvolume;
|
||||||
|
else
|
||||||
|
ch3.output = -ch3.nowvolume;
|
||||||
|
|
||||||
|
return ch3.output * vol / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_times, total;
|
||||||
|
num_times = total = 0;
|
||||||
|
while (ch3.phaseacc < 0)
|
||||||
|
{
|
||||||
|
ch3.phaseacc += ch3.freq;
|
||||||
|
if (NoiseShiftreg(ch3.xor_tap))
|
||||||
|
ch3.output = ch3.nowvolume;
|
||||||
|
else
|
||||||
|
ch3.output = -ch3.nowvolume;
|
||||||
|
|
||||||
|
total += ch3.output;
|
||||||
|
num_times++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (total / num_times) * vol / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool NoiseShiftreg(byte xor_tap)
|
||||||
|
{
|
||||||
|
int bit0, bit14;
|
||||||
|
|
||||||
|
bit0 = ch3.shift_reg & 1;
|
||||||
|
if ((ch3.shift_reg & xor_tap) != 0) bit14 = bit0 ^ 1;
|
||||||
|
else bit14 = bit0 ^ 0;
|
||||||
|
ch3.shift_reg >>= 1;
|
||||||
|
ch3.shift_reg |= (bit14 << 14);
|
||||||
|
return (bit0 ^ 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RenderTriangle()
|
||||||
|
{
|
||||||
|
int vol;
|
||||||
|
if (Supporter.Config.sound.bDisableVolumeEffect)
|
||||||
|
{
|
||||||
|
vol = 256;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vol = 256 - ((ch4.reg[1] & 0x01) + ch4.dpcm_value * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch2.enable == 0 || (ch2.len_count <= 0) || (ch2.lin_count <= 0))
|
||||||
|
{
|
||||||
|
return ch2.nowvolume * vol / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch2.freq < INT2FIX(8))
|
||||||
|
{
|
||||||
|
return ch2.nowvolume * vol / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Supporter.Config.sound.bChangeTone && ChannelTone[2, 0] != 0))
|
||||||
|
{
|
||||||
|
ch2.phaseacc -= cycle_rate;
|
||||||
|
if (ch2.phaseacc >= 0)
|
||||||
|
{
|
||||||
|
return ch2.nowvolume * vol / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch2.freq > cycle_rate)
|
||||||
|
{
|
||||||
|
ch2.phaseacc += ch2.freq;
|
||||||
|
ch2.adder = (ch2.adder + 1) & 0x1F;
|
||||||
|
|
||||||
|
if (ch2.adder < 0x10)
|
||||||
|
{
|
||||||
|
ch2.nowvolume = (ch2.adder & 0x0F) << TRIANGLE_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch2.nowvolume = (0x0F - (ch2.adder & 0x0F)) << TRIANGLE_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ch2.nowvolume * vol / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 樓笭ⅸ歙
|
||||||
|
int num_times, total;
|
||||||
|
num_times = total = 0;
|
||||||
|
while (ch2.phaseacc < 0)
|
||||||
|
{
|
||||||
|
ch2.phaseacc += ch2.freq;
|
||||||
|
ch2.adder = (ch2.adder + 1) & 0x1F;
|
||||||
|
|
||||||
|
if (ch2.adder < 0x10)
|
||||||
|
{
|
||||||
|
ch2.nowvolume = (ch2.adder & 0x0F) << TRIANGLE_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch2.nowvolume = (0x0F - (ch2.adder & 0x0F)) << TRIANGLE_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
total += ch2.nowvolume;
|
||||||
|
num_times++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (total / num_times) * vol / 256;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int x = ChannelTone[2, 0] - 1;
|
||||||
|
int pTone = 0;
|
||||||
|
|
||||||
|
ch2.phaseacc -= cycle_rate;
|
||||||
|
if (ch2.phaseacc >= 0)
|
||||||
|
{
|
||||||
|
return ch2.nowvolume * vol / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch2.freq > cycle_rate)
|
||||||
|
{
|
||||||
|
ch2.phaseacc += ch2.freq;
|
||||||
|
ch2.adder = (ch2.adder + 1) & 0x1F;
|
||||||
|
var temp = ToneTable[x, pTone + (ch2.adder & 0x1F)];
|
||||||
|
ch2.nowvolume = temp * 0x0F;
|
||||||
|
return ch2.nowvolume * vol / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 樓笭ⅸ歙
|
||||||
|
int num_times, total;
|
||||||
|
num_times = total = 0;
|
||||||
|
while (ch2.phaseacc < 0)
|
||||||
|
{
|
||||||
|
ch2.phaseacc += ch2.freq;
|
||||||
|
ch2.adder = (ch2.adder + 1) & 0x1F;
|
||||||
|
var temp = ToneTable[x, pTone + (ch2.adder & 0x1F)];
|
||||||
|
total += temp * 0x0F;
|
||||||
|
num_times++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (total / num_times) * vol / 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int RenderRectangle(RECTANGLE ch)
|
||||||
|
{
|
||||||
|
if (ch.enable == 0 || ch.len_count <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Channel disable?
|
||||||
|
if ((ch.freq < 8) || (ch.swp_inc == 0 && ch.freq > ch.freqlimit))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch.env_fixed != 0)
|
||||||
|
{
|
||||||
|
ch.nowvolume = ch.volume << RECTANGLE_VOL_SHIFT;
|
||||||
|
}
|
||||||
|
int volume = ch.nowvolume;
|
||||||
|
|
||||||
|
if (!(Supporter.Config.sound.bChangeTone && (ChannelTone[(ch.complement == 0) ? 0 : 1, ch.reg[0] >> 6]) != 0))
|
||||||
|
{
|
||||||
|
// 娗嶲<E5A897>燴
|
||||||
|
double total;
|
||||||
|
double sample_weight = ch.phaseacc;
|
||||||
|
if (sample_weight > cycle_rate)
|
||||||
|
{
|
||||||
|
sample_weight = cycle_rate;
|
||||||
|
}
|
||||||
|
total = (ch.adder < ch.duty) ? sample_weight : -sample_weight;
|
||||||
|
|
||||||
|
int freq = INT2FIX(ch.freq + 1);
|
||||||
|
ch.phaseacc -= cycle_rate;
|
||||||
|
while (ch.phaseacc < 0)
|
||||||
|
{
|
||||||
|
ch.phaseacc += freq;
|
||||||
|
ch.adder = (ch.adder + 1) & 0x0F;
|
||||||
|
|
||||||
|
sample_weight = freq;
|
||||||
|
if (ch.phaseacc > 0)
|
||||||
|
{
|
||||||
|
sample_weight -= ch.phaseacc;
|
||||||
|
}
|
||||||
|
total += (ch.adder < ch.duty) ? sample_weight : -sample_weight;
|
||||||
|
}
|
||||||
|
return (int)(volume * total / cycle_rate + 0.5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int x = ChannelTone[(ch.complement == 0) ? 0 : 1, ch.reg[0] >> 6] - 1;
|
||||||
|
int pTone = 0;
|
||||||
|
|
||||||
|
// 載陔剠仄
|
||||||
|
ch.phaseacc -= cycle_rate * 2;
|
||||||
|
if (ch.phaseacc >= 0)
|
||||||
|
{
|
||||||
|
var temp = ToneTable[x, pTone + (ch.adder & 0x1F)];
|
||||||
|
return temp * volume / ((1 << RECTANGLE_VOL_SHIFT) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1旦氾永皿分仃載陔
|
||||||
|
int freq = INT2FIX(ch.freq + 1);
|
||||||
|
if (freq > cycle_rate * 2)
|
||||||
|
{
|
||||||
|
ch.phaseacc += freq;
|
||||||
|
ch.adder = (ch.adder + 1) & 0x1F;
|
||||||
|
var temp = ToneTable[x, pTone + (ch.adder & 0x1F)];
|
||||||
|
return temp * volume / ((1 << RECTANGLE_VOL_SHIFT) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 樓笭ⅸ歙
|
||||||
|
int num_times, total;
|
||||||
|
num_times = total = 0;
|
||||||
|
while (ch.phaseacc < 0)
|
||||||
|
{
|
||||||
|
ch.phaseacc += freq;
|
||||||
|
ch.adder = (ch.adder + 1) & 0x1F;
|
||||||
|
var temp = ToneTable[x, pTone + (ch.adder & 0x1F)];
|
||||||
|
total += temp * volume / ((1 << RECTANGLE_VOL_SHIFT) / 2);
|
||||||
|
num_times++;
|
||||||
|
}
|
||||||
|
return total / num_times;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal byte SyncRead(ushort addr)
|
internal byte SyncRead(ushort addr)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
public int phaseacc;
|
public int phaseacc;
|
||||||
public int output;
|
public int output;
|
||||||
|
|
||||||
ushort address, cache_addr;
|
public ushort address, cache_addr;
|
||||||
public int dmalength, cache_dmalength;
|
public int dmalength, cache_dmalength;
|
||||||
public int dpcm_output_real, dpcm_output_fake, dpcm_output_old, dpcm_output_offset;
|
public int dpcm_output_real, dpcm_output_fake, dpcm_output_old, dpcm_output_offset;
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace VirtualNes.Core
|
using System;
|
||||||
|
|
||||||
|
namespace VirtualNes.Core
|
||||||
{
|
{
|
||||||
public class NOISE
|
public class NOISE
|
||||||
{
|
{
|
||||||
@ -32,5 +34,35 @@
|
|||||||
public byte sync_holdnote;
|
public byte sync_holdnote;
|
||||||
public byte dummy1;
|
public byte dummy1;
|
||||||
public int sync_len_count;
|
public int sync_len_count;
|
||||||
|
|
||||||
|
internal void ZeroMemory()
|
||||||
|
{
|
||||||
|
Array.Clear(reg, 0, reg.Length);
|
||||||
|
|
||||||
|
enable = 0;
|
||||||
|
holdnote = 0;
|
||||||
|
volume = 0;
|
||||||
|
xor_tap = 0;
|
||||||
|
shift_reg = 0;
|
||||||
|
|
||||||
|
phaseacc = 0;
|
||||||
|
freq = 0;
|
||||||
|
len_count = 0;
|
||||||
|
nowvolume = 0;
|
||||||
|
output = 0;
|
||||||
|
|
||||||
|
env_fixed = 0;
|
||||||
|
env_decay = 0;
|
||||||
|
env_count = 0;
|
||||||
|
dummy0 = 0;
|
||||||
|
env_vol = 0;
|
||||||
|
|
||||||
|
Array.Clear(sync_reg, 0, sync_reg.Length);
|
||||||
|
sync_output_enable = 0;
|
||||||
|
sync_enable = 0;
|
||||||
|
sync_holdnote = 0;
|
||||||
|
dummy1 = 0;
|
||||||
|
sync_len_count = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace VirtualNes.Core
|
using System;
|
||||||
|
|
||||||
|
namespace VirtualNes.Core
|
||||||
{
|
{
|
||||||
public class TRIANGLE
|
public class TRIANGLE
|
||||||
{
|
{
|
||||||
@ -25,5 +27,28 @@
|
|||||||
// public byte dummy1;
|
// public byte dummy1;
|
||||||
public int sync_len_count;
|
public int sync_len_count;
|
||||||
public int sync_lin_count;
|
public int sync_lin_count;
|
||||||
|
|
||||||
|
internal void ZeroMemory()
|
||||||
|
{
|
||||||
|
Array.Clear(reg, 0, reg.Length);
|
||||||
|
|
||||||
|
enable = 0;
|
||||||
|
holdnote = 0;
|
||||||
|
counter_start = 0;
|
||||||
|
dummy0 = 0;
|
||||||
|
phaseacc = 0;
|
||||||
|
freq = 0;
|
||||||
|
len_count = 0;
|
||||||
|
lin_count = 0;
|
||||||
|
adder = 0;
|
||||||
|
nowvolume = 0;
|
||||||
|
Array.Clear(sync_reg, 0, sync_reg.Length);
|
||||||
|
sync_enable = 0;
|
||||||
|
sync_holdnote = 0;
|
||||||
|
sync_counter_start = 0;
|
||||||
|
|
||||||
|
sync_len_count = 0;
|
||||||
|
sync_lin_count = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace VirtualNes.Core
|
|||||||
private APU apu;
|
private APU apu;
|
||||||
internal R6502 R = new R6502();
|
internal R6502 R = new R6502();
|
||||||
private byte[] ZN_Table = new byte[256];
|
private byte[] ZN_Table = new byte[256];
|
||||||
private Memory<byte> STACK;
|
private ByteArrayRef STACK;
|
||||||
|
|
||||||
public CPU(NES parent)
|
public CPU(NES parent)
|
||||||
{
|
{
|
||||||
@ -1361,12 +1361,12 @@ namespace VirtualNes.Core
|
|||||||
|
|
||||||
private byte POP()
|
private byte POP()
|
||||||
{
|
{
|
||||||
return STACK.Span[(++R.S) & 0xFF];
|
return STACK[(++R.S) & 0xFF];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PUSH(byte V)
|
private void PUSH(byte V)
|
||||||
{
|
{
|
||||||
STACK.Span[(R.S--) & 0xFF] = V;
|
STACK[(R.S--) & 0xFF] = V;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SEI()
|
private void SEI()
|
||||||
@ -2010,7 +2010,7 @@ namespace VirtualNes.Core
|
|||||||
DMA_cycles = 0;
|
DMA_cycles = 0;
|
||||||
|
|
||||||
// STACK quick access
|
// STACK quick access
|
||||||
STACK = new Memory<byte>(MMU.RAM, 0x0100, MMU.RAM.Length - 0x100);
|
STACK = new ByteArrayRef(MMU.RAM, 0x0100, MMU.RAM.Length - 0x100);
|
||||||
|
|
||||||
// Zero/Negative FLAG
|
// Zero/Negative FLAG
|
||||||
ZN_Table[0] = Z_FLAG;
|
ZN_Table[0] = Z_FLAG;
|
||||||
|
@ -6,7 +6,23 @@
|
|||||||
private int m_offset;
|
private int m_offset;
|
||||||
private int m_length;
|
private int m_length;
|
||||||
|
|
||||||
|
public int Offset
|
||||||
|
{
|
||||||
|
get => m_offset;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var gap = value - m_offset;
|
||||||
|
m_length -= gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteArrayRef() { }
|
||||||
public ByteArrayRef(byte[] array, int offset, int length)
|
public ByteArrayRef(byte[] array, int offset, int length)
|
||||||
|
{
|
||||||
|
SetArray(array, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetArray(byte[] array, int offset, int length)
|
||||||
{
|
{
|
||||||
m_rawArray = array;
|
m_rawArray = array;
|
||||||
m_offset = offset;
|
m_offset = offset;
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace VirtualNes.Core
|
||||||
|
{
|
||||||
|
public interface ISoundDataBuffer
|
||||||
|
{
|
||||||
|
void WriteByte(byte value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4585a754599519b48bfe50294600818f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -9,6 +9,10 @@ namespace VirtualNes.Core
|
|||||||
{
|
{
|
||||||
Array.Clear(array, 0, array.Length);
|
Array.Clear(array, 0, array.Length);
|
||||||
}
|
}
|
||||||
|
public static void ZEROMEMORY(int[] array, int length)
|
||||||
|
{
|
||||||
|
Array.Clear(array, 0, array.Length);
|
||||||
|
}
|
||||||
|
|
||||||
public static void memset(byte[] array, byte value, int length)
|
public static void memset(byte[] array, byte value, int length)
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
public class CfgSound
|
public class CfgSound
|
||||||
{
|
{
|
||||||
public bool bEnable { get; set; } = true;
|
public bool bEnable { get; set; } = true;
|
||||||
public int nRate { get; set; } = 22050;
|
public int nRate { get; set; } = 48000;
|
||||||
public int nBits { get; set; } = 8;
|
public int nBits { get; set; } = 8;
|
||||||
public int nBufferSize { get; set; } = 4;
|
public int nBufferSize { get; set; } = 4;
|
||||||
public int nFilterType { get; set; } = 0;
|
public int nFilterType { get; set; } = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user