AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Plugins/Mame.Core/sound/Sample.cs

221 lines
8.0 KiB
C#
Raw Normal View History

using System;
using System.IO;
using System.Runtime.InteropServices;
namespace MAME.Core
{
public unsafe class Sample
{
public struct sample_channel
{
//public short[] source;
#region //指针化 source
short[] source_src;
GCHandle source_handle;
public short* source;
public int sourceLength;
public bool source_IsNull => source == null;
public short[] source_set
{
set
{
source_handle.ReleaseGCHandle();
if (value == null)
return;
source_src = value;
sourceLength = value.Length;
source_src.GetObjectPtr(ref source_handle, ref source);
}
}
#endregion
public int source_length;
public int source_num;
public uint pos;
public uint frac;
public uint step;
public uint basefreq;
public byte loop;
public byte paused;
}
public struct samples_info
{
public int numchannels;
public sample_channel[] channel;
public loaded_samples[] samples;
public starthandler starthandler;
}
public struct loaded_sample
{
public int length;
public int frequency;
}
public struct loaded_samples
{
public int total;
public loaded_sample[] sample;
}
public static samples_info info = new samples_info();
public delegate void starthandler();
public static void sample_start_raw_n(int num, int channel, short* sampledata, int samples, int frequency, int loop)
{
Sound.samplestream.stream_update();
info.channel[channel].source_length = samples;
info.channel[channel].source_set = new short[samples];
AxiArray.Copy(sampledata, 0, info.channel[channel].source, 0, samples);
info.channel[channel].source_num = -1;
info.channel[channel].pos = 0;
info.channel[channel].frac = 0;
info.channel[channel].basefreq = (uint)frequency;
info.channel[channel].step = (uint)(((long)info.channel[channel].basefreq << 24) / 48000);
info.channel[channel].loop = (byte)loop;
}
public static void sample_start_raw(int channel, short* sampledata, int samples, int frequency, int loop)
{
sample_start_raw_n(0, channel, sampledata, samples, frequency, loop);
}
public static void sample_stop_n(int num, int channel)
{
Sound.samplestream.stream_update();
info.channel[channel].source = null;
info.channel[channel].source_num = -1;
}
public static void sample_stop(int channel)
{
sample_stop_n(0, channel);
}
public static int sample_playing_n(int num, int channel)
{
Sound.samplestream.stream_update();
return (info.channel[channel].source != null) ? 1 : 0;
}
public static int sample_playing(int channel)
{
return sample_playing_n(0, channel);
}
public static void sample_update_sound(int offset, int length)
{
int i, j;
if (info.channel[0].source != null && info.channel[0].paused == 0)
{
uint pos = info.channel[0].pos;
uint frac = info.channel[0].frac;
uint step = info.channel[0].step;
int sample_length = info.channel[0].source_length;
for (i = 0; i < length; i++)
{
int sample1 = info.channel[0].source[pos];
int sample2 = info.channel[0].source[(pos + 1) % sample_length];
int fracmult = (int)(frac >> (24 - 14));
Sound.samplestream.streamoutput_Ptrs[0][offset + i] = ((0x4000 - fracmult) * sample1 + fracmult * sample2) >> 14;
frac += step;
pos += frac >> 24;
frac = frac & ((1 << 24) - 1);
if (pos >= sample_length)
{
if (info.channel[0].loop != 0)
{
pos %= (uint)sample_length;
}
else
{
info.channel[0].source = null;
info.channel[0].source_num = -1;
if (i + 1 < length)
{
for (j = i + 1; j < length; j++)
{
Sound.samplestream.streamoutput_Ptrs[0][offset + j] = 0;
}
}
break;
}
}
}
info.channel[0].pos = pos;
info.channel[0].frac = frac;
}
else
{
for (i = 0; i < length; i++)
{
Sound.samplestream.streamoutput_Ptrs[0][offset + i] = 0;
}
}
}
public static void samples_start()
{
int i;
info.numchannels = 1;
info.channel = new sample_channel[info.numchannels];
for (i = 0; i < info.numchannels; i++)
{
info.channel[i].source = null;
info.channel[i].source_num = -1;
info.channel[i].step = 0;
info.channel[i].loop = 0;
info.channel[i].paused = 0;
}
switch (Machine.sName)
{
case "starfigh":
info.starthandler = SunA8.suna8_sh_start;
break;
case "tmnt":
case "tmntu":
case "tmntua":
case "tmntub":
case "tmht":
case "tmhta":
case "tmhtb":
case "tmntj":
case "tmnta":
case "tmht2p":
case "tmht2pa":
case "tmnt2pj":
case "tmnt2po":
info.starthandler = Konami68000.tmnt_decode_sample;
break;
default:
info.starthandler = null;
break;
}
if (info.starthandler != null)
{
info.starthandler();
}
}
public static void SaveStateBinary(BinaryWriter writer)
{
int i;
for (i = 0; i < info.numchannels; i++)
{
writer.Write(info.channel[i].source_length);
writer.Write(info.channel[i].source_num);
writer.Write(info.channel[i].pos);
writer.Write(info.channel[i].frac);
writer.Write(info.channel[i].step);
writer.Write(info.channel[i].basefreq);
writer.Write(info.channel[i].loop);
writer.Write(info.channel[i].paused);
}
}
public static void LoadStateBinary(BinaryReader reader)
{
int i;
for (i = 0; i < info.numchannels; i++)
{
info.channel[i].source_length = reader.ReadInt32();
info.channel[i].source_num = reader.ReadInt32();
info.channel[i].pos = reader.ReadUInt32();
info.channel[i].frac = reader.ReadUInt32();
info.channel[i].step = reader.ReadUInt32();
info.channel[i].basefreq = reader.ReadUInt32();
info.channel[i].loop = reader.ReadByte();
info.channel[i].paused = reader.ReadByte();
}
}
}
}