@@ -60,7 +60,7 @@ public static Dictionary<int, int>
60
60
{
61
61
//シーンごとにMaxLayerを取得
62
62
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" ] ! ) ] ,
64
64
} ;
65
65
66
66
return maxLayers . ToDictionary ( x => x . Scene , x => x . MaxLayer ) ;
@@ -80,7 +80,7 @@ public static async ValueTask<List<YmmCharacter>> ParseCharactersAsync(JObject y
80
80
} ) ;
81
81
}
82
82
83
- public static async ValueTask < IEnumerable < ( int Scene , YmmVoiceItem Item ) > >
83
+ public static async ValueTask < IEnumerable < ( int Scene , YmmVoiceItem Item ) > >
84
84
ParseVoiceItemsAsync (
85
85
JObject ymmp
86
86
)
@@ -120,7 +120,7 @@ private static Dictionary<int, JArray>
120
120
return items ;
121
121
}
122
122
123
- public static async ValueTask < IEnumerable < ( int Scene , YmmVoiceItem Item ) > >
123
+ public static async ValueTask < IEnumerable < ( int Scene , YmmVoiceItem Item ) > >
124
124
FilterCustomVoiceAsync (
125
125
IEnumerable < ( int Scene , YmmVoiceItem Item ) > voices
126
126
)
@@ -196,7 +196,8 @@ public static async ValueTask MakeRipSyncItemAsync(
196
196
int insertLayer = 0 ,
197
197
int offsetFrame = 0 ,
198
198
bool isLocked = false ,
199
- int sceneIndex = 0
199
+ int sceneIndex = 0 ,
200
+ int visualLeadFrames = 0
200
201
)
201
202
{
202
203
if ( lab is null || lab . Lines is null )
@@ -280,62 +281,62 @@ public static async ValueTask MakeRipSyncItemAsync(
280
281
switch ( line . Phoneme )
281
282
{
282
283
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
+ }
288
289
289
290
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
+ }
295
296
296
297
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
+ }
302
303
303
304
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
+ }
309
310
310
311
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
+ }
316
317
317
318
case var p when CLOSE_CONSONANT . Contains ( p ) :
318
- {
319
- imageFileName = images [ "N" ] ;
320
- break ;
321
- }
319
+ {
320
+ imageFileName = images [ "N" ] ;
321
+ break ;
322
+ }
322
323
323
324
case var p when OPEN_CONSONANT . Contains ( p ) :
324
- {
325
- imageFileName = consoOpt switch
326
325
{
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
+ }
333
334
334
335
default :
335
- {
336
- imageFileName = images [ "N" ] ;
337
- break ;
338
- }
336
+ {
337
+ imageFileName = images [ "N" ] ;
338
+ break ;
339
+ }
339
340
}
340
341
341
342
var mouseImagePath = Path . Combine ( lipSyncOption . MouseDir ! , imageFileName ) ;
@@ -349,7 +350,7 @@ public static async ValueTask MakeRipSyncItemAsync(
349
350
newItem [ "Layer" ] = insertLayer ;
350
351
newItem [ "CharacterName" ] = lipSyncOption . CharacterName ;
351
352
newItem [ "TachieFaceParameter" ] ! [ "Mouth" ] = mouseImagePath ;
352
- newItem [ "Frame" ] = line . FrameFrom + offsetFrame ;
353
+ newItem [ "Frame" ] = line . FrameFrom + offsetFrame - visualLeadFrames ;
353
354
newItem [ "Length" ] = line . FrameLen ;
354
355
newItem [ "IsLocked" ] = isLocked ;
355
356
@@ -371,11 +372,12 @@ public static int CulcContentOffset(double totalSeconds, int fps)
371
372
}
372
373
373
374
public static void MakeCustomVoiceFaceItem (
374
- IDictionary < int , int > maxLayer ,
375
+ IDictionary < int , int > maxLayer ,
375
376
IEnumerable < ( int Scene , YmmVoiceItem Item ) > customVoices ,
376
377
JObject ymmp ,
377
378
Dictionary < string , LipSyncOption > lipSyncSettings ,
378
- IEnumerable < ( int Scene , int Fps ) > currentYmmpFPS
379
+ IEnumerable < ( int Scene , int Fps ) > currentYmmpFPS ,
380
+ int visualLeadMs = 0
379
381
)
380
382
{
381
383
var sw = new System . Diagnostics . Stopwatch ( ) ;
@@ -436,7 +438,8 @@ await MakeRipSyncItemAsync(
436
438
set [ v . Item . CharacterName ! ] ! ,
437
439
maxLayer [ v . Scene ] + 1 ,
438
440
v . Item . Frame - contentOffset ,
439
- sceneIndex : v . Scene
441
+ sceneIndex : v . Scene ,
442
+ visualLeadFrames : CulcVisualLeadOffset ( visualLeadMs , sceneFps )
440
443
) ;
441
444
442
445
maxLayer [ v . Scene ] ++ ;
@@ -451,7 +454,8 @@ public static async ValueTask MakeAPIVoiceFaceItemAsync(
451
454
IEnumerable < ( int Scene , YmmVoiceItem Item ) > voiceItems ,
452
455
JObject ymmp ,
453
456
Dictionary < string , LipSyncOption > lipSyncSettings ,
454
- IEnumerable < ( int Scene , int Fps ) > currentYmmpFPS
457
+ IEnumerable < ( int Scene , int Fps ) > currentYmmpFPS ,
458
+ int visualLeadMs = 0
455
459
)
456
460
{
457
461
var ymmChara = await ParseCharactersAsync ( ymmp ) ;
@@ -549,7 +553,13 @@ await MakeRipSyncItemAsync(
549
553
set [ v ! . item . Item . CharacterName ! ] ! ,
550
554
maxLayer [ v . item . Scene ] + 1 ,
551
555
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
+ )
553
563
) ;
554
564
}
555
565
catch ( System . Exception e )
@@ -610,4 +620,9 @@ static bool HasSceneTimelines(JObject ymmp)
610
620
611
621
return default ;
612
622
}
623
+
624
+ static int CulcVisualLeadOffset ( double ms , int fps )
625
+ {
626
+ return ( int ) Math . Round ( ( ms / 1000.0 ) * fps ) ;
627
+ }
613
628
}
0 commit comments