Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
StreamingSound.cs
浏览该文件的文档.
1using System.Runtime.InteropServices;
2using Engine.Media;
3#if BROWSER
4using SourceInteger = Engine.Browser.AL.SourceInteger;
5using GetSourceInteger = Engine.Browser.AL.GetSourceInteger;
6using BufferFormat = Engine.Browser.AL.BufferFormat;
7using SourceVector3 = Engine.Browser.AL.SourceVector3;
8using SourceState = Engine.Browser.AL.SourceState;
9#else
10using Silk.NET.OpenAL;
11#endif
12
13namespace Engine.Audio {
14 public class StreamingSound : BaseSound {
15 Task m_task;
16 ManualResetEvent m_stopTaskEvent = new(false);
17
19 public readonly float m_bufferDuration;
20
21 public StreamingSource StreamingSource { get; set; }
22
23 public int ReadStreamingSource(byte[] buffer, int count) {
24 int num = 0;
25 if (StreamingSource.BytesCount > 0) {
26 while (count > 0) {
27 int num2 = StreamingSource.Read(buffer, num, count);
28 if (num2 > 0) {
29 num += num2;
30 count -= num2;
31 continue;
32 }
33 if (!m_isLooped) {
34 break;
35 }
37 }
38 }
39 return num;
40 }
41
42 void VerifyStreamingSource(StreamingSource streamingSource) {
43 ArgumentNullException.ThrowIfNull(streamingSource);
44 if (streamingSource.ChannelsCount < 1
45 || streamingSource.ChannelsCount > 2) {
46 throw new InvalidOperationException("Unsupported channels count.");
47 }
48 if (streamingSource.SamplingFrequency < 8000
49 || streamingSource.SamplingFrequency > 192000) {
50 throw new InvalidOperationException("Unsupported frequency.");
51 }
52 }
53
54 public StreamingSound(StreamingSource streamingSource,
55 float volume = 1f,
56 float pitch = 1f,
57 float pan = 0f,
58 bool isLooped = false,
59 bool disposeOnStop = false,
60 float bufferDuration = 0.3f) {
61 VerifyStreamingSource(streamingSource);
62 StreamingSource = streamingSource;
63 ChannelsCount = streamingSource.ChannelsCount;
64 SamplingFrequency = streamingSource.SamplingFrequency;
65 Volume = volume;
66 Pitch = pitch;
67 Pan = pan;
68 IsLooped = isLooped;
69 DisposeOnStop = disposeOnStop;
70 m_bufferDuration = Math.Clamp(bufferDuration, 0.01f, 10f);
71 if (m_source == 0) {
72 return;
73 }
74 m_task = Task.Run(
75 delegate {
76 try {
78 }
79 catch (Exception message) {
80 Log.Error(message);
81 }
82 }
83 );
84 }
85
86 internal override void InternalPlay(Vector3 direction) {
87 if (m_source != 0) {
88 uint source = (uint)m_source;
89 Mixer.AL.SetSourceProperty(source, SourceVector3.Position, direction.X, direction.Y, direction.Z);
90 Mixer.AL.SourcePlay(source);
92 }
93 }
94
95 internal override void InternalPause() {
96 if (m_source != 0) {
97 Mixer.AL.SourcePause((uint)m_source);
99 }
100 }
101
102 internal override void InternalStop() {
103 if (m_source != 0) {
104 Mixer.AL.SourceStop((uint)m_source);
107 lock (m_lock) {
108 m_noMoreData = false;
109 }
110 }
111 }
112
113 internal override void InternalDispose() {
114 if (m_stopTaskEvent != null
115 && m_task != null) {
116 m_stopTaskEvent.Set();
117 m_task.Wait();
118 m_task = null;
119 m_stopTaskEvent.Dispose();
120 m_stopTaskEvent = null;
121 }
122 if (StreamingSource != null) {
123 StreamingSource.Dispose();
124 StreamingSource = null;
125 }
126 base.InternalDispose();
127 }
128
130 uint[] array = new uint[3];
131 List<uint> list = new();
132 int millisecondsTimeout = Math.Clamp((int)(0.5f * m_bufferDuration / array.Length * 1000f), 1, 100);
133 byte[] array2 = new byte[2 * ChannelsCount * (int)(SamplingFrequency * m_bufferDuration / array.Length)];
134 for (int i = 0; i < array.Length; i++) {
135 uint num = Mixer.AL.GenBuffer();
137 array[i] = num;
138 list.Add(num);
139 }
140 uint source = (uint)m_source;
141 do {
142 lock (m_lock) {
143 if (!m_noMoreData) {
144 Mixer.AL.GetSourceProperty(source, GetSourceInteger.BuffersProcessed, out int value);
146 for (int j = 0; j < value; j++) {
147 uint item = 0u;
148 Mixer.AL.SourceUnqueueBuffers(source, 1, &item);
150 list.Add(item);
151 }
152 if (list.Count > 0
153 && !m_noMoreData
154 && State == SoundState.Playing) {
155 int num2 = ReadStreamingSource(array2, array2.Length);
156 m_noMoreData = num2 < array2.Length;
157 if (num2 > 0) {
158 uint num3 = list[^1];
159 GCHandle gCHandle = GCHandle.Alloc(array2, GCHandleType.Pinned);
160 Mixer.AL.BufferData(
161 num3,
162 ChannelsCount == 1 ? BufferFormat.Mono16 : BufferFormat.Stereo16,
163 gCHandle.AddrOfPinnedObject().ToPointer(),
164 num2,
166 );
168 Mixer.AL.SourceQueueBuffers(source, 1, &num3);
170 list.RemoveAt(list.Count - 1);
171 Mixer.AL.GetSourceProperty(source, GetSourceInteger.SourceState, out int sourceState);
173 if (sourceState != (int)SourceState.Playing) {
174 Mixer.AL.SourcePlay(source);
176 }
177 }
178 }
179 }
180 else {
181 Mixer.AL.GetSourceProperty(source, GetSourceInteger.SourceState, out int sourceState);
182 if (sourceState == (int)SourceState.Stopped) {
183 Dispatcher.Dispatch(delegate { Stop(); });
184 }
185 }
186 }
187 }
188 while (!m_stopTaskEvent.WaitOne(millisecondsTimeout));
189 Mixer.AL.SourceStop(source);
191 Mixer.AL.SetSourceProperty(source, SourceInteger.Buffer, 0);
193 for (int k = 0; k < array.Length; k++) {
194 if (array[k] != 0) {
195 Mixer.AL.DeleteBuffer(array[k]);
197 array[k] = 0;
198 }
199 }
200 }
201 }
202}
unsafe
定义 Main.cs:15
static AudioError CheckALError()
StreamingSound(StreamingSource streamingSource, float volume=1f, float pitch=1f, float pan=0f, bool isLooped=false, bool disposeOnStop=false, float bufferDuration=0.3f)
override void InternalPlay(Vector3 direction)
int ReadStreamingSource(byte[] buffer, int count)
void VerifyStreamingSource(StreamingSource streamingSource)
static void Dispatch(Action action, bool waitUntilCompleted=false)
static void Error(object message)
定义 Log.cs:80