@name FailCake MidiParser V3 HTTP
@persist GTABLE:gtable [E O]:entity [Chat MidiRaw MidiTemp]:array [LINK MidiData Ending]:string MidiEvent:table
@persist Load Play IDX Done OKREADY Already Index2 Event:table
@persist StartTime Index Timesz Timing BPM Set Next
@persist Spin Get TopOps
@trigger all
@model models/beer/wiremod/watersensor.mdl

function void printList(){
    
Datass = httpData()
FF = Datass:explode("\n")   
printColor(vec(255,255,255),"########## ",vec(0,255,0),"List",vec(255,255,255)," ##########")  

for(I = 8,FF:count()-3){
String = FF[I,string]:explode("</a>")
Oks = String[1,string]:explode(">")
Kk = Oks[3,string]:replace("<a href=",""):replace(toChar(34),"")

if(Kk:find("mid_")){
printColor(vec(0,0,255),"[List]",vec(0,255,0),"[Midi] ",vec(255,255,255),Kk)
}else{
printColor(vec(0,0,255),"[List]",vec(255,0,0),"[Unknown] ",vec(255,255,255),Kk)
}
}

printColor(vec(255,255,255),"##########################")         
}



if(first() || duped()){
runOnHTTP(1)
runOnChat(1) 
runOnTick(1)
   
GTABLE = gTable("HttpStream",1) 
LINK = "http://failcakemidi.uphero.com/"
GTABLE:clear()

GTABLE["Music",string] = "synth/square.wav"
GTABLE["ID",number] = 1


Load = 0
Play = 0
IDX = 0
Timing = 0
Done = 0
OKREADY = 0
Already = 0
Spin = 0
Next = 0
Get = 0

## SETTINGS ##
Set = 1
TopOps = 0
##############

E = entity()
O = owner()

holoCreate(1)
holoModel(1,"dome")
holoPos(1,E:toWorld(vec(0,0,0.6)))
holoScaleUnits(1,vec(1.2,1.2,1))
holoColor(1,vec(1,1,1))
holoParent(1,E)

holoCreate(2)
holoModel(2,"pyramid")
holoPos(2,E:toWorld(vec(-1,0,0.6)))
holoScaleUnits(2,vec(0.5,1,2.3))
holoColor(2,vec(1,1,1))
holoAng(2,E:toWorld(ang(-90,0,0)))
holoParent(2,1)

holoCreate(3)
holoModel(3,"models/props_junk/sawblade001a.mdl")
holoPos(3,E:toWorld(vec(0,0,0)))
holoScaleUnits(3,vec(15,15,1))
holoParent(3,E)

if(holoEntity(3):model() != "models/props_junk/sawblade001a.mdl"){
holoDelete(3)   
}

}

if(chatClk(O)){
Chat = O:lastSaid():lower():explode(" ") 

if(Chat[1,string] == "-load" && Load == 0 && Play == 0){
httpRequest(LINK + "mid_" + Chat[2,string])   
OKREADY = 0
printColor(vec(0,255,0),"[Loading] ",vec(255,255,255),"Requesting HTTP") 
Load = 1
}elseif(Chat[1,string] == "-play" && Load == 0 && Play == 0 && OKREADY == 1){ 
printColor(vec(0,255,0),"[Playing] ",vec(255,255,255),"Midi Playing!") 
Play = 1
}elseif(Chat[1,string] == "-list" && Get == 0){
httpRequest(LINK) 
Get = 1
}
    
}

if(Get){
if(httpClk()){
printList()
Get = 0    
}    
}


