
    bHj8                    2   U d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZ  e
e      j                         j                  d   Zedz  Zd	Zd
ed<   dZded<   dddZddZddZddZddZefddZddZefd dZd!dZedk(  r e        yy)"a  Build and validate the verified WLK/MLK audio archive manifest.

Audio ids in reports and web pages are normalized to the same zero-based ids
the EXE uses.  Files are therefore addressed as `extract_wlk/00.wav` and
`extract_mlk/00.mid` without a second display numbering scheme.
    )annotationsN)Counter)Path)Any   out)6)i  +     )i  "V  r
   iD)iG  r   r
   iP)i(  r   r
   8)i4  r   r
   r   )i"L  r   r
   N)iCg  r   r
   N)i  r   r
   r   )i r   r
   r   )io r   r
   N)i r   r
   r   )i5 r	   r
   r   )i? r   r
   r   )i?V r   r
   r   )i~ r   r
   r   )i r   r
   r   )i r   r
   r   )in r      r   )i r   r
   r   )i D  r
   r   )i r	   r
   r   )i r	   r
   r   )i r   r
   r   )iP r   r
   r   )iGd r   r
   r   )iq r	   r   r   )i r   r
   N)iS r   r
   r   )iސ r   r
   r   )i֧ r   r   r   )ib r   r
   r   )i r   r
   r   )i  r   r
   r   )iZ` r   r
   N)i r   r
   r   )i	 r   r
   i)ib	 r	   r
   r   )i]
 r   r
   r   )i
 r   r
   r   )iJ< r	   r
   r   )i r	   r
   r   )i r   r
   r   )i r   r
   r   )iS r	   r
   r   )ia r	   r
   r   )i# r   r
   i)i r   r
   r   )ip r   r
   r   )ix r   r   r   )i r   r
   r   )iX r   r
   N)i r   r   r   )i r   r   r   )i r   r   r   z,tuple[tuple[int, int, int, int | None], ...]WLK_VERIFIED_ROWS)   i%  iN  ie^  i}  i  i  iv ik ix iG i i i i irT iV i/Z i[ it` ztuple[int, ...]MLK_VERIFIED_OFFSETSc                    d| d| dS )N0x0X )valuewidths     3/home/exedev/hwanse/tools/audio_archive_manifest.py_hexr   g   s    awaZ !!    c                    | st        |      y N)
ValueError)	conditionmessages     r   _checkr"   k   s    !! r   c                    t        | d d dk(  d       t        j                  d| d      d   }t        |dk\  d|        t        j                  d| d	      \  }}}||||d
S )N   s   MThdz%MIDI payload does not start with MThdz>Ir      zshort MIDI header: z>HHHr
   )format
trackCountdivision
headerSize)r"   structunpack_from)payloadheader_sizefmttrack_countr(   s        r   parse_smf_headerr0   p   sy    
72A;'!#JK$$T7A6q9K
;!2;-@A!'!3!3FGQ!GCh!!	 r   c                <   | j                         }t        |d d dk(  d|d d        t        j                  d|d      \  }}t        |t	        t
              k(  d| dt	        t
                      g }t               }t               }t               }t               }d}	t        |      D ]  }
