bigbasi Posted December 16, 2025 Posted December 16, 2025 Rennas Ranch Voice Files View File Voice Files for Rennas Ranch created with XVASynth 3.0 These Files are not optimized, so they contain Voices which are not used in the Mod, thats why the files are so big, but I really haven't had it in me to find out which lines are spoken by whom. Due to the upload restrictions of 500MB I had to split it. If there are any problems, or voices missing, please let me know! PS: I created this Files for MY PLAYTHROUGH! But sharing is caring, as always. 😉 Due to the way I am exporting the lines with a script through SSEdit and the way the mod is configured the size of this Voice mod is at least 6-12 times as big as it has to be. I allready contacted the Mod Author, but I think he has enough to do to add more content to the mod, then to fix the voice lines, and I am totally ok with that! So please be patient, I think he'll has a lot on his plate right now. I just started my playthrough, so I dont know if anything is missing, for now it seems to work. Submitter bigbasi Submitted 12/16/25 Category Adult Mods Requirements Rennas Ranch Regular Edition Compatible Not Applicable Install Instructions Install as any other Mod 1
asdt123123 Posted December 16, 2025 Posted December 16, 2025 How are you people so fast with these voice files? Do you manually have to create them string by string? Or does the program just do it for you? I could maybe automate this process for you guys if it's tedious.
bigbasi Posted December 17, 2025 Author Posted December 17, 2025 9 hours ago, asdt123123 said: How are you people so fast with these voice files? Do you manually have to create them string by string? Or does the program just do it for you? I could maybe automate this process for you guys if it's tedious. Actually I could use your help, If you want have a look here, there I have described a problem, with the way I export the lines with SSEdit.
asdt123123 Posted December 17, 2025 Posted December 17, 2025 (edited) 15 hours ago, bigbasi said: Actually I could use your help, If you want have a look here, there I have described a problem, with the way I export the lines with SSEdit. I wrote a quick script that does essentially what you're asking: Spoiler { Export dialogues for Skyrim SE for use with xVASynth. VERSION: 2.7 } unit SkyrimSEExportDialogues; var slExport, slVoiceTypes, slIDs: TStringList; bDebug: Boolean; procedure DebugLog(s: string); begin if bDebug then AddMessage('[DEBUG] ' + s); end; function InfoFileName(PluginName: string; InfoFormID: integer; RespNumber: string): string; begin PluginName := ChangeFileExt(PluginName, ''); Result := Format('%s_%s_%s', [ PluginName, IntToHex(InfoFormID and $FFFFFF, 8), RespNumber ]); end; //heelper to get Editor ID of a Voice Type link safely function GetVoiceIDFromLink(e: IInterface): string; var rec: IInterface; begin Result := ''; if not Assigned(e) then Exit; rec := WinningOverride(LinksTo(e)); if Assigned(rec) and (Signature(rec) = 'VTYP') then Result := EditorID(rec); end; function GetVoiceTypeFromNPC(e: IInterface): string; var vtyp, race, baseNPC, tplt, vList, child: IInterface; sig, tpltFlags: string; iter, i: integer; begin Result := ''; if not Assigned(e) then Exit; e := WinningOverride(e); sig := Signature(e); DebugLog(' -> Resolving Actor: ' + Name(e)); // Resolve Reference (ACHR/REFR) to Base NPC if (sig = 'ACHR') or (sig = 'REFR') then begin baseNPC := WinningOverride(LinksTo(ElementBySignature(e, 'NAME'))); if Assigned(baseNPC) then begin e := baseNPC; sig := Signature(e); DebugLog(' -> Resolved Reference to Base: ' + Name(e)); end else begin DebugLog(' -> Could not resolve Base NPC for Reference.'); Exit; end; end; if sig = 'NPC_' then begin // Handle TEMPLATES for iter := 0 to 5 do begin tpltFlags := GetElementEditValues(e, 'ACBS\Template Flags'); if Pos('Use Traits', tpltFlags) > 0 then begin tplt := WinningOverride(LinksTo(ElementBySignature(e, 'TPLT'))); if Assigned(tplt) then begin DebugLog(' -> Inherits Traits from Template: ' + Name(tplt)); e := tplt; Continue; end; end; Break; end; // Try Explicit VTYP vtyp := ElementBySignature(e, 'VTYP'); if not Assigned(vtyp) then vtyp := ElementByName(e, 'VTYP - Voice Type'); // Try VTCK on NPC if not Assigned(vtyp) then vtyp := ElementBySignature(e, 'VTCK'); if Assigned(vtyp) then begin Result := GetVoiceIDFromLink(vtyp); if Result <> '' then begin DebugLog(' -> Found NPC Voice: ' + Result); Exit; end; end; // Fallback: Check Race (RNAM) -> VTCK (Voices To Check) // Get WinningOverride of the Race to ensure we see lists added by mods/patches race := WinningOverride(LinksTo(ElementBySignature(e, 'RNAM'))); if Assigned(race) then begin DebugLog(' -> Checking Race: ' + Name(race)); // Try Standard VTCK Signature vList := ElementBySignature(race, 'VTCK'); // If not found, try searching children (Brute force for "Voices") if not Assigned(vList) then begin for i := 0 to ElementCount(race) - 1 do begin child := ElementByIndex(race, i); if (Signature(child) = 'VTCK') or (Name(child) = 'Voices') then begin vList := child; Break; end; end; end; if Assigned(vList) and (ElementCount(vList) > 0) then begin // Grab the first one in the list // ElementByIndex(vList, 0) gives the reference inside the list vtyp := ElementByIndex(vList, 0); Result := GetVoiceIDFromLink(vtyp); if Result <> '' then DebugLog(' -> Found Race Default Voice: ' + Result) else DebugLog(' -> Race Voice List found, but link was nil.'); end else begin DebugLog(' -> Race has no Voice List (VTCK) or list is empty.'); end; end else begin DebugLog(' -> NPC has no Race link.'); end; end else begin DebugLog(' -> Element is not an NPC_'); end; end; function GetVoiceTypeName(link: IInterface): string; begin Result := GetVoiceIDFromLink(link); end; procedure GetStandardVoicesFromSex(lst: TStringList; male : Boolean); begin if male then begin lst.Add('MaleArgonian'); lst.Add('MaleBandit'); lst.Add('MaleBrute'); lst.Add('MaleCommoner'); lst.Add('MaleCommonerAccented'); lst.Add('MaleCondescending'); lst.Add('MaleCoward'); lst.Add('MaleDarkElf'); lst.Add('MaleDrunk'); lst.Add('MaleElfHaughty'); lst.Add('MaleEvenToned'); lst.Add('MaleEvenTonedAccented'); lst.Add('MaleGuard'); lst.Add('MaleKhajiit'); lst.Add('MaleNord'); lst.Add('MaleNordCommander'); lst.Add('MaleOldGrumpy'); lst.Add('MaleOldKindly'); lst.Add('MaleOrc'); lst.Add('MaleSlyCynical'); lst.Add('MaleSoldier'); lst.Add('MaleWarlock'); lst.Add('MaleYoungEager'); end else begin lst.Add('FemaleArgonian'); lst.Add('FemaleCommander'); lst.Add('FemaleCommoner'); lst.Add('FemaleCondescending'); lst.Add('FemaleCoward'); lst.Add('FemaleDarkElf'); lst.Add('FemaleElfHaughty'); lst.Add('FemaleEvenToned'); lst.Add('FemaleKhajiit'); lst.Add('FemaleNord'); lst.Add('FemaleOldGrumpy'); lst.Add('FemaleOldKindly'); lst.Add('FemaleOrc'); lst.Add('FemaleShrill'); lst.Add('FemaleSultry'); lst.Add('FemaleYoungEager'); end; end; function ParseConditions(conditions: IInterface; lstVoiceTypes, lstIDs: TStringList): string; var condItem, ctda, param1: IInterface; i, typ: integer; funcStr, sVal: string; sl: TStringList; compVal: Double; begin sl := TStringList.Create; if ElementCount(conditions) > 0 then DebugLog('Scanning ' + IntToStr(ElementCount(conditions)) + ' conditions...'); for i := 0 to ElementCount(conditions) - 1 do begin condItem := ElementByIndex(conditions, i); ctda := ElementBySignature(condItem, 'CTDA'); if not Assigned(ctda) then ctda := condItem; funcStr := GetElementEditValues(ctda, 'Function'); typ := GetElementNativeValues(ctda, 'Type'); compVal := GetElementNativeValues(ctda, 'Comparison Value'); DebugLog(' [Cond ' + IntToStr(i) + '] Func: "' + funcStr + '" | Type: ' + IntToStr(typ) + ' | Val: ' + FloatToStr(compVal)); // SKIP: Run On Target (Bit 1) if (typ and 2) > 0 then begin DebugLog(' -> Skipping (Run On Target)'); Continue; end; // PARAM 1 param1 := ElementByName(ctda, 'Parameter #1'); if not Assigned(param1) then param1 := ElementByIndex(ctda, 5); // CASE 1: GetIsID if funcStr = 'GetIsID' then begin if (Abs(compVal - 1.0) < 0.01) then begin DebugLog(' -> Found GetIsID. Checking Actor...'); sVal := GetVoiceTypeFromNPC(LinksTo(param1)); if sVal <> '' then begin sl.Add(sVal); DebugLog(' -> SUCCESS: Added Voice: ' + sVal); end else begin DebugLog(' -> FAIL: Could not extract voice from Actor ID.'); end; end; end // CASE 2: GetIsVoiceType else if funcStr = 'GetIsVoiceType' then begin if (Abs(compVal - 1.0) < 0.01) then begin sVal := GetVoiceTypeName(param1); if sVal <> '' then begin sl.Add(sVal); DebugLog(' -> SUCCESS: Added VTYP: ' + sVal); end; end; end // CASE 3: GetIsSex else if funcStr = 'GetIsSex' then begin if GetEditValue(param1) = 'Male' then GetStandardVoicesFromSex(sl, True) else GetStandardVoicesFromSex(sl, False); end; end; lstVoiceTypes.AddStrings(sl); sl.Free; end; function Initialize: integer; begin bDebug := True; slExport := TStringList.Create; slExport.Add('game_id,voice_id,model,out_path,text'); slVoiceTypes := TStringList.Create; slVoiceTypes.Sorted := True; slVoiceTypes.Duplicates := dupIgnore; slIDs := TStringList.Create; if bDebug then AddMessage('Initializing Export Script 2.7...'); end; function Process(e: IInterface): Integer; var dial, responses, response, masterFile: IInterface; i, j: integer; line, fname, voicename, path, model, voiceTypeStr: string; begin if Signature(e) <> 'INFO' then Exit; if bDebug then AddMessage('--------------------------------------------------'); if bDebug then AddMessage('Processing INFO: ' + IntToHex(FormID(e), 8)); slVoiceTypes.Clear; slIDs.Clear; ParseConditions(ElementByName(e, 'Conditions'), slVoiceTypes, slIDs); if slVoiceTypes.Count = 0 then begin if bDebug then AddMessage('FALLBACK: No valid voices found in conditions. Exporting ALL.'); GetStandardVoicesFromSex(slVoiceTypes, True); GetStandardVoicesFromSex(slVoiceTypes, False); end; dial := LinksTo(ElementByName(e, 'Topic')); responses := ElementByName(e, 'Responses'); masterFile := MasterOrSelf(e); for i := 0 to Pred(ElementCount(responses)) do begin response := ElementByIndex(responses, i); fname := InfoFileName( GetFileName(masterFile), FormID(e), GetElementEditValues(response, 'TRDT\Response number') ); for j := 0 to Pred(slVoiceTypes.Count) do begin voiceTypeStr := slVoiceTypes[j]; if voiceTypeStr <> '' then begin voicename := 'Sound\Voice\' + GetFileName(masterFile) + '\' + voiceTypeStr + '\' + fname + '.fuz'; model := 'sk_' + LowerCase(voiceTypeStr); path := 'Data\' + voicename; line := 'skyrim,' + voiceTypeStr + ',' + model + ',' + path + ',' + '"' + StringReplace(GetElementEditValues(response, 'NAM1'), '"', '''', [rfReplaceAll, rfIgnoreCase]) + '"'; slExport.Add(line); end; end; end; end; function Finalize: integer; var dlgSave: TSaveDialog; begin if slExport.Count > 1 then begin dlgSave := TSaveDialog.Create(nil); dlgSave.Options := dlgSave.Options + [ofOverwritePrompt]; dlgSave.Filter := 'CSV files (*.csv)|*.csv'; dlgSave.InitialDir := DataPath; dlgSave.FileName := 'skyrimDialogueExport.csv'; if dlgSave.Execute then begin AddMessage('Saving ' + dlgSave.FileName); slExport.SaveToFile(dlgSave.FileName); end; dlgSave.Free; end; slExport.Free; slVoiceTypes.Free; slIDs.Free; end; end. Couple of things to note, since I'm not trying to spend a bunch of time on this script: It doesn't check faction conditions. This shouldn't be hard, but I didn't bother. It DOES check NPC sex conditions, but if it's essentially Player.IsMale, it will add ALL male voice types. You can add a manual check for that condition though I hardcoded voice types I found off the wiki. No clue how you personally handle unique voice types like Cicero so I assumed this is fine Guards add all voice types. I think you can limit this though? I've only heard a handful of voices from guards, but wasn't 100% sure so. In other words, it's not perfect but I've included tons of debug printing and what not to make it super easy to improve the script. Edit: Btw, I plan on releasing a new slavery mod soon. Could you share the quick steps of using that voice generator on these files to save me some time? I plan to just do exactly what you're doing for my mod. Export voices, generate. I'm assuming this is done in one big batch..? Edited December 17, 2025 by asdt123123
kingsglaive Posted December 18, 2025 Posted December 18, 2025 Hello, I really like the SubmissiveLolaResubmission mod. Some authors have updated Lola's Voice Files before, but they have stopped now. Hex Bolt recently updated SubmissiveLolaResubmission significantly. Could you create its Voice Files?
bigbasi Posted December 18, 2025 Author Posted December 18, 2025 (edited) 19 hours ago, asdt123123 said: I wrote a quick script that does essentially what you're asking: Holy cow... WTF? I read over it and looks ok, I'll give it a try an let you know how it works! Thanks a lot man! This looks so much simpler, than the script I am using now 19 hours ago, asdt123123 said: Btw, I plan on releasing a new slavery mod soon. Could you share the quick steps of using that voice generator on these files to save me some time? I plan to just do exactly what you're doing for my mod. Export voices, generate. I'm assuming this is done in one big batch..? I'm looking forward to your mod, really! I like to play those kind of mod. Once If tested your script I can try to write down the steps I need to do, to mak it work 7 hours ago, kingsglaive said: Hello, I really like the SubmissiveLolaResubmission mod. Some authors have updated Lola's Voice Files before, but they have stopped now. Hex Bolt recently updated SubmissiveLolaResubmission significantly. Could you create its Voice Files? Holy Shit, you are asking for not a small favor Buddy. Total new lines: 193394, to generate the voice files it'll take weeks. (for the whole mod) No wonder nobody continues to make new voicefiles 😉 But I'll check if I can make a delta voice pack starting from 2.1.8, like I did for Laura, probably faster. Edit: delta are 24120 new lines, thats doable, should be done tomorrow CET. Edited December 18, 2025 by bigbasi
kamithemoon Posted December 21, 2025 Posted December 21, 2025 On 12/17/2025 at 3:02 PM, asdt123123 said: I wrote a quick script that does essentially what you're asking: Reveal hidden contents { Export dialogues for Skyrim SE for use with xVASynth. VERSION: 2.7 } unit SkyrimSEExportDialogues; var slExport, slVoiceTypes, slIDs: TStringList; bDebug: Boolean; procedure DebugLog(s: string); begin if bDebug then AddMessage('[DEBUG] ' + s); end; function InfoFileName(PluginName: string; InfoFormID: integer; RespNumber: string): string; begin PluginName := ChangeFileExt(PluginName, ''); Result := Format('%s_%s_%s', [ PluginName, IntToHex(InfoFormID and $FFFFFF, 8), RespNumber ]); end; //heelper to get Editor ID of a Voice Type link safely function GetVoiceIDFromLink(e: IInterface): string; var rec: IInterface; begin Result := ''; if not Assigned(e) then Exit; rec := WinningOverride(LinksTo(e)); if Assigned(rec) and (Signature(rec) = 'VTYP') then Result := EditorID(rec); end; function GetVoiceTypeFromNPC(e: IInterface): string; var vtyp, race, baseNPC, tplt, vList, child: IInterface; sig, tpltFlags: string; iter, i: integer; begin Result := ''; if not Assigned(e) then Exit; e := WinningOverride(e); sig := Signature(e); DebugLog(' -> Resolving Actor: ' + Name(e)); // Resolve Reference (ACHR/REFR) to Base NPC if (sig = 'ACHR') or (sig = 'REFR') then begin baseNPC := WinningOverride(LinksTo(ElementBySignature(e, 'NAME'))); if Assigned(baseNPC) then begin e := baseNPC; sig := Signature(e); DebugLog(' -> Resolved Reference to Base: ' + Name(e)); end else begin DebugLog(' -> Could not resolve Base NPC for Reference.'); Exit; end; end; if sig = 'NPC_' then begin // Handle TEMPLATES for iter := 0 to 5 do begin tpltFlags := GetElementEditValues(e, 'ACBS\Template Flags'); if Pos('Use Traits', tpltFlags) > 0 then begin tplt := WinningOverride(LinksTo(ElementBySignature(e, 'TPLT'))); if Assigned(tplt) then begin DebugLog(' -> Inherits Traits from Template: ' + Name(tplt)); e := tplt; Continue; end; end; Break; end; // Try Explicit VTYP vtyp := ElementBySignature(e, 'VTYP'); if not Assigned(vtyp) then vtyp := ElementByName(e, 'VTYP - Voice Type'); // Try VTCK on NPC if not Assigned(vtyp) then vtyp := ElementBySignature(e, 'VTCK'); if Assigned(vtyp) then begin Result := GetVoiceIDFromLink(vtyp); if Result <> '' then begin DebugLog(' -> Found NPC Voice: ' + Result); Exit; end; end; // Fallback: Check Race (RNAM) -> VTCK (Voices To Check) // Get WinningOverride of the Race to ensure we see lists added by mods/patches race := WinningOverride(LinksTo(ElementBySignature(e, 'RNAM'))); if Assigned(race) then begin DebugLog(' -> Checking Race: ' + Name(race)); // Try Standard VTCK Signature vList := ElementBySignature(race, 'VTCK'); // If not found, try searching children (Brute force for "Voices") if not Assigned(vList) then begin for i := 0 to ElementCount(race) - 1 do begin child := ElementByIndex(race, i); if (Signature(child) = 'VTCK') or (Name(child) = 'Voices') then begin vList := child; Break; end; end; end; if Assigned(vList) and (ElementCount(vList) > 0) then begin // Grab the first one in the list // ElementByIndex(vList, 0) gives the reference inside the list vtyp := ElementByIndex(vList, 0); Result := GetVoiceIDFromLink(vtyp); if Result <> '' then DebugLog(' -> Found Race Default Voice: ' + Result) else DebugLog(' -> Race Voice List found, but link was nil.'); end else begin DebugLog(' -> Race has no Voice List (VTCK) or list is empty.'); end; end else begin DebugLog(' -> NPC has no Race link.'); end; end else begin DebugLog(' -> Element is not an NPC_'); end; end; function GetVoiceTypeName(link: IInterface): string; begin Result := GetVoiceIDFromLink(link); end; procedure GetStandardVoicesFromSex(lst: TStringList; male : Boolean); begin if male then begin lst.Add('MaleArgonian'); lst.Add('MaleBandit'); lst.Add('MaleBrute'); lst.Add('MaleCommoner'); lst.Add('MaleCommonerAccented'); lst.Add('MaleCondescending'); lst.Add('MaleCoward'); lst.Add('MaleDarkElf'); lst.Add('MaleDrunk'); lst.Add('MaleElfHaughty'); lst.Add('MaleEvenToned'); lst.Add('MaleEvenTonedAccented'); lst.Add('MaleGuard'); lst.Add('MaleKhajiit'); lst.Add('MaleNord'); lst.Add('MaleNordCommander'); lst.Add('MaleOldGrumpy'); lst.Add('MaleOldKindly'); lst.Add('MaleOrc'); lst.Add('MaleSlyCynical'); lst.Add('MaleSoldier'); lst.Add('MaleWarlock'); lst.Add('MaleYoungEager'); end else begin lst.Add('FemaleArgonian'); lst.Add('FemaleCommander'); lst.Add('FemaleCommoner'); lst.Add('FemaleCondescending'); lst.Add('FemaleCoward'); lst.Add('FemaleDarkElf'); lst.Add('FemaleElfHaughty'); lst.Add('FemaleEvenToned'); lst.Add('FemaleKhajiit'); lst.Add('FemaleNord'); lst.Add('FemaleOldGrumpy'); lst.Add('FemaleOldKindly'); lst.Add('FemaleOrc'); lst.Add('FemaleShrill'); lst.Add('FemaleSultry'); lst.Add('FemaleYoungEager'); end; end; function ParseConditions(conditions: IInterface; lstVoiceTypes, lstIDs: TStringList): string; var condItem, ctda, param1: IInterface; i, typ: integer; funcStr, sVal: string; sl: TStringList; compVal: Double; begin sl := TStringList.Create; if ElementCount(conditions) > 0 then DebugLog('Scanning ' + IntToStr(ElementCount(conditions)) + ' conditions...'); for i := 0 to ElementCount(conditions) - 1 do begin condItem := ElementByIndex(conditions, i); ctda := ElementBySignature(condItem, 'CTDA'); if not Assigned(ctda) then ctda := condItem; funcStr := GetElementEditValues(ctda, 'Function'); typ := GetElementNativeValues(ctda, 'Type'); compVal := GetElementNativeValues(ctda, 'Comparison Value'); DebugLog(' [Cond ' + IntToStr(i) + '] Func: "' + funcStr + '" | Type: ' + IntToStr(typ) + ' | Val: ' + FloatToStr(compVal)); // SKIP: Run On Target (Bit 1) if (typ and 2) > 0 then begin DebugLog(' -> Skipping (Run On Target)'); Continue; end; // PARAM 1 param1 := ElementByName(ctda, 'Parameter #1'); if not Assigned(param1) then param1 := ElementByIndex(ctda, 5); // CASE 1: GetIsID if funcStr = 'GetIsID' then begin if (Abs(compVal - 1.0) < 0.01) then begin DebugLog(' -> Found GetIsID. Checking Actor...'); sVal := GetVoiceTypeFromNPC(LinksTo(param1)); if sVal <> '' then begin sl.Add(sVal); DebugLog(' -> SUCCESS: Added Voice: ' + sVal); end else begin DebugLog(' -> FAIL: Could not extract voice from Actor ID.'); end; end; end // CASE 2: GetIsVoiceType else if funcStr = 'GetIsVoiceType' then begin if (Abs(compVal - 1.0) < 0.01) then begin sVal := GetVoiceTypeName(param1); if sVal <> '' then begin sl.Add(sVal); DebugLog(' -> SUCCESS: Added VTYP: ' + sVal); end; end; end // CASE 3: GetIsSex else if funcStr = 'GetIsSex' then begin if GetEditValue(param1) = 'Male' then GetStandardVoicesFromSex(sl, True) else GetStandardVoicesFromSex(sl, False); end; end; lstVoiceTypes.AddStrings(sl); sl.Free; end; function Initialize: integer; begin bDebug := True; slExport := TStringList.Create; slExport.Add('game_id,voice_id,model,out_path,text'); slVoiceTypes := TStringList.Create; slVoiceTypes.Sorted := True; slVoiceTypes.Duplicates := dupIgnore; slIDs := TStringList.Create; if bDebug then AddMessage('Initializing Export Script 2.7...'); end; function Process(e: IInterface): Integer; var dial, responses, response, masterFile: IInterface; i, j: integer; line, fname, voicename, path, model, voiceTypeStr: string; begin if Signature(e) <> 'INFO' then Exit; if bDebug then AddMessage('--------------------------------------------------'); if bDebug then AddMessage('Processing INFO: ' + IntToHex(FormID(e), 8)); slVoiceTypes.Clear; slIDs.Clear; ParseConditions(ElementByName(e, 'Conditions'), slVoiceTypes, slIDs); if slVoiceTypes.Count = 0 then begin if bDebug then AddMessage('FALLBACK: No valid voices found in conditions. Exporting ALL.'); GetStandardVoicesFromSex(slVoiceTypes, True); GetStandardVoicesFromSex(slVoiceTypes, False); end; dial := LinksTo(ElementByName(e, 'Topic')); responses := ElementByName(e, 'Responses'); masterFile := MasterOrSelf(e); for i := 0 to Pred(ElementCount(responses)) do begin response := ElementByIndex(responses, i); fname := InfoFileName( GetFileName(masterFile), FormID(e), GetElementEditValues(response, 'TRDT\Response number') ); for j := 0 to Pred(slVoiceTypes.Count) do begin voiceTypeStr := slVoiceTypes[j]; if voiceTypeStr <> '' then begin voicename := 'Sound\Voice\' + GetFileName(masterFile) + '\' + voiceTypeStr + '\' + fname + '.fuz'; model := 'sk_' + LowerCase(voiceTypeStr); path := 'Data\' + voicename; line := 'skyrim,' + voiceTypeStr + ',' + model + ',' + path + ',' + '"' + StringReplace(GetElementEditValues(response, 'NAM1'), '"', '''', [rfReplaceAll, rfIgnoreCase]) + '"'; slExport.Add(line); end; end; end; end; function Finalize: integer; var dlgSave: TSaveDialog; begin if slExport.Count > 1 then begin dlgSave := TSaveDialog.Create(nil); dlgSave.Options := dlgSave.Options + [ofOverwritePrompt]; dlgSave.Filter := 'CSV files (*.csv)|*.csv'; dlgSave.InitialDir := DataPath; dlgSave.FileName := 'skyrimDialogueExport.csv'; if dlgSave.Execute then begin AddMessage('Saving ' + dlgSave.FileName); slExport.SaveToFile(dlgSave.FileName); end; dlgSave.Free; end; slExport.Free; slVoiceTypes.Free; slIDs.Free; end; end. Couple of things to note, since I'm not trying to spend a bunch of time on this script: It doesn't check faction conditions. This shouldn't be hard, but I didn't bother. It DOES check NPC sex conditions, but if it's essentially Player.IsMale, it will add ALL male voice types. You can add a manual check for that condition though I hardcoded voice types I found off the wiki. No clue how you personally handle unique voice types like Cicero so I assumed this is fine Guards add all voice types. I think you can limit this though? I've only heard a handful of voices from guards, but wasn't 100% sure so. In other words, it's not perfect but I've included tons of debug printing and what not to make it super easy to improve the script. Edit: Btw, I plan on releasing a new slavery mod soon. Could you share the quick steps of using that voice generator on these files to save me some time? I plan to just do exactly what you're doing for my mod. Export voices, generate. I'm assuming this is done in one big batch..? I've been testing dialogue export scripts, including yours, I'm running into some oddities. With Doublecheeseburger's Dialogue Export Script, TheAncientProfession will generate 45815 lines of dialogue With you script it will generate 65279 lines of dialogue And with the Oblivion Dialogue Export Script133320 lines of dialogue Those seem like waaaay big numbers. I've been using Doublecheeseburger's script for awhile now and the main issue I've been having with it is due to factions and quest aliases generating dialogue bloat. Factions: In the vanilla game, only FemaleNord, MaleGuard, and MaleNord commander can be guards and their dialogue conditions generally just say something like "has faction guards = 1" or something and isn't associated with a voice type or particular NPC. So since there's no particular voice condition for them, the dialogue export script will generate dialogue for all available voice types which leads to massive dialogue bloat Aliases: This happens in scenes a lot. I don't think I've ever really seen scene dialogue with individual conditions on the speaker, nor do there seem to be conditions on the controlling quest. Instead, I'm guessing authors use scripts to fill aliases, which I would guess that the dialogue export script cannot detect. So you end up with a particular line of dialogue that doesn't appear to have any voice conditions associated with them so the script will generate them for all possible voice types. If you're still working on a dialogue export script, may I ask you to modify Doublecheeseburger's script to cross reference vanilla factions for potential voice types? Lots of mods might write dialogue for bandits, for example, and if the script could generate voice files only for potential vanilla bandit voice types, that could cut down on a great deal of bloat. And also, if you could get aliases to work properly, that would be wonderful too but I'm guessing that would not be easy. But thankfully bloat only happens for scene dialogue and those can be identified and removed manually.
asdt123123 Posted December 21, 2025 Posted December 21, 2025 (edited) 1 hour ago, kamithemoon said: I've been testing dialogue export scripts, including yours, I'm running into some oddities. With Doublecheeseburger's Dialogue Export Script, TheAncientProfession will generate 45815 lines of dialogue With you script it will generate 65279 lines of dialogue And with the Oblivion Dialogue Export Script133320 lines of dialogue Those seem like waaaay big numbers. I've been using Doublecheeseburger's script for awhile now and the main issue I've been having with it is due to factions and quest aliases generating dialogue bloat. Factions: In the vanilla game, only FemaleNord, MaleGuard, and MaleNord commander can be guards and their dialogue conditions generally just say something like "has faction guards = 1" or something and isn't associated with a voice type or particular NPC. So since there's no particular voice condition for them, the dialogue export script will generate dialogue for all available voice types which leads to massive dialogue bloat Aliases: This happens in scenes a lot. I don't think I've ever really seen scene dialogue with individual conditions on the speaker, nor do there seem to be conditions on the controlling quest. Instead, I'm guessing authors use scripts to fill aliases, which I would guess that the dialogue export script cannot detect. So you end up with a particular line of dialogue that doesn't appear to have any voice conditions associated with them so the script will generate them for all possible voice types. If you're still working on a dialogue export script, may I ask you to modify Doublecheeseburger's script to cross reference vanilla factions for potential voice types? Lots of mods might write dialogue for bandits, for example, and if the script could generate voice files only for potential vanilla bandit voice types, that could cut down on a great deal of bloat. And also, if you could get aliases to work properly, that would be wonderful too but I'm guessing that would not be easy. But thankfully bloat only happens for scene dialogue and those can be identified and removed manually. Hey my script isn't really intended to be used as is - just an example. The output path isn't even correct. It should be Branch_Topic_ID. Just there to learn from. In somewhat related news, I've been considering working on a new voice generator from finetuning, but the models are getting insane in size and still have issues with expressing emotion (Only tried with MaleNord). So now I'm experimenting with voice cloning models with SOME success. So far this is the best model I've found for cloning: https://github.com/index-tts/index-tts - https://huggingface.co/IndexTeam/IndexTTS-2 Great voice modulation with very few artifacts - but no emotional context creates somewhat out-of-place voices. so my plan now is to maybe fine tune an LLM or just hard-code some emotion controller for each dialogue line to use in the audio context. Or maybe we can request that mod authors tag text for emotional effect? Like SAD, ANGRY - etc (Or use built in expressions?). Idk, my ramble is over. Point is, we can do better then that SnythX mod and still run locally. Here's a demo of IndexTTS-2: https://huggingface.co/spaces/IndexTeam/IndexTTS-2-Demo Edited December 21, 2025 by asdt123123 1
kamithemoon Posted December 22, 2025 Posted December 22, 2025 (edited) 2 hours ago, asdt123123 said: Hey my script isn't really intended to be used as is - just an example. The output path isn't even correct. It should be Branch_Topic_ID. Just there to learn from. In somewhat related news, I've been considering working on a new voice generator from finetuning, but the models are getting insane in size and still have issues with expressing emotion (Only tried with MaleNord). So now I'm experimenting with voice cloning models with SOME success. So far this is the best model I've found for cloning: https://github.com/index-tts/index-tts - https://huggingface.co/IndexTeam/IndexTTS-2 Great voice modulation with very few artifacts - but no emotional context creates somewhat out-of-place voices. so my plan now is to maybe fine tune an LLM or just hard-code some emotion controller for each dialogue line to use in the audio context. Or maybe we can request that mod authors tag text for emotional effect? Like SAD, ANGRY - etc (Or use built in expressions?). Idk, my ramble is over. Point is, we can do better then that SnythX mod and still run locally. Here's a demo of IndexTTS-2: https://huggingface.co/spaces/IndexTeam/IndexTTS-2-Demo Authors do tag text for emotional intensity. It goes from 0 - 100 and has Happy, Angry, Surprised, Fearful, Neutral, and Confused. The original dialogue extraction scripts were built for xVASynth though so the emotional bit wasn't used. I've been building voices oldskool with the Tortoise + RVC combo. It works well for the most part and can even generate some emotion though not much. But the two biggest hurdles I've been facing are dialogue bloat, which I mentioned earlier, and context. For context, with the Animal Research voices I made, I checked each one for quality and they sound fine individually without context. But in game is when I find out things do not match. For example, something simple like "Yes." might appear a dozen times or so but all I see is "Yes." and have no idea what the context is so in game it might come out super weird. Oh, I must say, I'm liking IndexTTS-2. Do you happen to have a guide on how to install and use it locally? I was following this one but I keep running into an issue with the initial download of "This repository exceed its LFS budget" Edited December 22, 2025 by kamithemoon
asdt123123 Posted December 22, 2025 Posted December 22, 2025 (edited) 2 hours ago, kamithemoon said: Authors do tag text for emotional intensity. It goes from 0 - 100 and has Happy, Angry, Surprised, Fearful, Neutral, and Confused. The original dialogue extraction scripts were built for xVASynth though so the emotional bit wasn't used. I've been building voices oldskool with the Tortoise + RVC combo. It works well for the most part and can even generate some emotion though not much. But the two biggest hurdles I've been facing are dialogue bloat, which I mentioned earlier, and context. For context, with the Animal Research voices I made, I checked each one for quality and they sound fine individually without context. But in game is when I find out things do not match. For example, something simple like "Yes." might appear a dozen times or so but all I see is "Yes." and have no idea what the context is so in game it might come out super weird. Oh, I must say, I'm liking IndexTTS-2. Do you happen to have a guide on how to install and use it locally? I was following this one but I keep running into an issue with the initial download of "This repository exceed its LFS budget" Yeah their LFS budget has been cooked for days. On Github just manually click Code -> Download ZIP. When you're installing, don't do uv sync --all-extras. Deepspeed is buggy as fuck on Windows. Just do uv sync --extra webui Then get the model: uv tool install "huggingface-hub[cli,hf_xet]" hf download IndexTeam/IndexTTS-2 --local-dir=checkpoints And that's all you need to do. Edit: Forgot to mention. When you're using the mode - set the temperature low to like 0.4 if not lower. Use emotion vectors. And with your input audio, make absolute sure it doesn't contain pauses. This model fucking LIKES pausing randomly in audio. If your input audio has pauses (from commas, etc), cut it out even if it sounds a bit weird. Here's my super basic script for automating voice generation. I only included a few races. Extract this in the same folder as index-tts. Run it using uv run skyrim_voice_generator.py This is just a quick thing I put together so don't expect greatness. If you manage to get better results, SHARE 🙏 Make sure you reformat the .wav files to what skyrim expects: mono 41k hz 16bit skyrim_voice_generator.zip Edited December 22, 2025 by asdt123123
kamithemoon Posted December 22, 2025 Posted December 22, 2025 48 minutes ago, asdt123123 said: Yeah their LFS budget has been cooked for days. On Github just manually click Code -> Download ZIP. Shoot, I should have mentioned that I already tried that. The file is only 31.8 mb large and the extracted files seem to be broken. For example, all the example audio is only 131 bytes large and contain no actual audio. Same is true with your original link to Index TTS. Dang, I kinda figured it was a github issue. I guess all I can do is wait until the new month and see if his tokens or whatever resets itself.
asdt123123 Posted December 22, 2025 Posted December 22, 2025 57 minutes ago, kamithemoon said: Shoot, I should have mentioned that I already tried that. The file is only 31.8 mb large and the extracted files seem to be broken. For example, all the example audio is only 131 bytes large and contain no actual audio. Same is true with your original link to Index TTS. Dang, I kinda figured it was a github issue. I guess all I can do is wait until the new month and see if his tokens or whatever resets itself. You don't need any of those audio files. They're purely for testing their examples. The program works flawlessly without them.
kamithemoon Posted December 22, 2025 Posted December 22, 2025 (edited) 2 hours ago, asdt123123 said: You don't need any of those audio files. They're purely for testing their examples. The program works flawlessly without them. Sweet! Using your guide, I got it working. Next question, do you have a script for extracting voice files for a mod in a format that IndexTTS can use to batch generate? Originally, I was using the Audiobook maker from Jarod's Journey and a script written by @Killer905 to batch generate individual audio files and rename them into the format needed for the quest. Then I'd use RunaLip to make the fuz files. Edited December 22, 2025 by kamithemoon
bigbasi Posted December 22, 2025 Author Posted December 22, 2025 Just thought I hop onto the train and try to get this TTS Model Working to! the last voicefiles sound amazing, so yeah atm I'm trying to download the model and get it working
kamithemoon Posted December 22, 2025 Posted December 22, 2025 18 hours ago, asdt123123 said: Here's my super basic script for automating voice generation. I only included a few races. Extract this in the same folder as index-tts. Run it using uv run skyrim_voice_generator.py This is just a quick thing I put together so don't expect greatness. If you manage to get better results, SHARE 🙏 Make sure you reformat the .wav files to what skyrim expects: mono 41k hz 16bit skyrim_voice_generator.zip 1.65 MB · 1 download Sweet, I got it working mostly and figured out the file you need is lines.csv. But next question, what type of formatting do you need to read lines.csv. I tried the default formatting for xVASynth and also with just file name and text and neither of them loaded correctly, or else my output was 0 for a FemaleEventoned voice files.
asdt123123 Posted December 23, 2025 Posted December 23, 2025 (edited) 7 hours ago, bigbasi said: Just thought I hop onto the train and try to get this TTS Model Working to! the last voicefiles sound amazing, so yeah atm I'm trying to download the model and get it working I think we could all collaborate and manage to make a really good voice system based on this model. If you check out my mini-project, I was messing with emotion vectors based on the comment. So "Hey you!!" is angry, "Hey you!" is mean, "Who are you?" is question, etc. Super simple - but it's difficult to derive emotion from text lol. Like, "Hey you!" - could be a friendly greeting. Or it could be a - hey stop right there criminal type thing lol. Just to put some more context into the code: In tts.infer - you'll see a "do_sample" variable (In the webUI it's named gpt2 I think?). This toggles the sampling to use greedy search instead. So instead of using an LLM, for every step of generation, it strictly picks the single token with the highest probability. So that might be something you want to mess with. You can see I set the temperature to 0.4 and enabled sampling. Emotion vectors: Here's the emotion vectors: Happy - vec1 Angry - vec2 Sad - vec3 Fear / Afraid - vec4 Disgust - vec5 Melancholic / Depressed - vec6 Surprise - vec7 Calm / Neutral - vec8 so [1.0, 0, 0, 0, 0, 0, 0, 1.0] = Happy at 1, Calm at 1. I haven't tried values over 1, I assume they're capped there since it gets pretty wild at 1 lol In the inference code (normalize_emo_vec function), the model applies a "bias" to these inputs before generating audio. This means setting a slider to "1.0" does not affect the model equally for every emotion. That's why I made a separate config for each voice. The model explicitly dampens Surprise and Calm: Happy/Disgust/Melancholic are multiplied by ~0.94. Angry is multiplied by 0.875. Sad/Fear are passed through fully (1.0). Surprise is multiplied by 0.68. Calm is multiplied by 0.56. This is likely more of a normalization then anything but it's still something to note. If you do not include an emotion vector, the model will derive emotions from the input voice you gave it. SO "tts.infer(spk_audio_prompt='examples/voice_01.wav', text=text, output_path="gen.wav", verbose=True)" = Tells the model to derrive the emotion data from the input audio. You COULD possibly use this to improve the output more..? I went straight to emotion vectors and never tested this. Obviously you'd need different input voices like: MaleNord_mad.wav, MaleNord_happy.wav - etc. Tokenization: I noticed the model has some strange subword tokenization. Might be something worth looking into if you experience issues. I say that purely because this is a Chinese made model, so might have issues with English? Here's an example: That = _That Stomach = _S to ma ch This is just their BPE model at work basically, so theoretically could be absolutely fine. I'm just noting it because again - this is a Chinese trained model. So MIGHT have to include specific pronunciation for certain stuff if we have problems. Final notes: I set max_text_tokens_per_segment to 600 to basically force the model to use more context in simple terms. It'll help with flow, and likely prevent weird pauses more. Should be low enough to avoid artifacts, and not use too much extra VRAM. I haven't touched top_p and top_k. I usually use 0.8 or 0.9 in LLMs and never touch top_k. I only really mess with temperature. Lower the temp, more deterministic which is largely what we want here. 2 hours ago, kamithemoon said: Sweet, I got it working mostly and figured out the file you need is lines.csv. But next question, what type of formatting do you need to read lines.csv. I tried the default formatting for xVASynth and also with just file name and text and neither of them loaded correctly, or else my output was 0 for a FemaleEventoned voice files. It will parse those cvs files outputted from the script we wrote for xEdit->xVASynth. Doesn't take anything custom. If you have trouble, just ask ChatGPT or something to fix the formatting and give it the python script and first 5 lines of your lines.cvs. Edited December 23, 2025 by asdt123123
kamithemoon Posted December 23, 2025 Posted December 23, 2025 (edited) 28 minutes ago, asdt123123 said: I think we could all collaborate and manage to make a really good voice system based on this model. If you check out my mini-project, I was messing with emotion vectors based on the comment. So "Hey you!!" is angry, "Hey you!" is mean, "Who are you?" is question, etc. Super simple - but it's difficult to derive emotion from text lol. Like, "Hey you!" - could be a friendly greeting. Or it could be a - hey stop right there criminal type thing lol. Just to put some more context into the code: In tts.infer - you'll see a "do_sample" variable (In the webUI it's named gpt2 I think?). This toggles the sampling to use greedy search instead. So instead of using an LLM, for every step of generation, it strictly picks the single token with the highest probability. So that might be something you want to mess with. You can see I set the temperature to 0.4 and enabled sampling. Emotion vectors: Here's the emotion vectors: Happy - vec1 Angry - vec2 Sad - vec3 Fear / Afraid - vec4 Disgust - vec5 Melancholic / Depressed - vec6 Surprise - vec7 Calm / Neutral - vec8 so [1.0, 0, 0, 0, 0, 0, 0, 1.0] = Happy at 1, Calm at 1. I haven't tried values over 1, I assume they're capped there since it gets pretty wild at 1 lol In the inference code (normalize_emo_vec function), the model applies a "bias" to these inputs before generating audio. This means setting a slider to "1.0" does not affect the model equally for every emotion. That's why I made a separate config for each voice. The model explicitly dampens Surprise and Calm: Happy/Disgust/Melancholic are multiplied by ~0.94. Angry is multiplied by 0.875. Sad/Fear are passed through fully (1.0). Surprise is multiplied by 0.68. Calm is multiplied by 0.56. This is likely more of a normalization then anything but it's still something to note. If you do not include an emotion vector, the model will derive emotions from the input voice you gave it. SO "tts.infer(spk_audio_prompt='examples/voice_01.wav', text=text, output_path="gen.wav", verbose=True)" = Tells the model to derrive the emotion data from the input audio. You COULD possibly use this to improve the output more..? I went straight to emotion vectors and never tested this. Obviously you'd need different input voices like: MaleNord_mad.wav, MaleNord_happy.wav - etc. Tokenization: I noticed the model has some strange subword tokenization. Might be something worth looking into if you experience issues. I say that purely because this is a Chinese made model, so might have issues with English? Here's an example: That = _That Stomach = _S to ma ch This is just their BPE model at work basically, so theoretically could be absolutely fine. I'm just noting it because again - this is a Chinese trained model. So MIGHT have to include specific pronunciation for certain stuff if we have problems. Final notes: I set max_text_tokens_per_segment to 600 to basically force the model to use more context in simple terms. It'll help with flow, and likely prevent weird pauses more. Should be low enough to avoid artifacts, and not use too much extra VRAM. I haven't touched top_p and top_k. I usually use 0.8 or 0.9 in LLMs and never touch top_k. I only really mess with temperature. Lower the temp, more deterministic which is largely what we want here. It will parse those cvs files outputted from the script we wrote for xEdit->xVASynth. Doesn't take anything custom. If you have trouble, just ask ChatGPT or something to fix the formatting and give it the python script and first 5 lines of your lines.cvs. This is exciting! It took some tweaking but I have a batch generation for FemaleEventoned for Animal Research going. The initial output quality does seem less than what I get out of Tortoise but once it's done generating, I'll post process though RVC to see if that improves things. At the very least, IndexTTS seems MUCH more consistent when generating dialogue and there's a lot less broken generations. If nothing else, it could be a great fallback tool for generations that Tortoise has trouble with. This tool and your script was quite easy to use so I would say that ultimately, I would want it in the hands of the mod authors. The mod authors are the ones that understand the emotional context of their dialogue and would be best suited to generating dialogue that's suitable. I'm looking forward to the day when new mods will come with pregenerated voices. Before yesterday, I have never once used ChatGPT and was only vaguely aware of its existence. But it's turned out to be an invaluable tool for troubleshooting crash logs. Edited December 23, 2025 by kamithemoon
kamithemoon Posted December 23, 2025 Posted December 23, 2025 Hrm, RVC post processing makes it sound ALOT better. Check out these 2 generations. The 1st one is IndexTTS and the other is Tortoise. IndexTTS.mp3 Tortoise.mp3
asdt123123 Posted December 23, 2025 Posted December 23, 2025 1 hour ago, kamithemoon said: Hrm, RVC post processing makes it sound ALOT better. Check out these 2 generations. The 1st one is IndexTTS and the other is Tortoise. IndexTTS.mp3 Tortoise.mp3 RVC is for sure something to look into. I'm only concerned it will have a lot of trouble with like Nord voice types for example. We do still have the ability to finetune these models for specific characters, but finetunes/loras will still have a lot of issues with emotion expression. And agan, the nord voice is pretty difficult to work with. I was actually amazed Index clones Nord voices so well.
bigbasi Posted February 2 Author Posted February 2 3 hours ago, Caligula Big said: RR just got updated! Hooray! on my way!
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now