1413acc715b3a9852053025f8c7bd2f304a2676e
[rock.divinelegy.git] / Services / SimfileParser.php
1 <?php
2
3 namespace Services;
4
5 use Services\ISimfileParser;
6 use Exception;
7
8 class SimfileParser implements ISimfileParser
9 {
10
11 // 'light' => 'Novice',
12 // 'beginner' => 'Novice',
13 // 'easy' => 'Easy',
14 // 'medium' => 'Medium',
15 // 'hard' => 'Hard',
16 // 'challenge' => 'Expert',
17 // 'edit' => 'Edit'
18
19 private $_smFileLines;
20
21 public function parse($simfileData)
22 {
23 $this->_smFileLines = explode(";", $simfileData);
24 }
25
26 public function banner()
27 {
28 return $this->extractKey('BANNER') ?: null;
29 }
30
31 public function title()
32 {
33 $title = $this->extractKey('TITLE');
34 if(!$title) throw new Exception ('Invalid SM file. TITLE missing');
35
36 return $title;
37 }
38
39 public function artist()
40 {
41 $artist = $this->extractKey('ARTIST');
42 if(!$artist) throw new Exception ('Invalid SM file. ARTIST missing');
43
44 return new \Domain\VOs\StepMania\Artist($artist);
45 }
46
47 public function stops()
48 {
49 $stops = $this->extractKey('STOPS');
50 if($stops === false) throw new Exception ('Invalid SM file. STOPS missing');
51
52 return (bool)$stops;
53 }
54
55 public function fgChanges()
56 {
57 $fgChanges = $this->extractKey('FGCHANGES');
58 //XXX: Looks like fgChanges is allowed to be missing.
59 //if($fgChanges === false) throw new Exception ('Invalid SM file. FGCHANGES missing');
60
61 return (bool)$fgChanges;
62 }
63
64 public function bpm()
65 {
66 $displayBpm = $this->extractKey('DISPLAYBPM');
67
68 if($displayBpm)
69 {
70 $bpmRange = explode(":",$displayBpm);
71 $bpmRange[1] = @$bpmRange[1] ?: $bpmRange[0];
72 } else {
73 $bpms = $this->extractKey('BPMS');
74 $bpmRange = $this->parseBpms($bpms);
75 }
76
77 //I have nfi why I made the BPM VO high-low instead of low-high in the constructor but yolo
78 return new \Domain\VOs\StepMania\BPM($bpmRange[1], $bpmRange[0]);
79 }
80
81 public function bgChanges()
82 {
83 $bgChanges = $this->extractKey('BGCHANGES');
84 if($bgChanges === false) throw new Exception ('Invalid SM file. BGCHANGES missing');
85
86 return (bool)$bgChanges;
87 }
88
89 public function bpmChanges()
90 {
91 $bpms = $this->extractKey('BPMS');
92 if(!$bpms) throw new Exception ('Invalid SM file. BPMS missing');
93
94 $bpmRange = $this->parseBpms($bpms);
95 //XXX: We have bpm changes when the high and low bpms are different.
96 return $bpmRange[0] != $bpmRange[1];
97 }
98
99 public function subtitle()
100 {
101 $subtitle = $this->extractKey('SUBTITLE');
102 if(!$subtitle) throw new Exception ('Invalid SM file. SUBTITLE missing');
103
104 return $subtitle;
105 }
106
107 function steps()
108 {
109 if(empty($this->_smFileLines)) throw new Exception('SM file data not set.');
110 $allSteps = array();
111
112 foreach ($this->_smFileLines as $line)
113 {
114 $pos = strpos($line, '#NOTES:');
115 if ($pos !== false)
116 {
117 $noteData = trim(substr($line, $pos + 9));
118 $allSteps[] = $this->stepchartFromNoteData($noteData);
119 }
120 }
121
122 if(empty($allSteps)) throw new Exception('Invalid Sm file. NOTES missing');
123 return $allSteps;
124 }
125
126 private function stepchartFromNoteData($noteData)
127 {
128 $stepData = array_map('trim', explode(':', $noteData));
129 return new \Domain\VOs\StepMania\StepChart(
130 new \Domain\VOs\StepMania\DanceMode($stepData[0]),
131 new \Domain\VOs\StepMania\Difficulty($stepData[2]),
132 empty($stepData[1]) ? null : new \Domain\VOs\StepMania\StepArtist($stepData[1]),
133 $stepData[3]
134 );
135 }
136
137 private function extractKey($key)
138 {
139 if(empty($this->_smFileLines)) throw new Exception('SM file data not set.');
140
141 foreach ($this->_smFileLines as $line)
142 {
143 $pos = strpos($line, '#' . $key . ':');
144 if ($pos !== false) return trim(substr($line, $pos + strlen($key) + 2));
145 }
146
147 return false;
148 }
149
150 private function parseBpms($bpms)
151 {
152 $bpms = explode(",", $bpms);
153 $bpmRange = array('high' => null, 'low' => null);
154
155 foreach($bpms as $bpm)
156 {
157 $bpmMeasure = explode('=', $bpm);
158 $bpmValue = floatval($bpmMeasure[1]);
159
160 if(empty($bpmRange['low'])) $bpmRange['low'] = $bpmRange['high'] = $bpmValue;
161
162 $bpmRange['high'] = ($bpmValue > $bpmRange['high']) ? $bpmValue : $bpmRange['high'];
163 $bpmRange['low'] = ($bpmValue < $bpmRange['low']) ? $bpmValue : $bpmRange['low'];
164 }
165
166 return array($bpmRange['low'], $bpmRange['high']);
167 }
168 }