88using Microsoft . AspNetCore . Mvc ;
99using Microsoft . VisualBasic . FileIO ;
1010using NAudio . Lame ;
11- using SimaiSharp ;
11+ using NAudio . Wave ;
1212using Vanara . Windows . Forms ;
13- using Xabe . FFmpeg ;
1413using FolderBrowserDialog = System . Windows . Forms . FolderBrowserDialog ;
1514
1615namespace MaiChartManager . Controllers . Music ;
@@ -549,13 +548,26 @@ public async Task ExportAsMaidata(int id, string assetDir, bool ignoreVideo = fa
549548 await using var zipStream = HttpContext . Response . BodyWriter . AsStream ( ) ;
550549 using var zipArchive = new ZipArchive ( zipStream , ZipArchiveMode . Create , leaveOpen : true ) ;
551550
551+ // 计算由于WAV转MP3导致的音频开头增加的空白段的长度,以便稍后通过&first参数给予修正。
552+ // 具体的情况和原理,详见https://github.com/MuNET-OSS/MaiChartManager/issues/40
553+ var wavPath = await AudioConvert . GetCachedWavPath ( GetAudioCandidateIds ( music ) ) ;
554+ if ( wavPath is null )
555+ {
556+ var message = BuildAudioResolveErrorMessage ( music ) ;
557+ logger . LogError ( "{message}" , message ) ;
558+ throw new FileNotFoundException ( message ) ;
559+ }
560+ using var wavReader = new WaveFileReader ( wavPath ) ;
561+ // 根据上面issue中的结论,wav转mp3引起的开头空白段的长度为1728采样点
562+ var audioDelay = 1728 / ( double ) wavReader . WaveFormat . SampleRate ;
563+
552564 Ma2Parser parser = new ( ) ;
553565 var simaiFile = new StringBuilder ( ) ;
554566
555567 simaiFile . AppendLine ( $ "&title={ music . Name } ") ;
556568 simaiFile . AppendLine ( $ "&artist={ music . Artist } ") ;
557569 simaiFile . AppendLine ( $ "&wholebpm={ music . Bpm } ") ;
558- simaiFile . AppendLine ( "&first=0.0333 " ) ;
570+ simaiFile . AppendLine ( $ "&first={ audioDelay :: 0 . #### } ");
559571 simaiFile . AppendLine ( $ "&shortid={ music . Id } ") ;
560572 simaiFile . AppendLine ( $ "&genreid={ music . GenreId } ") ;
561573 var genre = StaticSettings. GenreList. FirstOrDefault( it => it . Id == music . GenreId ) ;
@@ -622,6 +634,7 @@ public async Task ExportAsMaidata(int id, string assetDir, bool ignoreVideo = fa
622634 imageStream . Close ( ) ;
623635 }
624636
637+ // 导出音频
625638 var soundEntry = zipArchive. CreateEntry( "track. mp3") ;
626639 await using var soundStream = soundEntry. Open( ) ;
627640 var tag = new ID3TagData
@@ -633,16 +646,10 @@ public async Task ExportAsMaidata(int id, string assetDir, bool ignoreVideo = fa
633646 Comment = version ? . GenreName ,
634647 AlbumArt = img ,
635648 } ;
636- var wavPath = await AudioConvert . GetCachedWavPath ( GetAudioCandidateIds ( music ) ) ;
637- if ( wavPath is null )
638- {
639- var message = BuildAudioResolveErrorMessage ( music ) ;
640- logger . LogError ( "{message}" , message ) ;
641- throw new FileNotFoundException ( message ) ;
642- }
643649
644- AudioConvert . ConvertWavPathToMp3Stream ( wavPath , soundStream , tag ) ;
650+ AudioConvert . ConvertWavToMp3Stream ( wavReader , soundStream , tag ) ;
645651 soundStream . Close ( ) ;
652+ wavReader . Close ( ) ;
646653
647654 if ( ! ignoreVideo && StaticSettings . MovieDataMap . TryGetValue ( music . NonDxId , out var movieUsmPath) )
648655 {
0 commit comments