#!/usr/bin/env python3 """Original synthetic MP3+G test media. Regeneration requires ffmpeg; playback does not.""" from pathlib import Path import wave,struct,math,subprocess,zipfile,shutil root=Path(__file__).resolve().parents[1]/'Fixtures';root.mkdir(exist_ok=True) font={ 'A':['01110','10001','10001','11111','10001','10001','10001'], 'C':['01111','10000','10000','10000','10000','10000','01111'], 'D':['11110','10001','10001','10001','10001','10001','11110'], 'E':['11111','10000','10000','11110','10000','10000','11111'], 'F':['11111','10000','10000','11110','10000','10000','10000'], 'G':['01111','10000','10000','10111','10001','10001','01111'], 'H':['10001','10001','10001','11111','10001','10001','10001'], 'I':['11111','00100','00100','00100','00100','00100','11111'], 'J':['00111','00010','00010','00010','10010','10010','01100'], 'K':['10001','10010','10100','11000','10100','10010','10001'], 'L':['10000','10000','10000','10000','10000','10000','11111'], 'M':['10001','11011','10101','10101','10001','10001','10001'], 'N':['10001','11001','10101','10011','10001','10001','10001'], 'O':['01110','10001','10001','10001','10001','10001','01110'], 'P':['11110','10001','10001','11110','10000','10000','10000'], 'R':['11110','10001','10001','11110','10100','10010','10001'], 'S':['01111','10000','10000','01110','00001','00001','11110'], 'T':['11111','00100','00100','00100','00100','00100','00100'], 'U':['10001','10001','10001','10001','10001','10001','01110'], 'V':['10001','10001','10001','10001','10001','01010','00100'], 'W':['10001','10001','10001','10101','10101','11011','10001'], 'Y':['10001','10001','01010','00100','00100','00100','00100'], '3':['11110','00001','00001','01110','00001','00001','11110'], ' ':['00000']*7, } def packet(inst,data):return bytes([9,inst,0,0]+(data+[0]*16)[:16]+[0]*4) packets=[bytes(24) for _ in range(6000)] def put(index,seq): for p in seq: assert packets[index]==bytes(24),'overlapping instructions' packets[index]=p;index+=1 return index colors=[0x013,0xfff,0xfd0,0x0cf]+[0]*12 def palette(offset): data=[] for c in colors[offset:offset+8]:data.extend([(c>>6)&63,c&63]) return packet(30 if offset==0 else 31,data) put(0,[palette(0),palette(8),packet(1,[0,0]),packet(2,[0])]) def frame(lines): pixels=[[0]*300 for _ in range(216)] for line,(text,y) in enumerate(lines): x=(300-len(text)*12)//2 for char in text: for gy,row in enumerate(font[char]): for gx,bit in enumerate(row): if bit=='1': for dy in range(2): for dx in range(2):pixels[y+gy*2+dy][x+gx*2+dx]=1 x+=12 return pixels def tiles(pixels,xor=False): result=[] for row in range(1,17): for col in range(1,49): bits=[] for y in range(12): v=0 for x in range(6):v=(v<<1)|pixels[row*12+y][col*6+x] bits.append(v) if any(bits):result.append(packet(38 if xor else 6,[0,3 if xor else 1,row,col]+bits)) return result scenes=[[("KJAMS CLONE",66),("MP3 PLUS G TEST",114)],[("ONE TWO THREE FOUR",66),("SING ALONG",114)],[("WITH THE TEST TONE",66),("PLAY PAUSE SEEK",114)],[("MP3 PLUS G TEST",66),("TEST COMPLETE",114)]] for index,lines in enumerate(scenes): start=index*1500+(5 if index==0 else 0) pixels=frame(lines) put(start,([packet(1,[0,0])] if index else [])+tiles(pixels)) # Highlight each word after the initial white text has been drawn. for line,(text,y) in enumerate(lines): left=(300-len(text)*12)//2 words=text.split();cursor=0 for wi,word in enumerate(words): mask=[[0]*300 for _ in range(216)] for py in range(y,y+14): for px in range(left+cursor*12,left+(cursor+len(word))*12):mask[py][px]=pixels[py][px] put(index*1500+240+line*600+wi*100,tiles(mask,True)) cursor+=len(word)+1 (root/'TestTrack.cdg').write_bytes(b''.join(packets)) rate=44100;duration=20;notes=[261.63,329.63,392.0,523.25,392.0,329.63,293.66,261.63] with wave.open(str(root/'TestTrack.wav'),'w') as out: out.setparams((1,2,rate,0,'NONE','not compressed')) for beat in range(duration*2): freq=notes[beat%len(notes)] data=bytearray() for i in range(rate//2): t=i/rate;fade=min(1,t/0.015,(0.5-t)/0.04) data.extend(struct.pack('