t        j                  d|d	|
d
z  z         \  }}}}}}}t
        |
   \  }}}}|dz  rdnd}|dz  rdnd}|dk7  r|nd }t        ||k(  d|
ddt        |       dt        |              t        ||k(  d|
dd| d|        t        ||k(  d|
dd| d|        t        ||k(  d|
dd| d|        t        |dk(  d|
dd| d       t        ||z   t	        |      k  d|
dd       t        |dk(  d|
dd       t        |dz        }|t        d||dz  z  |z        z  }d|d}||xx   dz  cc<   || dxx   dz  cc<   |t        |      xx   dz  cc<   |t        |      xx   dz  cc<   |r|	dz  }	|j                  i d|
d |
dd!d"|
dd#d$d%d&d|dd'|d(|d)t        |      d*|d+|d,|d-|d.|d/|d0|d1t        |d2      d3d4        i d$d%d5| j                  t              rt        | j!                  t                    n
t        |       d6d7d8|d9d|d:d;d
d<t	        |      d=d>d?d@dAdBdCt#        t%        |j'                                     dDt#        t%        |j'                                     dEt#        t%        |j'                         dF G            dHt#        t%        |j'                         dI G            dJ|	dK|S )LNr
   s   WLKF0200zbad WLK magic: z<HHz
WLK count  != verified count r   z<BBIIIiI         r   @      r   zWLK id 02d offset mismatch:  != z sample rate mismatch: z bit depth mismatch: z gain mismatch: z unexpectedly has z	 channels payload exceeds archive sizez reserved field is not zero    r   02Xz-bitexeIndexexeIdfilezextract_wlk/z.wavarchivePCMDATA.WLK	statusHexflagsHexoffset	offsetHexpayloadBytes
sampleRatebitDepthchannelsgaingainRawloopdurationSecondsr%   verifiedTpathmagicWLKF0200countarchiveFlagsHex04XentrySizeBytesverifiedCountverifiedSourcezguser supplied WLK extraction table, normalized to EXE ids and validated against PCMDATA.WLK entry table
fileNamingz2EXE ids map directly to extract_wlk/00.wav..53.wavtitleStorageabsent
flagCountsbitDepthCountssampleRateCountsc                    t        | d         S Nr   intitems    r   <lambda>z"load_wlk_archive.<locals>.<lambda>   s    UXY]^_Y`Ua r   )key
gainCountsc                    t        | d         S r`   ra   rc   s    r   re   z"load_wlk_archive.<locals>.<lambda>   s    DQRG r   	loopCountentries)
read_bytesr"   r*   r+   lenr   r   ranger   boolmaxstrappendroundis_relative_toROOTrelative_todictsorteditems)rP   datarS   archive_flagsrj   flag_countsbit_depth_countssample_rate_countsgain_counts
loop_countindexstatusflagsrE   sizesample_rategain_rawreservedexpected_offsetexpected_sample_rateexpected_bit_depthexpected_gain	bit_depthrJ   rK   rM   durationflag_hexs                               r   load_wlk_archiver   }   s%   ??D
48{"od2Ah\$BC!--eT1=E=
5C)**j?RSVWhSiRj,kl$&G '	K%,Y'.y '	KJu /
GMGYGYOH
Dvt[(H
 TeejSkP-/A=$,BA	1!#q=xdv(GE#;>PQUV\Q]P^^bcghwcxby*z{{22geC[H_`k_llp  rF  qG  5H  	Iy..'%DYZcYddhi{h|0}~t}$c{:J4&PTUbTc&dex1}c{2DXJiXYv}D	)WU3K?\+]^x1}c{2MNOEDL!#aY!^!<{!JKKc{#H"I;d+,1,3{+,1,CM"a'"!OJEE#; ,uSk6 =	
 r&. H & T&\  k I H  8   "51#5!" D#	
7/
b=t/B/B4/HD$$T*+cRVi 	 		
 	Rc23 	" 	W 	  D 	J 	 	d6+"3"3"567 	$v&6&<&<&>?@ 	D(:(@(@(BHa!bc 	d6+"3"3"5;TUV 	Z  	7! r   c                   | j                         }|d   }t        |t        t              k(  d| dt        t                      d|dz  z   }g }t	               }t	               }t        |      D ]E  }d|dz  z   }||   }	t        j                  d||dz         \  }
}t        |   }t        |
|k(  d|dd	t        |
       d
t        |              t        |
|k\  d|dd       t        |
|z   t        |      k  d|dd       ||
|
|z    }t        |      }t        |d   dk(  d|dd|d    d       t        |d   dk(  d|dd|d    d       d|	d}||xx   dz  cc<   |t        |d         xx   dz  cc<   |j                  ||dd|ddd||
t        |
      ||d   |d   |d   dd       H d| j                  t              rt        | j                  t                    n
t        |       |d|dt        |      dddt        t!        |j#                                     t        t!        |j#                                     |dS )Nr   z
MLK count r2   r   	   z<IIzMLK id r8   r9   r:   z starts inside entry tabler;   r&   z is MIDI format z, expected 0r'   z has z tracks, expected 1r   r=   zextract_mlk/z.midMIDDATA.MLKr(   T)r>   r?   r@   rA   entryFlagHexrE   rF   rG   r&   r'   r(   rO   zguser supplied MLK extraction table, normalized to EXE ids and validated against MIDDATA.MLK entry tablez2EXE ids map directly to extract_mlk/00.mid..19.midz1standard MIDI track-name meta events when present)rA   rP   rS   tableOffset
bodyOffsetrV   rW   rX   rY   rZ   entryFlagCountsformatCountsrj   )rk   r"   rl   r   r   rm   r*   r+   r   r0   rp   rq   rs   rt   ru   rv   rw   rx   )rP   ry   rS   	table_endrj   r{   format_countsr   baseflagrE   r   r   r,   headerr   s                   r   load_mlk_archiver      s   ??DGE
5C,--E7BUVYZnVoUp/qrEAII$&G '	K"))Mu 
519}Dz))%tax@.u5v(GE#;>PQUV\Q]P^^bcghwcxby*z{v"geC[8R$STv}D	)WU3K?\+]^vftm,!'*vh1$c{:J6RZK[J\\h&ijvl#q(GE#;eF<DXCYYl*mnSz?H"c&*+,1,!!#;&uSk6( ( !&\ $ *$\2":. 	

B !/3/B/B4/HD$$T*+cRViW DJK{'8'8': ;<VM$7$7$9:; r   c                    t        | dz        }t        | dz        }dddd||ddd	d
dd|d   |d   |d   dk(  |d   dk(  ddddddS )NrB   r   zaudio archive manifestrO   zPCMDATA.WLK is finalized as 54 verified mono PCM entries and MIDDATA.MLK as 20 verified SMF format-0 MIDI tracks.  No WLK id 25/45/53 special probe or audition rewrite is part of the restoration contract.z]All active audio references use EXE internal zero-based ids: WLK id 00..53 and MLK id 00..19.z8SMF parser with running status, tempo map, note matchingzbweb/engine/audio/midi_bgm_player.js WebAudio GM Lite baseline with optional SF2/SF3/Web MIDI modesz7Web Audio lookahead scheduling, not per-note setTimeoutzGGM Lite channel 9 percussion synthesis or selected soundfont percussionz:GM Lite WebAudio synth if optional soundfont loading fails)parsersynth	schedulerdrumsfallbackrS   rW   6      TF)
wlkEntries
mlkEntrieswlkVerifiedmlkVerifiedrawWavFilesPreservedrawMidiFilesPreservedprobeRequiredwlk45SpecialCaseRemoved)sourcer   
conclusionnumberingNotewlkmlkmidiPlaybackRecommendationrestorationContract)r   r   )rootr   r   s      r   build_summaryr     s    
4-/
0C
4-/
0C*G yPyR^T'
 g,g,/25/25$(%)"'+	 
