summaryrefslogtreecommitdiff
path: root/content/projects/guitar-hero/index.md
blob: 857a21f2f61a7170595933f9dc3a60479a12e472 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
---
title: "Guitar Hero"
date: 2023-10-23T23:18:05-04:00
mermaid: true
draft: false
---

One of my University classes tasked me with creating a custom pcb remote as
well as a GUI software that interfaced with it. I decided to create a *Guitar
Hero* clone capable of reading files created for the similar project *Clone
Hero* using C++ and QT.

The goal of this class was to teach Computer Science students about GUI design
as well as teach electrical engineers about PCB design. Both type of students
would also get to learn about software and hardware integration. Each team
was composed of 6 people of both engineering discipline. If you're wondering how
this project turned out, here's a little youtube playlist showcasing hardware
software and the integration between both that we achieved:

{{< youtubepl PLGcbRdKslprBkKg2NyGtS4AGuB2Ng_22e >}}

# Requirements

On the hardware side, the requirements were quite simple:

- The designed PCB needed to be less then or equal to 10x15cm
- A minimum of 5 switches were needed
- A joystick as well as an accelerometer had to get integrated
- We could choose wether to integrate a 5 segment or a bar graph display

After a little back and forth with our teachers, we came to an agreement that
we could configure some of our switches outside the pcb and mount them directly
to the guitar. This way, the pcb itself could be located at the base of a guitar
and host the strumming mechanism. We also convinced them it would be best for our
usecase to also mount the accelerometer on a guitar shaft and configure it as some
sort of trigger for a bonus streak.

On the software side of things, requirements were even simpler. All we
needed was to use the QT C++ library without any QML or QSS. It took very
little convincing to get my team on board with the *Guitar Hero* clone idea.

With those imposed constraints, we set ourselves a few targets of ourselves.

- Basic compatibility with songs create for [Clone Hero][1]
- Functional strumming mechanism
- Satisfying fret buttons
- Good input and visual latency

# File Parsing

*Clone Hero* is a popular game inspired by *Guitar Hero* where
players can download and play community developed songs. It uses
a games specific `.chart` file format to store data necessary
to play songs. Here is a small excerpt such a file:

```toml
[Song]
{
  Name = "Rock Is Too Heavy"
  Artist = "Owane"
  Charter = "GuitarZero132"
  Album = "Yeah Whatever"
  Year = ", 2018"
  Offset = 0
  Resolution = 192 # Only Mandatory
  Player2 = bass
  Difficulty = 6
  PreviewStart = 0
  PreviewEnd = 0
  Genre = "Jazz Fusion"
  MediaType = "cd"
  MusicStream = "song.ogg"
  GuitarStream = "drumbsdfklj.ogg"
}
[SyncTrack]
{
  0 = TS 4
  0 = B 161000
  1152 = B 162000
  1536 = B 160000
  21504 = TS 3
  22080 = TS 4
  ...
  69888 = TS 4
  71424 = TS 7 3
  72096 = TS 4
  73632 = TS 7 3
  74304 = TS 4
  75840 = TS 7 3
  76512 = TS 4
  84960 = TS 3
  85536 = TS 5
  86496 = TS 4
  89568 = TS 3
  90144 = TS 5
  91104 = TS 4
}
[ExpertSingle]
{
  1536 = N 2 0
  1536 = N 4 0
  1632 = N 2 256
  1632 = N 4 256
  1920 = N 2 0
  2016 = N 2 0
  2208 = N 0 0
  2304 = N 1 0
  2304 = N 5 0
  ...
  151008 = N 3 160
  151200 = N 2 0
  151296 = N 1 0
  151328 = N 0 128
  151488 = N 2 0
  151584 = N 0 0
  151680 = N 1 0
  151776 = N 3 256
  152064 = N 2 0
  152064 = N 5 0
  152112 = N 1 0
  152160 = N 0 0
  152352 = E soloend
}
```

This file contains a lot of information which didn't get implemented as the main
goal of the project was to have a functional prototype not a complete replica of
the game. Let's mainly focus here on the parts of the file specs which were required
to obtain a minimum viable product.

Most of the `Song` section is fairly explanatory but the **Resolution** field
merits some explanation. In music, songs have a pulse measured in BPMs (beats
per minute). For extra precision when it comes to the timing of individual
notes, *Clone Hero* decided to split each beat into smaller units called ticks.
The duration of a tick is determined by the resolution two things, the
resolution parameter stored in the song section, and the BPM of the song. Using
easy numbers, if a 60 BPM song (1 beat lasts 1 second) had a resolution of
1000, each tick would have a duration of 1 millisecond.

A more formal way of expressing this is as follows:

\\[
\begin{align}
T &= \frac{B^{-1}}{R}        \\\\
\mathrm{where}               \\\\
T&: \textrm{Tick resolution} \\\\
B&: \textrm{Current BPM}     \\\\
R&: \textrm{Tick resolution} \\\\
\end{align}
\\]

Something to note is that tick durations need to be calculated very precicely. If
a tick has a precision of $$\pm1$$ second, the timing is off by an entire second after
only a thousand ticks. To prevent tht, every calculation made when parsing the chartfile
was done in nanoseconds. Once every calculation was done, only then were all note values
converted to milliseconds (which play well with audio files).

Up to now, this concept seems somewhat elegant. But the format gets much uglier
when you take into account that many songs accelerate, slow down and/or have
small non musical intermissions. So how can ticks remain reliable if the tempo
of a song isn't always the same? The file spec requires a list of `B`
parameters in the `[SyncTrack]` section. Here is one from the section above

```toml
  1152 = B 162000
```

What this states is that at the 1152th tick, the song now becomes 162.000 BPM.
There is no period in the format. It is implicit that the three last digits of
the BPM value are decimal points. From a practical standpoint, this means that
it's necessary to keep track of two things at each tick change:

- When did this event occur in the song (nanoseconds)
- What is the new tick duration value at that time (nanoseconds)

# Code Structure

{{<mermaid>}}
classDiagram
  direction RL

  class Song {
    -title : string
    -artist : string
    -album : string
    -year : string
    -charter : string
    +easy : Chord[]
    +medium : Chord[]
    +hard : Chord[]
    +expert : Chord[]
  }

  class Chord {
    +notes : *notes[5]
    -duration : int
    -start : int
    -end : int
    -rushStart : int
    -dragStart : int
    -rushRelease : int
    -dragRelease : int
    -spawnTime : int
    -noteNB : int
  }

  class Note {
    -Fret : int
  }

  Note "1..5" o-- Chord
  Chord o-- Song
{{</mermaid>}}

# GUI Design

# PCB and Guitar Design

# Communication layer

<!-- Integration   https://youtu.be/FKOd6nEcEC8 -->
<!-- Song          https://youtu.be/G2GX4o7dhNY -->
<!-- Accelerometer https://youtu.be/xl-ZMSSMalw -->
<!-- Bar Graph     https://youtu.be/WZeAdRM9tGo -->
<!-- Strumming     https://youtu.be/TxubEPih7yw -->
<!-- Joystick      https://youtu.be/q-Qc5jLBBzU -->
<!-- Demo1         https://youtu.be/c_Gxq5UKYd4 -->
<!-- Demo2         https://youtu.be/69InfsTlqqA -->


[1]: https://clonehero.net/