public static Sound Read(Stream source) { BinaryReaderEx reader = new BinaryReaderEx(source); Sound result = new Sound(); int id = reader.ReadInt32(); if (id == 0x00394453) { int headerLength = reader.ReadInt32(); int sampleLength = reader.ReadInt32(); headerLength -= 12; if (headerLength > 0) reader.ReadBytes(headerLength); byte[] wavData = reader.ReadBytes(sampleLength); using (MemoryStream wavDataMem = new MemoryStream(wavData)) { using (WaveStream wavStream = new WaveFileReader(wavDataMem)) { byte[] rawWaveData = new byte[wavStream.Length]; wavStream.Read(rawWaveData, 0, (int)wavStream.Length); result.SetSound(rawWaveData, wavStream.WaveFormat); } } } return result; }
public static void Process(Sound[] sounds, Chart[] charts) { List<int> keysoundsUsed = new List<int>(); List<int> bgmKeysounds = new List<int>(); foreach (Chart chart in charts) { foreach (Entry entry in chart.Entries) { if (entry.Type == EntryType.Sample || entry.Type == EntryType.Marker) { if (entry.Value.Denominator == 1 && entry.Value.Numerator > 0) { int noteValue = (int)entry.Value.Numerator; if (!keysoundsUsed.Contains(noteValue)) { keysoundsUsed.Add(noteValue); if (!bgmKeysounds.Contains(noteValue)) { bgmKeysounds.Add(noteValue); } } if (entry.Player != 0) { bgmKeysounds.Remove(noteValue); } } } } } int count = sounds.Length; for (int i = 0; i < count; i++) { for (int j = i + 1; j < count; j++) { if (bgmKeysounds.Contains(i + 1) && bgmKeysounds.Contains(j + 1)) { if (sounds[i].Data.Length == sounds[j].Data.Length && Math.Abs(sounds[i].Panning - sounds[j].Panning) == 1) { byte[] render0 = sounds[i].Render(1.0f); byte[] render1 = sounds[j].Render(1.0f); int renderLength = render0.Length; byte[] output = new byte[renderLength]; for (int k = 0; k < renderLength; k++) { output[k] = (byte)(render0[k] | render1[k]); } sounds[i].SetSound(output, sounds[i].Format); sounds[j].SetSound(new byte[] { }, sounds[j].Format); sounds[i].Panning = 0.5f; sounds[i].Volume = 1.0f; } } } } }
public static Sound Read(Stream source) { Sound result = new Sound(); BinaryReader reader = new BinaryReader(source); if (new string(reader.ReadChars(4)) == "2DX9") { int infoLength = reader.ReadInt32(); int dataLength = reader.ReadInt32(); reader.ReadInt16(); int channel = reader.ReadInt16(); int panning = reader.ReadInt16(); int volume = reader.ReadInt16(); int options = reader.ReadInt32(); reader.ReadBytes(infoLength - 24); byte[] wavData = reader.ReadBytes(dataLength); using (MemoryStream wavDataMem = new MemoryStream(wavData)) { using (WaveStream wavStream = new WaveFileReader(wavDataMem)) { int bytesToRead; // using a mux, we force all sounds to be 2 channels bytesToRead = (int)wavStream.Length; byte[] rawWaveData = new byte[bytesToRead]; int bytesRead = wavStream.Read(rawWaveData, 0, bytesToRead); result.SetSound(rawWaveData, wavStream.WaveFormat); // calculate output panning if (panning > 0x7F || panning < 0x01) panning = 0x40; result.Panning = ((float)panning - 1.0f) / 126.0f; // calculate output volume if (volume < 0x01) volume = 0x01; else if (volume > 0xFF) volume = 0xFF; result.Volume = VolumeTable[volume]; result.Channel = channel; } } } return result; }
public static Sound Read(Stream source) { Sound result = new Sound(); WaveFileReader reader = new WaveFileReader(source); if (reader.Length > 0) { result.Data = new byte[reader.Length]; reader.Read(result.Data, 0, result.Data.Length); result.Format = reader.WaveFormat; } else { result.Data = new byte[] { }; result.Format = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm, 44100, 2, 44100 * 4, 4, 16); } result.Panning = 0.5f; result.Volume = 1.0f; return result; }
public static Sound Read(Stream source, Properties properties) { BinaryReaderEx reader = new BinaryReaderEx(source); Sound result = new Sound(); bool stereo = (properties.Flag0F & 0x80) != 0; byte[] data = reader.ReadBytes(properties.SampleLength); int dataLength = data.Length; byte[] newData = new byte[dataLength * (stereo ? 1 : 2)]; // translate the "signed" data int newDataPtr = 0; for (int i = 0; i < dataLength; i += 2) { int sample = ((int)data[i] << 8) | data[i + 1]; if (sample >= 0x8000) { sample = -(sample & 0x7FFF); } newData[newDataPtr] = (byte)(sample & 0xFF); newData[newDataPtr + 1] = (byte)((sample >> 8) & 0xFF); if (!stereo) { newData[newDataPtr + 2] = newData[newDataPtr]; newData[newDataPtr + 3] = newData[newDataPtr + 1]; newDataPtr += 2; } newDataPtr += 2; } // 16-bit stereo format result.Format = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm, properties.Frequency, 2, properties.Frequency * 4, 4, 16); result.Data = newData; // determine volume result.Volume = VolumeTable[properties.Volume]; // determine panning result.Panning = (float)(properties.Panning - 1) / (float)0x7E; // return the final result return result; }
// note: I/O functions do not use the Offset field in Properties public static Sound Read(Stream source, Properties prop) { Sound result = new Sound(); byte[] data = ReadRaw(source, prop); // get the true sample rate int sampleRate = prop.Frequency; sampleRate = (int)((sampleRate * 44100L) / 60216L); // decode the sound and quantize to 16 bits stereo switch (prop.SampleType & 0xC) { case 0x0: data = Decode8(data); break; case 0x4: data = Decode16(data); break; case 0x8: data = Decode4(data); break; } // 16-bit stereo format result.Format = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm, sampleRate, 2, sampleRate * 4, 4, 16); result.Data = data; // determine volume result.Volume = VolumeTable[prop.Volume]; // determine panning int panValue = prop.Panning & 0xF; if (panValue < 1) panValue = 8; if (panValue > 15) panValue = 8; result.Panning = (float)(panValue - 1) / 14f; // return the final result return result; }
public static byte[] Render(Chart chart, Sound[] sounds) { Dictionary<long, Entry> lastNote = new Dictionary<long, Entry>(); Dictionary<int, Fraction> noteCutoff = new Dictionary<int, Fraction>(); Dictionary<int, byte[]> renderedSamples = new Dictionary<int, byte[]>(); int[] buffer = new int[0]; chart.Entries.Reverse(); foreach (Entry entry in chart.Entries) { if (entry.Type == EntryType.Sample) { lastNote[GetIdentifier(entry)] = entry; } else if (entry.Type == EntryType.Marker) { Sound sound; if (entry.Value.Numerator > 0) { byte[] soundData = null; int soundIndex = (int)entry.Value - 1; sound = sounds[(int)entry.Value - 1]; if (renderedSamples.ContainsKey(soundIndex)) { soundData = renderedSamples[soundIndex]; } else if (sound != null) { soundData = sound.Render(1.0f); renderedSamples[soundIndex] = soundData; } Fraction cutoff = new Fraction(-1, 1); if (sound.Channel >= 0 && noteCutoff.ContainsKey(sound.Channel)) { cutoff = noteCutoff[sound.Channel]; } if (soundData != null) { Paste(soundData, ref buffer, entry.LinearOffset * chart.TickRate, cutoff * chart.TickRate); } if (sound.Channel >= 0) noteCutoff[sound.Channel] = entry.LinearOffset; } } } chart.Entries.Reverse(); int length = buffer.Length; Int16[] outputSamples = new Int16[length]; int normalization = 1; for (int i = 0; i < length; i++) { // auto-normalize int currentSample = buffer[i] / normalization; while (currentSample > 32767 || currentSample < -32768) { normalization++; currentSample = buffer[i] / normalization; } } for (int i = 0; i < length; i++) { outputSamples[i] = (Int16)(buffer[i] / normalization); } using (MemoryStream mem = new MemoryStream()) { using (WaveFileWriter writer = new WaveFileWriter(new IgnoreDisposeStream(mem), WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm, 44100, 2, 44100 * 4, 4, 16))) { writer.WriteSamples(outputSamples, 0, length); } mem.Flush(); return mem.ToArray(); } }
public static MicrosoftXWB Read(Stream source) { MicrosoftXWB result = new MicrosoftXWB(); using (BinaryReader reader = new BinaryReader(source)) { int sampleCount = 0; WaveBankHeader header = new WaveBankHeader(); WaveBankData bank = new WaveBankData(); WaveBankEntry[] entries = { }; string[] names = { }; MemoryStream dataChunk = new MemoryStream(); header = WaveBankHeader.Read(source); for (int i = 0; i < (int)WaveBankSegIdx.Count; i++) { WaveBankRegion region = header.Segments[i]; if (region.Length > 0) { source.Position = region.Offset; MemoryStream mem = new MemoryStream(reader.ReadBytes(region.Length)); BinaryReader memReader = new BinaryReader(mem); switch (i) { case (int)WaveBankSegIdx.BankData: bank = WaveBankData.Read(mem); sampleCount = bank.EntryCount; entries = new WaveBankEntry[sampleCount]; names = new string[sampleCount]; mem.Dispose(); break; case (int)WaveBankSegIdx.EntryMetaData: for (int j = 0; j < sampleCount; j++) entries[j] = WaveBankEntry.Read(mem); mem.Dispose(); break; case (int)WaveBankSegIdx.EntryNames: for (int j = 0; j < sampleCount; j++) names[j] = Util.TrimNulls(new string(memReader.ReadChars(Constants.WavebankEntrynameLength))); mem.Dispose(); break; case (int)WaveBankSegIdx.EntryWaveData: dataChunk = mem; break; case (int)WaveBankSegIdx.SeekTables: mem.Dispose(); break; default: mem.Dispose(); break; } } } if (sampleCount > 0) { List<Sound> sounds = new List<Sound>(); for (int i = 0; i < sampleCount; i++) { WaveBankEntry entry = entries[i]; byte[] rawData = new byte[entry.PlayRegion.Length]; dataChunk.Position = entry.PlayRegion.Offset; dataChunk.Read(rawData, 0, rawData.Length); WaveFormat dataFormat; switch (entry.Format.FormatTag) { case Constants.WavebankminiformatTagPcm: dataFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm, entry.Format.SamplesPerSec, entry.Format.Channels, entry.Format.AvgBytesPerSec, entry.Format.BlockAlign, entry.Format.BitsPerSample); break; case Constants.WavebankminiformatTagXma: dataFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.DviAdpcm, entry.Format.SamplesPerSec, entry.Format.Channels, entry.Format.AvgBytesPerSec, entry.Format.BlockAlign, entry.Format.BitsPerSample); break; case Constants.WavebankminiformatTagAdpcm: dataFormat = new AdpcmWaveFormat(entry.Format.SamplesPerSec, entry.Format.Channels, (short)entry.Format.BlockAlign, entry.Format.AvgBytesPerSec, (short)entry.Format.AdpcmSamplesPerBlock); //dataFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Adpcm, entry.Format.SamplesPerSec, entry.Format.Channels, entry.Format.AvgBytesPerSec, entry.Format.BlockAlign, entry.Format.BitsPerSample); break; case Constants.WavebankminiformatTagWma: dataFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.WindowsMediaAudio, entry.Format.SamplesPerSec, entry.Format.Channels, entry.Format.AvgBytesPerSec, entry.Format.BlockAlign, entry.Format.BitsPerSample); break; default: dataFormat = null; break; } if (dataFormat != null) { Sound baseSound = new Sound(rawData, dataFormat); baseSound.Name = names[i]; sounds.Add(baseSound); } } result.sounds = sounds.ToArray(); result.Name = bank.BankName; } } return result; }
// returns the number of bytes written public static int Write(Sound source, Stream target, Properties prop) { BinaryWriterEx writer = new BinaryWriterEx(target); return 0; }
public static void ConvertSounds(Sound[] sounds, string filename, float volume) { string name = Path.GetFileNameWithoutExtension(Path.GetFileName(filename)); string targetPath = Path.Combine(Path.GetDirectoryName(filename), name); if (!Directory.Exists(targetPath)) Directory.CreateDirectory(targetPath); int count = sounds.Length; for (int j = 0; j < count; j++) { int sampleIndex = j + 1; sounds[j].WriteFile(Path.Combine(targetPath, Scharfrichter.Codec.Util.ConvertToBMEString(sampleIndex, 4) + @".wav"), volume); } }