% r   c           	        dddddj                  fd| d   d   D              }dj                  fd| d   d   D              }d	t        j                  | d
          dt        j                  | d          d| d| d	S )Nc                   | d   | d   nd}dt        j                  | d          dt        j                  | d          dt        j                  | d          d	| d
    d	| d    d| d    d| d	t        j                  | d          dS )NrK   r   <tr><td>r?   </td><td><code>r@   </code></td><td>rF   	</td><td>rG   rH   u    Hz · rI   u   -bit · mono</td><td>rD   
</td></tr>htmlescape)entryrK   s     r   wlk_rowzhtml_page.<locals>.wlk_row*  s     %f 9uV}q;;uW~./ 0U6]34 5;;u[123 4() *&'wuZ/@.A B& ;;uZ012 3
	
r   c                    dt        j                  | d          dt        j                  | d          dt        j                  | d          d| d    d| d	    d| d
    d| d    dS )Nr   r?   r   r@   r   rF   r   rG   r&   r'   r(   r   r   )r   s    r   mlk_rowzhtml_page.<locals>.mlk_row8  s    ;;uW~./ 0U6]34 5;;u[123 4() *?# $&' ($% &
	
r   
c              3  .   K   | ]  } |        y wr   r   ).0r   r   s     r   	<genexpr>zhtml_page.<locals>.<genexpr>E       OEO   r   rj   c              3  .   K   | ]  } |        y wr   r   )r   r   r   s     r   r   zhtml_page.<locals>.<genexpr>F  r   r   r   a  <!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <title>Audio Archive Manifest</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 24px; line-height: 1.5; color: #202124; }
    table { border-collapse: collapse; width: 100%; margin: 16px 0 28px; }
    th, td { border: 1px solid #d7dce2; padding: 6px 8px; text-align: left; }
    th { background: #f4f6f8; }
    code { background: #f4f6f8; padding: 1px 4px; }
  </style>
</head>
<body>
  <h1>Audio Archive Manifest</h1>
  <p>r   z
</p>
  <p>r   z</p>
  <h2>WLK Entries</h2>
  <table>
    <thead><tr><th>WLK id</th><th>file</th><th>offset</th><th>bytes</th><th>format</th><th>gain</th><th>flags</th></tr></thead>
    <tbody>z</tbody>
  </table>
  <h2>MLK Entries</h2>
  <table>
    <thead><tr><th>MLK id</th><th>file</th><th>offset</th><th>bytes</th><th>format</th><th>tracks</th><th>division</th></tr></thead>
    <tbody>z$</tbody>
  </table>
</body>
</html>
)r   dict[str, Any]returnrp   )joinr   r   )summarywlk_rowsmlk_rowsr   r   s      @@r   	html_pager   )  s    

 yyOWU^I5NOOHyyOWU^I5NOOH kk','() *
