diff --git a/app/app.go b/app/app.go index 7236c52..d2ba38f 100644 --- a/app/app.go +++ b/app/app.go @@ -77,7 +77,6 @@ var ConfigFormat = ConfigTemplate{ type App struct { *Printer - Config map[string]extractor.Config Hashes map[stingray.Hash]string gameDir string dataDir *stingray.DataDir @@ -242,7 +241,7 @@ func (a *App) MatchingFiles(includeGlob, excludeGlob string, cfgTemplate ConfigT return res, nil } -func (a *App) ExtractFile(id stingray.FileID, outDir string, runner *exec.Runner) error { +func (a *App) ExtractFile(id stingray.FileID, outDir string, extrCfg map[string]extractor.Config, runner *exec.Runner) error { name, ok := a.Hashes[id.Name] if !ok { name = id.Name.String() @@ -257,7 +256,7 @@ func (a *App) ExtractFile(id stingray.FileID, outDir string, runner *exec.Runner return fmt.Errorf("extract %v.%v: file does not found", name, typ) } - cfg := a.Config[typ] + cfg := extrCfg[typ] if cfg == nil { cfg = make(extractor.Config) } diff --git a/extractor/wwise/extractor.go b/extractor/wwise/extractor.go index 753a3fb..be4ccc3 100644 --- a/extractor/wwise/extractor.go +++ b/extractor/wwise/extractor.go @@ -127,6 +127,10 @@ func convertWemStream(outPath string, in io.ReadSeeker, format format, runner *e } } default: + if format == formatAac && !dec.ChannelLayout().HasName() { + // AAC doesn't support custom layouts + format = formatOgg + } var fmtExt string switch format { case formatMp3: @@ -143,7 +147,7 @@ func convertWemStream(outPath string, in io.ReadSeeker, format format, runner *e "-f", "f32le", "-ar", fmt.Sprint(dec.SampleRate()), "-ac", fmt.Sprint(dec.Channels()), - "-channel_layout", dec.ChannelLayout().String(), + "-channel_layout", fmt.Sprintf("0x%x", uint32(dec.ChannelLayout())), "-i", "pipe:", outPath+fmtExt, ); err != nil { diff --git a/hash_tool/main.go b/hash_tool/main.go index 49d3987..eebd8cb 100644 --- a/hash_tool/main.go +++ b/hash_tool/main.go @@ -192,7 +192,7 @@ func main() { } if *maxWords != -1 { - fmt.Fprintln(os.Stderr, "brute_force_length only available for \"crack\" mode") + fmt.Fprintln(os.Stderr, "max_words only available for \"crack\" mode") os.Exit(1) } diff --git a/main.go b/main.go index ef90833..9539e14 100644 --- a/main.go +++ b/main.go @@ -161,7 +161,7 @@ extractor config: truncName = "..." + truncName[len(truncName)-37:] } prt.Statusf("File %v/%v: %v", i+1, len(files), truncName) - if err := a.ExtractFile(id, *outDir, runner); err == nil { + if err := a.ExtractFile(id, *outDir, extrCfg, runner); err == nil { numExtrFiles++ } else { prt.Errorf("%v", err) diff --git a/wwise/wem.go b/wwise/wem.go index b839c66..a0c1b80 100644 --- a/wwise/wem.go +++ b/wwise/wem.go @@ -232,6 +232,50 @@ const ( SpeakerTBR // top back left ) +// Returns ffmpeg-compatible string for a single speaker flag (e.g. "FL"). +func (sp SpeakerFlag) String() string { + switch sp { + case SpeakerFL: + return "FL" + case SpeakerFR: + return "FR" + case SpeakerFC: + return "FC" + case SpeakerLFE: + return "LFE" + case SpeakerBL: + return "BL" + case SpeakerBR: + return "BR" + case SpeakerFLC: + return "FLC" + case SpeakerFRC: + return "FRC" + case SpeakerBC: + return "BC" + case SpeakerSL: + return "SL" + case SpeakerSR: + return "SR" + case SpeakerTC: + return "TC" + case SpeakerTFL: + return "TFL" + case SpeakerTFC: + return "TFC" + case SpeakerTFR: + return "TFR" + case SpeakerTBL: + return "TBL" + case SpeakerTBC: + return "TBC" + case SpeakerTBR: + return "TBR" + default: + panic(fmt.Sprintf("unhandled case: 0b%032b", uint32(sp))) + } +} + type ChannelLayout uint32 const ( @@ -263,9 +307,40 @@ const ( Mapping7Point1Top = ChannelLayout(SpeakerFL | SpeakerFR | SpeakerFC | SpeakerLFE | SpeakerBL | SpeakerBR | SpeakerTFL | SpeakerTFR) ) -// Returns FFmpeg-compatible name. -func (cm ChannelLayout) String() string { - switch cm { +// Returns true if the channel layout can be described by a simple name like "7.1" or "stereo". +// The string can be obtained by calling String(). +func (cl ChannelLayout) HasName() bool { + return cl == MappingMono || + cl == MappingStereo || + cl == Mapping2Point1 || + cl == Mapping3Point0 || + cl == Mapping3Point0Back || + cl == Mapping4Point0 || + cl == MappingQuad || + cl == MappingQuadSide || + cl == Mapping3Point1 || + cl == Mapping5Point0 || + cl == Mapping5Point0Side || + cl == Mapping4Point1 || + cl == Mapping5Point1 || + cl == Mapping5Point1Side || + cl == Mapping6Point0 || + cl == Mapping6Point0Front || + cl == MappingHexagonal || + cl == Mapping6Point1 || + cl == Mapping6Point1Back || + cl == Mapping6Point1Front || + cl == Mapping7Point0 || + cl == Mapping7Point0Front || + cl == Mapping7Point1 || + cl == Mapping7Point1Wide || + cl == Mapping7Point1WideSide || + cl == Mapping7Point1Top +} + +// Returns channel layout name, or, if nonstandard, list of speakers separated by "|". +func (cl ChannelLayout) String() string { + switch cl { case MappingMono: return "mono" case MappingStereo: @@ -319,7 +394,16 @@ func (cm ChannelLayout) String() string { case Mapping7Point1Top: return "7.1(top)" default: - panic(fmt.Sprintf("unhandled case: 0x%032b", uint32(cm))) + var res string + for i := 0; i < 64; i++ { + if (cl>>i)&1 != 0 { + if len(res) != 0 { + res += "|" + } + res += SpeakerFlag(1 << i).String() + } + } + return res } }