106 lines
		
	
	
		
			No EOL
		
	
	
		
			2.1 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			No EOL
		
	
	
		
			2.1 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <META NAME=VIEWPORT CONTENT=initial-scale=1>
 | |
| <CENTER>
 | |
| <P><A HREF=http://nycki.net/qrplay>qrplay v3d</A><br>by nycki and SArpnt</P>
 | |
| <TEXTAREA ID=F STYLE=WIDTH:MIN(40EM,99%);HEIGHT:9LH>; @title nupa's theme
 | |
| ; @authors nycki bsp
 | |
| ; single channel version
 | |
| 1[@0000]
 | |
| 
 | |
| 2[
 | |
|   0[c-c+]1  1
 | |
|   0[e-c+]1  0[g-c+]1
 | |
|   0[c-b!+]1 1
 | |
|   0[e-b!+]1 0[g-b!+]1
 | |
|   0[d-a+]1  0[c-a+]1
 | |
| ]
 | |
| 
 | |
| 2
 | |
| 0[d-a+]1   0[c-a+]1
 | |
| 0[d#-a!+]1 0[d-a!+]1
 | |
| 1          1
 | |
| 
 | |
| 2
 | |
| 0[d#-a!+]1 0[d-g+]1
 | |
| 0[c--c++]1 1
 | |
| 1          1
 | |
| </TEXTAREA><P>
 | |
| <BUTTON onclick="
 | |
| F.A?.close();
 | |
| F.A=A=new AudioContext;
 | |
| D=Date.now();
 | |
| S='@qx@'+F.value.toLowerCase();
 | |
| // stack
 | |
| B=[];
 | |
| // stack variables
 | |
| K=T=Z=0;
 | |
| U=137;
 | |
| V=40;
 | |
| // samples
 | |
| C='+g,-b+c#deff#g,g++ddb--g++ddb,,+ea-g--b++g++c#,a#ga#g-a#+g-b+g,-a++c#-aae+e--a,-ffed#ddc#,dddddd#e,--ba#bb-a+a#-b'.split(',').map(c=>`{@++m${c}}x`);
 | |
| 
 | |
| // main loop
 | |
| M=_=>{
 | |
| 	[a,b,c,d]=S;
 | |
| 	// next index into S
 | |
| 	s=1;
 | |
| 	// opcode
 | |
| 	z='\n;+-@.3cdefgabxjtsiqhwmuv{}z012456789'.indexOf(a);
 | |
| 
 | |
| 	// do nothing
 | |
| 	z<0?0:
 | |
| 	// comment
 | |
| 	z<2?K=z:K?0:
 | |
| 	// octave
 | |
| 	z<4?O+=a+1|0:
 | |
| 	// reset octave and length
 | |
| 	z<5?(O=0,L=1):
 | |
| 	// dots and triplets
 | |
| 	z<7?L*=3/(z<6?2:9):
 | |
| 	// note or rest
 | |
| 	z<15?(
 | |
| 		z-=7,
 | |
| 		o=new OscillatorNode(A,{
 | |
| 			type:'square',
 | |
| 			detune:100*(z*2-(z>2)-(b=='!')+(b=='#')+12*O-9)
 | |
| 		}),
 | |
| 		g=new GainNode(A,{gain:z<7&&.5**(13-V/5)}),
 | |
| 		o.connect(g),
 | |
| 		g.connect(A.destination),
 | |
| 		o.start(T),
 | |
| 		o.stop(T+=7.5*L/U)
 | |
| 	):
 | |
| 	// set note length
 | |
| 	z<22?L=2**(z-16):
 | |
| 	// set note length (microtone)
 | |
| 	z<23?L=U/2**11:
 | |
| 	// change tempo in bpm
 | |
| 	z<24?(U=b+c+d,s+=3):
 | |
| 	// change volume
 | |
| 	z<25?(V=b+c,s+=2):
 | |
| 	// play simultaneously
 | |
| 	z<26?B[Z++]=[L,O,T,U,V]:z<27?[L,O,T,U,V]=B[--Z]:
 | |
| 	// play on channel
 | |
| 	z<28?B[B[Z]=[L,O,T,U,V],s=3,Z=b+c]=[L,O,T,U,V]=[1,0,0,U,V]:
 | |
| 	// store sample
 | |
| 	b=='['?(
 | |
| 		m=0,
 | |
| 		d=B.findIndex.call(S,c=>
 | |
| 			c=='['?!++m:
 | |
| 			c==']'?!--m:
 | |
| 			0
 | |
| 		),
 | |
| 		C[a]=S.slice(s,d),
 | |
| 		s=d+1
 | |
| 	):
 | |
| 	// play sample
 | |
| 	S=C[a]+S.slice(s--);
 | |
| 	
 | |
| 	// loop (but don't get too far ahead)
 | |
| 	A.state!='closed'&&(S=S.slice(s))&&setTimeout(M,1e3*T-Date.now()+D-5e3);
 | |
| };M()
 | |
| ">#play</BUTTON> <BUTTON ONCLICK=F.A.close()>#stop
 | |
| 
 | |
| <!-- snip -->
 | |
| </BUTTON></P>
 | |
| <img src="qrplay-v3d-nupas-theme.png">
 | |
| </center> |