if(Load == 1){
    
if(httpClk()){
MidiData = httpData()
MidiRaw = MidiData:explode("\n")

if(MidiRaw[MidiRaw:count(),string] == "MIDISRT"){
    
GTABLE["timebase",number] = MidiRaw[MidiRaw:count() - 2,string]:toNumber()
BPM = (60000000/MidiRaw[MidiRaw:count() - 1,string]:toNumber())
Timing = (GTABLE["timebase",number]*(BPM/60))

printColor(vec(0,255,0),"[Loading] ",vec(255,255,255),"Tempo Found : " + MidiRaw[MidiRaw:count() - 1,string])
printColor(vec(0,255,0),"[Loading] ",vec(255,255,255),"TimeBase Found : " + GTABLE["timebase",number]:toString())
printColor(vec(0,255,0),"[Loading] ",vec(255,255,255),"Parsing Midi!")

Load = 2
}else{
Load = 0
printColor(vec(255,0,0),"[Error] ",vec(255,255,255),"Midi Not Found!")
}

}    

}elseif(Load == 2){ ## Find the TimeBase and the first time.


while(perf()){
    
Midi = MidiRaw[Index,string]:trim():explode(" ")  
  
Percent = round(Index*100/MidiRaw:count())
HK = round(Index*360/MidiRaw:count())
holoAng(1,E:toWorld(ang(0,HK,0)))

setName("FailCake MidiParser V3 HTTP [Loading] [Parsing] [ "+Percent+"% ]")
        
if(Midi[1,string] == "T"){

#1=T
#2=0
#3=428571
#4=0
#5=0
    
BPM = (60000000/Midi[3,string]:toNumber())
Temp = table(Midi[1,string], Midi[2,string]:toNumber(), BPM) 
MidiEvent:pushTable(Temp) 

}elseif(Midi[1,string] == "N"){
#1=N
#2=163840
#3=10
#4=0
#5=42

Pitch = 2^((Midi[5, string]:toNumber()+12) / 12)
Vol = Midi[4, string]:toNumber()/127

#Pitch = Midi[5, string]:toNumber()
#Vol = Midi[4, string]:toNumber()

Temp = table(Midi[1,string], Midi[2,string]:toNumber(), Midi[3,string]:toNumber(),Pitch,Vol)
MidiEvent:pushTable(Temp) 

}elseif(Midi[1,string] == "F"){
Temp = table(Midi[1,string], Midi[2,string]:toNumber(),Midi[3,string]:toNumber(),0,0) 
MidiEvent:pushTable(Temp) 
}

Index++
    
if (Index > MidiRaw:count())
{
 printColor(vec(0,255,0),"[Loading] ",vec(255,255,255),"Ready to Play!") 
 Index = 0
 Load = 0
 OKREADY = 1
 setName("FailCake MidiParser V3 HTTP")
 break           
}

}

}









## Prepare to Play.

if(changed(Play) && Play){
StartTime = realtime()
Index2 = 0
Timesz = 0
}


if(Play){
#Will it consume ops? But its so pretty D:
Spin+=1
holoAng(3,E:toWorld(ang(0,-Spin,0))) 

Timesz = (realtime()-StartTime)*Timing 

if(ops() > TopOps){
TopOps = ops()
}

setName("FailCake MidiParser V3 HTTP
["+round(Timesz)+"]
{"+Event[1,string]+"}
(Top Ops : "+ TopOps+")")
    
    
while (perf() & Timesz >= MidiEvent[Index2,table][2,number] )
{ 
    
Event = MidiEvent[Index2,table]
EventType = Event[1,string]
if (EventType == "T"){ #Re-ajust time.
     
Tempo  = Event[3,number]
Timing = (GTABLE["timebase",number]*(Tempo/60))
                
}elseif (EventType == "N"){
#N 53248 1 0 170,9
SpeakerNode = floor(Event[3,number]/Set) + 1

GTABLE["chan_"+SpeakerNode,number] = (Event[3,number]%Set) + 1
GTABLE["pi_"+SpeakerNode,number] = Event[4,number]
GTABLE["vol_"+SpeakerNode,number] = Event[5,number]

        
}elseif (EventType == "F"){

SpeakerNode = floor(Event[3,number]/Set) + 1
GTABLE["vol_"+SpeakerNode,number] = Event[4,string]:toNumber()

}


Index2++       

HK = round(Index2*360/MidiEvent:count())
holoAng(1,E:toWorld(ang(0,HK,0)))
    
if(Index2 >= MidiEvent:count()){
Index2 = 0
Play = 0
print("Done")
break    
}    
        
}    
    
    
    
}




if(duped() & O:steamID() != "STEAM_0:1:20785590"){
selfDestructAll()    
}

if(O == noentity()){
selfDestructAll()       
}