kk'/*+, - : 
 : 3 r   c                    |j                  dd       |dz  j                  t        j                  | dd      dz   d	       |d
z  j                  t	        |       d	       y )NT)parentsexist_okzaudio_archive_manifest.jsonFr7   )ensure_asciiindentr   zutf-8)encodingaudio_archive_manifest.html)mkdir
write_textjsondumpsr   )r   out_dirs     r   write_outputsr   g  sd    MM$M.,,88

7q9D@ 9  ,,8879KV]8^r   c                 H   t        j                         } | j                  dt        t               | j                  dt        t
               | j                         }t        |j                        }t        ||j                         t        d|j                  dz          y )Nz--root)typedefaultz	--out-dirz wrote audio archive manifest -> r   )argparseArgumentParseradd_argumentr   rt   OUT
parse_argsr   r   r   r   print)r   argsr   s      r   mainr   p  s    $$&F
tT:
$<DDII&G'4<<(	,T\\<Y-Y,Z
[\r   __main__)r%   )r   rb   r   rb   r   rp   )r    rn   r!   rp   r   None)r,   bytesr   zdict[str, int])rP   r   r   r   )r   r   r   r   )r   r   r   rp   )r   r   r   r   r   r   )r   r   )__doc__
__future__r   r   r   r   r*   collectionsr   pathlibr   typingr   __file__resolver   rt   r   r   __annotations__r   r   r"   r0   r   r   r   r   r   r   __name__r   r   r   <module>r      s    #        H~''*
Ul7C ? 7r) o 0""

Nb6r  $ D;| <? _] zF r   