public IDjmainArchive Decode(IDjmainChunk chunk, DjmainDecodeOptions options) { if (chunk.Data.Length != 0x1000000) { throw new RhythmCodexException("Chunk length must be exactly 16mb (0x1000000 bytes)"); } if (chunk.Format == DjmainChunkFormat.Unknown || !Enum.IsDefined(typeof(DjmainChunkFormat), chunk.Format)) { throw new RhythmCodexException($"{nameof(chunk.Format)} is not recognized"); } using (var stream = new ReadOnlyMemoryStream(chunk.Data)) { var swappedStream = new ByteSwappedReadStream(stream); var chartSoundMap = _offsetProvider.GetSampleChartMap(chunk.Format) .Select((offset, index) => new KeyValuePair <int, int>(index, offset)) .ToDictionary(kv => kv.Key, kv => kv.Value); var rawCharts = ExtractCharts(stream, chunk.Format).Where(c => c.Value != null).ToList(); var decodedCharts = DecodeCharts(rawCharts, chartSoundMap, chunk.Format); var sounds = options.DisableAudio ? null : DecodeSounds(swappedStream, chunk.Format, chartSoundMap, rawCharts, decodedCharts, options) .ToDictionary(kv => kv.Key, kv => kv.Value.Select(s => s)); return(new DjmainArchive { RawCharts = rawCharts.ToDictionary(kv => kv.Key, kv => kv.Value), Charts = decodedCharts?.Select(c => c.Value).ToList(), Samples = sounds?.SelectMany(s => s.Value).Select(s => s.Value).ToList() }); } }
public ITask CreateDecodeDjmainHdd() { return(Build("Extract DJMAIN HDD", task => { var files = GetInputFiles(task); if (!files.Any()) { task.Message = "No input files."; return false; } ParallelProgress(task, files, file => { var options = new DjmainDecodeOptions { DisableAudio = !EnableExportingSounds }; using (var stream = OpenRead(task, file)) { long offset = 0; var chunks = _djmainChunkStreamReader.Read(stream); foreach (var chunk in chunks) { var chunkPath = $"{Alphabet.EncodeNumeric(chunk.Id, 4)}"; var decoded = _djmainDecoder.Decode(chunk, options); ExportKeysoundedChart(task, file, chunkPath, $"{Alphabet.EncodeNumeric(chunk.Id, 4)}", decoded.Charts, decoded.Samples); if (EnableExportingRaw) { foreach (var(key, value) in decoded.RawCharts) { using (var rawChartStream = OpenWriteMulti(task, file, _ => Path.Combine(chunkPath, $"{Alphabet.EncodeNumeric(key, 2)}.cs5"))) { _djmainChartEventStreamWriter.Write(rawChartStream, value); rawChartStream.Flush(); } } }
private IDictionary <int, IDictionary <int, ISound> > DecodeSounds(Stream stream, DjmainChunkFormat format, IReadOnlyDictionary <int, int> chartSoundMap, IEnumerable <KeyValuePair <int, IEnumerable <IDjmainChartEvent> > > charts, IEnumerable <KeyValuePair <int, IChart> > decodedCharts, DjmainDecodeOptions options) { return(_offsetProvider.GetSampleMapOffsets(format) .Select((offset, index) => new KeyValuePair <int, int>(index, offset)) .ToDictionary(kv => kv.Key, kv => { var chartData = charts .Where(c => chartSoundMap[c.Key] == kv.Key) .SelectMany(c => c.Value) .ToList(); var samples = DecodeSamples(stream, format, kv.Value, chartData); var decodedSamples = _soundDecoder.Decode(samples); if (!options.DoNotConsolidateSamples) { _soundConsolidator.Consolidate(decodedSamples.Values, decodedCharts.SelectMany(dc => dc.Value?.Events ?? Enumerable.Empty <IEvent>())); } foreach (var sample in decodedSamples.Where(s => s.Value.Samples.Any())) { var s = sample.Value; s[NumericData.SampleMap] = kv.Key; } foreach (var discardedSample in decodedSamples.Where(s => !s.Value.Samples.Any()).ToList()) { decodedSamples.Remove(discardedSample); } return decodedSamples; })); }