-
-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathSoundBuffer.cs
287 lines (254 loc) · 12.2 KB
/
SoundBuffer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using SFML.System;
namespace SFML.Audio
{
////////////////////////////////////////////////////////////
/// <summary>
/// Storage for audio samples defining a sound
/// </summary>
////////////////////////////////////////////////////////////
public class SoundBuffer : ObjectBase
{
////////////////////////////////////////////////////////////
/// <summary>
/// Construct a sound buffer from a file
///
/// Here is a complete list of all the supported audio formats:
/// ogg, wav, flac, mp3, aiff, au, raw, paf, svx, nist, voc, ircam,
/// w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
/// </summary>
/// <param name="filename">Path of the sound file to load</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public SoundBuffer(string filename) :
base(sfSoundBuffer_createFromFile(filename))
{
if (IsInvalid)
{
throw new LoadingFailedException("sound buffer", filename);
}
}
////////////////////////////////////////////////////////////
/// <summary>
/// Construct a sound buffer from a custom stream.
///
/// Here is a complete list of all the supported audio formats:
/// ogg, wav, flac, mp3, aiff, au, raw, paf, svx, nist, voc, ircam,
/// w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
/// </summary>
/// <param name="stream">Source stream to read from</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public SoundBuffer(Stream stream) :
base(IntPtr.Zero)
{
using (var adaptor = new StreamAdaptor(stream))
{
CPointer = sfSoundBuffer_createFromStream(adaptor.InputStreamPtr);
}
if (IsInvalid)
{
throw new LoadingFailedException("sound buffer");
}
}
////////////////////////////////////////////////////////////
/// <summary>
/// Construct a sound buffer from a file in memory.
///
/// Here is a complete list of all the supported audio formats:
/// ogg, wav, flac, mp3, aiff, au, raw, paf, svx, nist, voc, ircam,
/// w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
/// </summary>
/// <param name="bytes">Byte array containing the file contents</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public SoundBuffer(ReadOnlySpan<byte> bytes) :
base(IntPtr.Zero)
{
unsafe
{
fixed (void* ptr = bytes)
{
CPointer = sfSoundBuffer_createFromMemory((IntPtr)ptr, (UIntPtr)bytes.Length);
}
}
if (IsInvalid)
{
throw new LoadingFailedException("sound buffer");
}
}
////////////////////////////////////////////////////////////
/// <summary>
/// Construct a sound buffer from an array of samples
/// </summary>
/// <param name="samples">Array of samples</param>
/// <param name="channelCount">Channel count</param>
/// <param name="sampleRate">Sample rate</param>
/// <param name="channelMapData">Map of position in sample frame to sound channel</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public SoundBuffer(ReadOnlySpan<short> samples, uint channelCount, uint sampleRate, ReadOnlySpan<SoundChannel> channelMapData) :
base(IntPtr.Zero)
{
unsafe
{
fixed (short* samplesPtr = samples)
{
fixed (SoundChannel* channels = channelMapData)
{
CPointer = sfSoundBuffer_createFromSamples(samplesPtr, (uint)samples.Length, channelCount, sampleRate, channels, (UIntPtr)channelMapData.Length);
}
}
}
if (IsInvalid)
{
throw new LoadingFailedException("sound buffer");
}
}
////////////////////////////////////////////////////////////
/// <summary>
/// Construct a sound buffer from another sound buffer
/// </summary>
/// <param name="copy">Sound buffer to copy</param>
////////////////////////////////////////////////////////////
public SoundBuffer(SoundBuffer copy) :
base(sfSoundBuffer_copy(copy.CPointer))
{
}
////////////////////////////////////////////////////////////
/// <summary>
/// Save the sound buffer to an audio file.
///
/// Here is a complete list of all the supported audio formats:
/// ogg, wav, flac, mp3, aiff, au, raw, paf, svx, nist, voc, ircam,
/// w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
/// </summary>
/// <param name="filename">Path of the sound file to write</param>
/// <returns>True if saving has been successful</returns>
////////////////////////////////////////////////////////////
public bool SaveToFile(string filename) => sfSoundBuffer_saveToFile(CPointer, filename);
////////////////////////////////////////////////////////////
/// <summary>
/// Sample rate of the sound buffer.
///
/// The sample rate is the number of audio samples played per
/// second. The higher, the better the quality.
/// </summary>
////////////////////////////////////////////////////////////
public uint SampleRate => sfSoundBuffer_getSampleRate(CPointer);
////////////////////////////////////////////////////////////
/// <summary>
/// Number of channels (1 = mono, 2 = stereo)
/// </summary>
////////////////////////////////////////////////////////////
public uint ChannelCount => sfSoundBuffer_getChannelCount(CPointer);
////////////////////////////////////////////////////////////
/// <summary>
/// Total duration of the buffer
/// </summary>
////////////////////////////////////////////////////////////
public Time Duration => sfSoundBuffer_getDuration(CPointer);
////////////////////////////////////////////////////////////
/// <summary>
/// Array of audio samples stored in the buffer.
///
/// The format of the returned samples is 16 bits signed integer
/// (sf::Int16).
/// </summary>
////////////////////////////////////////////////////////////
public ReadOnlySpan<short> Samples
{
get
{
unsafe
{
// Sample array should remain constant and not get invalidated as a result
var samplesCount = sfSoundBuffer_getSampleCount(CPointer);
var samples = sfSoundBuffer_getSamples(CPointer);
return new ReadOnlySpan<short>(samples.ToPointer(), (int)samplesCount);
}
}
}
////////////////////////////////////////////////////////////
/// <summary>
/// Get the map of position in sample frame to sound channel
/// <para/>
/// This is used to map a sample in the sample stream to a
/// position during spatialisation.
/// </summary>
////////////////////////////////////////////////////////////
public virtual ReadOnlySpan<SoundChannel> ChannelMap
{
get
{
unsafe
{
var channels = sfSoundBuffer_getChannelMap(CPointer, out var count);
Array.Resize(ref _channels, (int)count);
for (var i = 0; i < _channels.Length; i++)
{
_channels[i] = channels[i];
}
return _channels;
}
}
}
////////////////////////////////////////////////////////////
/// <summary>
/// Provide a string describing the object
/// </summary>
/// <returns>String description of the object</returns>
////////////////////////////////////////////////////////////
public override string ToString()
{
if (IsInvalid)
{
return MakeDisposedObjectString();
}
return "[SoundBuffer]" +
" SampleRate(" + SampleRate + ")" +
" ChannelCount(" + ChannelCount + ")" +
" Duration(" + Duration + ")";
}
////////////////////////////////////////////////////////////
/// <summary>
/// Handle the destruction of the object
/// </summary>
/// <param name="disposing">Is the GC disposing the object, or is it an explicit call ?</param>
////////////////////////////////////////////////////////////
protected override void Destroy(bool disposing) => sfSoundBuffer_destroy(CPointer);
private SoundChannel[] _channels;
#region Imports
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern IntPtr sfSoundBuffer_createFromFile(string filename);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern unsafe IntPtr sfSoundBuffer_createFromStream(IntPtr stream);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern unsafe IntPtr sfSoundBuffer_createFromMemory(IntPtr data, UIntPtr size);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern unsafe IntPtr sfSoundBuffer_createFromSamples(short* samples, ulong sampleCount, uint channelsCount, uint sampleRate, SoundChannel* channelMapData, UIntPtr channelMapSize);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern IntPtr sfSoundBuffer_copy(IntPtr soundBuffer);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern void sfSoundBuffer_destroy(IntPtr soundBuffer);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool sfSoundBuffer_saveToFile(IntPtr soundBuffer, string filename);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern IntPtr sfSoundBuffer_getSamples(IntPtr soundBuffer);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern ulong sfSoundBuffer_getSampleCount(IntPtr soundBuffer);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern uint sfSoundBuffer_getSampleRate(IntPtr soundBuffer);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern uint sfSoundBuffer_getChannelCount(IntPtr soundBuffer);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern unsafe SoundChannel* sfSoundBuffer_getChannelMap(IntPtr soundBuffer, out UIntPtr count);
[DllImport(CSFML.Audio, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern Time sfSoundBuffer_getDuration(IntPtr soundBuffer);
#endregion
}
}