规则。前四位是音频长度,截取数量
1表示为单声道;4表示为采样宽度;16000表示为采样率
其中采样宽度4,即量化位数为32bit
附上python的
任务是把这个写成C#的
import wave
import socket
import struct
sentence = "今天天气怎么样。"
bytes_file = bytes(sentence,encoding='utf-8')
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('222.128.11.92',19003))
a = struct.pack('>i', len(bytes_file)) + bytes_file
sock.sendall(struct.pack('>i', len(bytes_file)) + bytes_file)
chunk = sock.recv(1024)
print(chunk[:4])
target_len = struct.unpack('>i',chunk[:4])[0]
print(target_len)
rec_bytes = chunk[4:]
while len(rec_bytes) < target_len:
chunk = sock.recv(1024)
rec_bytes += chunk
print(len(rec_bytes))
f = wave.open("./tmp.wav", "wb")
f.setnchannels(1)
f.setsampwidth(4)
f.setframerate(16000)
f.writeframes(rec_bytes)
f.close()
sock.close()
目标:转成C#的。
提供一个helper方法。
///
/// 文件截取处理
///
public class WavScissorHelper
{
public static bool GetWavFileScissor(string OriginalAudioFilePath, string DestinedAudioFilePath, int beginCutTime, int endCutTime, ref string errorInfo)
{
if (!File.Exists(OriginalAudioFilePath))
{
errorInfo = string.Format("源文件:[{0}]不存在!", OriginalAudioFilePath);
return false;
}
if (!Directory.Exists(Path.GetDirectoryName(DestinedAudioFilePath)))
{
errorInfo = string.Format("文件夹:[{0}]不存在!", Path.GetDirectoryName(DestinedAudioFilePath));
return false;
}
if ((beginCutTime < 0) || (endCutTime < 0)
|| (beginCutTime > endCutTime))
{
errorInfo = string.Format("截取时间[{0}][{1}]有误!", beginCutTime, endCutTime);
return false;
}
try
{
WavFile oldFile = new WavFile(OriginalAudioFilePath);
if (endCutTime > oldFile.PlayTime)
{
errorInfo = string.Format("结束截取时间[{0}]大于音频文件播放时间[{1}]!", endCutTime, oldFile.PlayTime);
return false;
}
int timeSpan = endCutTime - beginCutTime;
WavFile newFile = new WavFile(DestinedAudioFilePath);
newFile.WavFormat = oldFile.WavFormat;
byte[] newAudioBytes = new byte[oldFile.WavFormat.ByteRate * timeSpan];
Array.Copy(oldFile.AudioDataBytes, oldFile.WavFormat.ByteRate * beginCutTime, newAudioBytes, 0, newAudioBytes.Length);
newFile.WriteWavFile(newAudioBytes);
return true;
}
catch (Exception e)
{
return false;
}
}
}
///
/// 淡入淡出处理
///
public class WavFadeHelper
{
private WavFile _wavFile;
public WavFadeHelper(string wavFilePath)
{
_wavFile = new WavFile(wavFilePath);
}
public bool FadeAtFirstSec(FadeMode fadeMode, long fadeLength)
{
return FadeAtSec(fadeMode, 0, fadeLength);
}
public bool FadeAtEndSec(FadeMode fadeMode, long fadeLength)
{
long totalTime = _wavFile.PlayTime;
if (totalTime < fadeLength)
fadeLength = totalTime;
long startTime = totalTime - fadeLength;
return FadeAtSec(fadeMode, startTime, startTime + fadeLength);
}
public bool FadeAtSec(FadeMode fadeMode, long startSec, long endSec)
{
//总播放时间
long totalTime = _wavFile.PlayTime;
//采样位数
// 16 bit 纵坐标为采样系数 细化为 2^16= 65535份 16位二进制表示 [ 0000 0000 0000 0000 ]
// 即为2Byte (每单位时间内产生 2Byte 的音频数据)
int byteNumPerSample = _wavFile.WavFormat.BitsPerSample / 8;
//采样频率
// 11025Hz 横坐标为采样频率 单位时间为: 1/11025 s
//单位时间内产生的的音频数据大小为 2Byte * 11025Hz * 声道数
//audioData 是按字节处理 16bit采样 每次获取两个字节进行处理
//开始位置 存储单元索引
long startIndex = startSec * byteNumPerSample * _wavFile.WavFormat.SampleRate;
if (startIndex % byteNumPerSample > 0)
startIndex -= startIndex % byteNumPerSample;
//结束位置 存储单元索引
long endIndex = endSec * byteNumPerSample * _wavFile.WavFormat.SampleRate;
if (endIndex > _wavFile.AudioDataBytes.Length - 1)
endIndex = _wavFile.AudioDataBytes.Length - 1;
//字节数组 音频数据
byte[] audioDatas = _wavFile.AudioDataBytes;
//初始衰减率
double rate = 1.0;
//对每个单位时间内的 样点幅值 进行衰减
//从淡化开始时间到结束时间共有 [ 采样频率 * 时间段(s) * 采样位数/8(Byte) ] 个存储单元
//每次取出 采样位数/8(Byte) 个存储单元进行衰减
// i 的值为每次衰减处理时的 字节读取位置 (索引)
for (int i = (int)startIndex; i < endIndex; i += byteNumPerSample)
{
//衰减率的方向与淡入淡出有关
//衰减率的大小与当前读取处理字节的索引位置有关
if (fadeMode == FadeMode.FadeOut)
rate = (double)(endIndex - i) / (endIndex - startIndex);
else
rate = (double)(i - startIndex) / (endIndex - startIndex);
//单位时间内的字节数为1 即采用8bit采样位数 每次只需要对一个字节进行衰减
if (byteNumPerSample == 1)
{
//获取需要衰减的字节值
byte audioData = audioDatas[i];
//进行衰减线性处理
byte changedAudioData = (byte)((double)audioData * rate);
//byte changedAudioData = Convert.ToByte((double)audioData * rate);
//对原来的值进行更改
audioDatas[i] = changedAudioData;
}
else if (byteNumPerSample == 2)
{
//16bit 量化 每单位时间产生2Byte数据 因此取 2Byte 的数据进行衰减处理
byte[] audioData = new byte[2];
Array.Copy(audioDatas, i, audioData, 0, 2);
//单个样点幅值
double sample = 0;
//转换为整数进行线性处理
sample = (double)BitConverter.ToInt16(audioData, 0) * rate;
//转换为字节存储
byte[] buffer = BitConverter.GetBytes(Convert.ToInt16(sample));
if (!BitConverter.IsLittleEndian)
Array.Reverse(buffer);
Array.Copy(buffer, 0, audioDatas, i, 2);
}
}
_wavFile.WriteWavFile(audioDatas);
return true;
}
}
///
/// 淡入淡出模式
///
public enum FadeMode
{
FadeIn,
FadeOut
}
///
/// WAV 文件
///
public class WavFile
{
private WavFormat _wavFormat; //文件格式
private long _fileLength; //文件长度
private string _filePath; //文件路径
private byte[] _audioData; //语音数据
private WavFile() { }
public WavFile(string filePath)
{
_filePath = filePath;
}
///
/// 文件格式
///
public WavFormat WavFormat
{
get
{
if (_wavFormat == null)
_wavFormat = GetWavFormat();
return _wavFormat;
}
set { _wavFormat = value; }
}
///
/// 文件大小
///
public long FileLength
{
get
{
if (_wavFormat == null)
_wavFormat = GetWavFormat();
return _fileLength;
}
set { _fileLength = value; }
}
///
/// 播放时长
///
public long PlayTime
{
get
{
if (_wavFormat == null)
_wavFormat = GetWavFormat();
return _audioData.Length / _wavFormat.ByteRate;
}
}
///
/// 语音数据
///
public byte[] AudioDataBytes
{
get
{
if (_wavFormat == null)
_wavFormat = GetWavFormat();
return _audioData;
}
set { _audioData = value; }
}
///
/// 设置Wav文件格式
///
/// 采样位数
/// 声道数
/// 采样率
public void SetWavFormat(int bitsPerSample, int channels, int sampleRate)
{
_wavFormat = new WavFormat();
_wavFormat.BitsPerSample = bitsPerSample;
_wavFormat.Channels = channels;
_wavFormat.SampleRate = sampleRate;
}
///
/// 写文件
///
/// 音频数据
public void WriteWavFile(byte[] audioData)
{
WriteWavFile(_wavFormat, audioData, 0, audioData.Length);
}
///
/// 写文件
///
/// 文件格式
/// 音频数据
/// audioData数组开始索引位置
/// 写入audioData数组长度
public void WriteWavFile(WavFormat wavFormat, byte[] audioData, int startIndex, int length)
{
FileStream fs = null;
BinaryWriter bw = null;
try
{
fs = new FileStream(_filePath, FileMode.Create, FileAccess.Write);
bw = new BinaryWriter(fs);
fs.Position = 0;
bw.Write(new char[4] { 'R', 'I', 'F', 'F' });
//ChunkFileSize
bw.Write((int)(length + 44 - 8));
bw.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' });
bw.Write((int)16);
bw.Write((short)1);
bw.Write((short)wavFormat.Channels);
bw.Write(wavFormat.SampleRate);
bw.Write((int)(wavFormat.SampleRate * ((wavFormat.BitsPerSample * wavFormat.Channels) / 8)));
bw.Write((short)((wavFormat.BitsPerSample * wavFormat.Channels) / 8));
bw.Write((short)wavFormat.BitsPerSample);
bw.Write(new char[4] { 'd', 'a', 't', 'a' });
bw.Write(length);
bw.Write(audioData, startIndex, length);
}
finally
{
if (bw != null)
bw.Close();
if (fs != null)
{
fs.Close();
fs.Dispose();
}
}
}
///
/// 获取Wav文件格式
///
///
private WavFormat GetWavFormat()
{
FileStream fs = null;
BinaryReader br = null;
WavFormat wavFormat = new WavFormat();
try
{
fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read);
br = new BinaryReader(fs);
_fileLength = fs.Length;
fs.Position = 22;
wavFormat.Channels = br.ReadInt16();
fs.Position = 24;
wavFormat.SampleRate = br.ReadInt32();
fs.Position = 28;
wavFormat.ByteRate = br.ReadInt32();
fs.Position = 34;
wavFormat.BitsPerSample = br.ReadInt16();
//The audio data
fs.Position = 44;
int dataByteSize = (int)(fs.Length - 44);
if (_audioData == null)
_audioData = new byte[dataByteSize];
fs.Read(_audioData, 0, dataByteSize);
}
finally
{
if (br != null)
br.Close();
if (fs != null)
{
fs.Close();
fs.Dispose();
}
}
return wavFormat;
}
}
///
/// WAV 文件格式
///
public class WavFormat
{
///
/// 采样位数
///
public int BitsPerSample;
///
/// 声道数
///
public int Channels;
///
/// 采样率
///
public int SampleRate;
///
/// 传输速率(播放速率)
///
public long ByteRate;
}
我的接受和解析