@@ -60,7 +60,7 @@ public static Dictionary<int, int>
6060 {
6161 //シーンごとにMaxLayerを取得
6262 true => tl . Select ( ( v , i ) => ( Scene : i , MaxLayer : ( int ) v [ "MaxLayer" ] ! ) ) ,
63- _ => [ ( Scene : 0 , MaxLayer : ( int ) tl [ "MaxLayer" ] ! ) ] ,
63+ _ => [ ( Scene : 0 , MaxLayer : ( int ) tl [ "MaxLayer" ] ! ) ] ,
6464 } ;
6565
6666 return maxLayers . ToDictionary ( x => x . Scene , x => x . MaxLayer ) ;
@@ -80,7 +80,7 @@ public static async ValueTask<List<YmmCharacter>> ParseCharactersAsync(JObject y
8080 } ) ;
8181 }
8282
83- public static async ValueTask < IEnumerable < ( int Scene , YmmVoiceItem Item ) > >
83+ public static async ValueTask < IEnumerable < ( int Scene , YmmVoiceItem Item ) > >
8484 ParseVoiceItemsAsync (
8585 JObject ymmp
8686 )
@@ -120,7 +120,7 @@ private static Dictionary<int, JArray>
120120 return items ;
121121 }
122122
123- public static async ValueTask < IEnumerable < ( int Scene , YmmVoiceItem Item ) > >
123+ public static async ValueTask < IEnumerable < ( int Scene , YmmVoiceItem Item ) > >
124124 FilterCustomVoiceAsync (
125125 IEnumerable < ( int Scene , YmmVoiceItem Item ) > voices
126126 )
@@ -196,7 +196,8 @@ public static async ValueTask MakeRipSyncItemAsync(
196196 int insertLayer = 0 ,
197197 int offsetFrame = 0 ,
198198 bool isLocked = false ,
199- int sceneIndex = 0
199+ int sceneIndex = 0 ,
200+ int visualLeadFrames = 0
200201 )
201202 {
202203 if ( lab is null || lab . Lines is null )
@@ -280,62 +281,62 @@ public static async ValueTask MakeRipSyncItemAsync(
280281 switch ( line . Phoneme )
281282 {
282283 case var p when VOWELS_A . Contains ( p ) :
283- {
284- imageFileName = images [ "a" ] ;
285- lastVowel = imageFileName ;
286- break ;
287- }
284+ {
285+ imageFileName = images [ "a" ] ;
286+ lastVowel = imageFileName ;
287+ break ;
288+ }
288289
289290 case var p when VOWELS_I . Contains ( p ) :
290- {
291- imageFileName = images [ "i" ] ;
292- lastVowel = imageFileName ;
293- break ;
294- }
291+ {
292+ imageFileName = images [ "i" ] ;
293+ lastVowel = imageFileName ;
294+ break ;
295+ }
295296
296297 case var p when VOWELS_U . Contains ( p ) :
297- {
298- imageFileName = images [ "u" ] ;
299- lastVowel = imageFileName ;
300- break ;
301- }
298+ {
299+ imageFileName = images [ "u" ] ;
300+ lastVowel = imageFileName ;
301+ break ;
302+ }
302303
303304 case var p when VOWELS_E . Contains ( p ) :
304- {
305- imageFileName = images [ "e" ] ;
306- lastVowel = imageFileName ;
307- break ;
308- }
305+ {
306+ imageFileName = images [ "e" ] ;
307+ lastVowel = imageFileName ;
308+ break ;
309+ }
309310
310311 case var p when VOWELS_O . Contains ( p ) :
311- {
312- imageFileName = images [ "o" ] ;
313- lastVowel = imageFileName ;
314- break ;
315- }
312+ {
313+ imageFileName = images [ "o" ] ;
314+ lastVowel = imageFileName ;
315+ break ;
316+ }
316317
317318 case var p when CLOSE_CONSONANT . Contains ( p ) :
318- {
319- imageFileName = images [ "N" ] ;
320- break ;
321- }
319+ {
320+ imageFileName = images [ "N" ] ;
321+ break ;
322+ }
322323
323324 case var p when OPEN_CONSONANT . Contains ( p ) :
324- {
325- imageFileName = consoOpt switch
326325 {
327- ConsonantOption . CONTINUE_BEFORE_VOWEL => lastVowel ,
328- ConsonantOption . SMALL_MOUSE => images [ "u" ] , //TODO:代理処理
329- _ => images [ "N" ] ,
330- } ;
331- break ;
332- }
326+ imageFileName = consoOpt switch
327+ {
328+ ConsonantOption . CONTINUE_BEFORE_VOWEL => lastVowel ,
329+ ConsonantOption . SMALL_MOUSE => images [ "u" ] , //TODO:代理処理
330+ _ => images [ "N" ] ,
331+ } ;
332+ break ;
333+ }
333334
334335 default :
335- {
336- imageFileName = images [ "N" ] ;
337- break ;
338- }
336+ {
337+ imageFileName = images [ "N" ] ;
338+ break ;
339+ }
339340 }
340341
341342 var mouseImagePath = Path . Combine ( lipSyncOption . MouseDir ! , imageFileName ) ;
@@ -349,7 +350,7 @@ public static async ValueTask MakeRipSyncItemAsync(
349350 newItem [ "Layer" ] = insertLayer ;
350351 newItem [ "CharacterName" ] = lipSyncOption . CharacterName ;
351352 newItem [ "TachieFaceParameter" ] ! [ "Mouth" ] = mouseImagePath ;
352- newItem [ "Frame" ] = line . FrameFrom + offsetFrame ;
353+ newItem [ "Frame" ] = line . FrameFrom + offsetFrame - visualLeadFrames ;
353354 newItem [ "Length" ] = line . FrameLen ;
354355 newItem [ "IsLocked" ] = isLocked ;
355356
@@ -371,11 +372,12 @@ public static int CulcContentOffset(double totalSeconds, int fps)
371372 }
372373
373374 public static void MakeCustomVoiceFaceItem (
374- IDictionary < int , int > maxLayer ,
375+ IDictionary < int , int > maxLayer ,
375376 IEnumerable < ( int Scene , YmmVoiceItem Item ) > customVoices ,
376377 JObject ymmp ,
377378 Dictionary < string , LipSyncOption > lipSyncSettings ,
378- IEnumerable < ( int Scene , int Fps ) > currentYmmpFPS
379+ IEnumerable < ( int Scene , int Fps ) > currentYmmpFPS ,
380+ int visualLeadMs = 0
379381 )
380382 {
381383 var sw = new System . Diagnostics . Stopwatch ( ) ;
@@ -436,7 +438,8 @@ await MakeRipSyncItemAsync(
436438 set [ v . Item . CharacterName ! ] ! ,
437439 maxLayer [ v . Scene ] + 1 ,
438440 v . Item . Frame - contentOffset ,
439- sceneIndex : v . Scene
441+ sceneIndex : v . Scene ,
442+ visualLeadFrames : CulcVisualLeadOffset ( visualLeadMs , sceneFps )
440443 ) ;
441444
442445 maxLayer [ v . Scene ] ++ ;
@@ -451,7 +454,8 @@ public static async ValueTask MakeAPIVoiceFaceItemAsync(
451454 IEnumerable < ( int Scene , YmmVoiceItem Item ) > voiceItems ,
452455 JObject ymmp ,
453456 Dictionary < string , LipSyncOption > lipSyncSettings ,
454- IEnumerable < ( int Scene , int Fps ) > currentYmmpFPS
457+ IEnumerable < ( int Scene , int Fps ) > currentYmmpFPS ,
458+ int visualLeadMs = 0
455459 )
456460 {
457461 var ymmChara = await ParseCharactersAsync ( ymmp ) ;
@@ -549,7 +553,13 @@ await MakeRipSyncItemAsync(
549553 set [ v ! . item . Item . CharacterName ! ] ! ,
550554 maxLayer [ v . item . Scene ] + 1 ,
551555 v . item . Item . Frame - contentOffset ,
552- sceneIndex : v . item . Scene
556+ sceneIndex : v . item . Scene ,
557+ visualLeadFrames : CulcVisualLeadOffset (
558+ visualLeadMs ,
559+ currentYmmpFPS
560+ . ElementAtOrDefault ( v . item . Scene )
561+ . Fps
562+ )
553563 ) ;
554564 }
555565 catch ( System . Exception e )
@@ -610,4 +620,9 @@ static bool HasSceneTimelines(JObject ymmp)
610620
611621 return default ;
612622 }
623+
624+ static int CulcVisualLeadOffset ( double ms , int fps )
625+ {
626+ return ( int ) Math . Round ( ( ms / 1000.0 ) * fps ) ;
627+ }
613628}
0 commit comments