Take the 2-minute tour ×
Mathematics Stack Exchange is a question and answer site for people studying math at any level and professionals in related fields. It's 100% free, no registration required.

I'm in the process of reverse engineering a music file format from an old computer game. It uses numbers from 0 to 127 to represent note frequencies, however I need to convert these numbers to a different unit (in this case millihertz) in order to use them.

Unfortunately because of various technical reasons, the output frequency values I am working with are a little inaccurate due to rounding issues. I am not sure how to take this into account when trying to find a formula to fit the sequence, as most explanations I can understand assume the values are precise.

Could someone please help me find a formula to fit this sequence? Here are some values. The first column is the input note number, and the second column is the output frequency in millihertz.

  0 16262
  1 17258
  2 18301
  3 19391
  4 20529
  5 21762
  6 23042
 24 51774
 50 146410
 80 520403
 98 1171287
127 1796378

I am reasonably certain the formula to calculate these is quite simple (given the game would not want to waste too much processing power on the music), but I'm being thwarted by the inaccuracies in the above list of numbers.

EDIT:

Here's some more values after some of the discussion below:

 73 439232
 89 878465
126 1772103

EDIT2:

Here are some more values as requested. It looks like values are indeed invalid where the lower four bits of the note number are >= 12.

  7 24417
  8 25887
  9 27452
 10 29064
 11 30818
 12 13654  // possible invalid note
 15 56136  // possible invalid note
 16 32525
share|improve this question
1  
2  
@wj32 Even better: wolframalpha.com/input/?i=fit+{{0%2C+ln+16262}%2C+{1%2C+ln+17258}%2C+‌​{2%2Cln+18301}%2C+{3%2Cln+19391}%2C+{4%2Cln+20529}%2C+{5%2C++++ln+21762}%2C+{6%2C‌​+ln+23042}%2C+{24%2C+ln+51774}%2C+{50%2C+ln+146410}%2C+{80%2C+ln+520403}%2C+{98%2‌​C++++ln+1171287}} (with 127 =1796378 dropped and a logarithm inserted). See the good linear fit. –  Hagen von Eitzen Feb 24 '13 at 10:40
add comment

3 Answers

up vote 6 down vote accepted

Actually, the answer is simple enough in hindsight. The indices consist of two 4-bit numbers. The lower four bits encode the note from C to B, the upper four bits encode the octave. I'm leaving the rest of the answer just because it documents the process of arriving at that result; you won't need any of that.


Much of the world's music, almost all Western music, and practically all computer game music is based on semitones. Two frequencies that form a semitone interval differ by a factor of $\sqrt[12]2\approx1.06$.

In your data, the interval between any two of the first seven frequencies is a semitone; the interval between notes $6$ and $24$ is $12\log_2(51774/23042)\approx14$ semitones, and so on, the next three intervals comprising $18$, $22$ and $14$ semitones, respectively. The last one doesn't come out close to an integral number of semitones; perhaps there's a typo in the last frequency?

[Edit in response to comment:]

Here's a correspondence between indices and semitones of the values you've given, except the upper two that seem to be less exact:

$$ \begin{array}{} 0&1&2&3&4&5&6&24&50&73&80&89&98\\\hline 0&1&2&3&4&5&6&20&38&57&60&69&74 \end{array} $$

Here's a fit based on that correspondence. The fit is as exact as you could wish for, given that you know there are rounding errors in your data. The $R^2$ value is $0.999999$, the resulting function for mapping semitones (not indices) to frequencies is $16273.4\mathrm e^{0.057792x}$, and the coefficient $0.057792$ in the exponent is approximately $\frac1{12}\log2\approx0.057762$, as it should be. Thus, if you can complete that correspondence between indices and semitones, you can get the frequencies to a good accuracy. However, it's not obvious from the values you've provided so far how to complete this correspondence – at the lower end of the spectrum the indices appear to correspond directly to semitones, but then later they seem to move in irregular steps, with $18$ indices corresponding to $14$ semitones, then $26$ to $18$, $23$ to $19$, $7$ to $3$, $9$ to $9$ and $9$ to $5$. You'll probably have to measure more values to make sense of that – if you don't want to measure too many, you could start with some between $73$ and $80$, corresponding to semitones $57$ to $60$, since that would allow you to see whether two indices map to the same semitone or whether there are fractional semitone steps in between.

I don't know whether it's a coincidence, but your index $73$, corresponding to semitone $57$, appears to correspond to your A; at $439.2$ Hz, its frequency is slightly below $440$ Hz, and all the other frequencies are "too low" (with respect to the $440$ Hz pitch standard) by a similar factor.

share|improve this answer
    
No typo in the last frequency, but it is the maximum value so possibly some sort of wrapping or clipping is going on. If these are semitone values, is it possible to produce a simple formula to approximate the values in the table? What you say makes sense but I'm still not quite sure where to start! –  Malvineous Feb 24 '13 at 11:43
add comment

I think I've cracked it. Take your index $i$ $(0 \le i \le 127)$, and express it in hex. Then the high nibble $\lfloor i / 16\rfloor$ is the octave, and the low nibble $i$ mod $16$ is the number of semitones (0-11) above C in that octave. If this is right, then indexes with a low nibble greater than 11 (hex 'B') are simply invalid (and presumably they are never used). This would include the anomalous 126 and 127.

index 0 represents four octaves below middle C.

This doesn't explain all your figures to the last digit, but it will certainly be good enough for your average game player. Perhaps these figures are not well-tempered at all, but optimised for a certain key. I might try to find which key that is if I find myself with some free time :-)

With this in mind, can you post the frequencies for 7, 8, 9, 10, and 11, please?

share|improve this answer
    
You beat me to it by four seconds :-) –  joriki Feb 24 '13 at 12:46
1  
4000 milliseconds is a long time in acoustics. –  TonyK Feb 24 '13 at 12:50
    
@TonyK: I've added the extra values, and a few invalid ones too. It looks like you're right. Using this method gives the most accurate playback yet! –  Malvineous Feb 24 '13 at 20:22
    
@Malvineous: Thanks for that! I got quite excited when I found that 25887/17258 = 3/2, until I realised that would mean the thing was optimised for the key of C#. (What language was it programmed in?) But none of the other ratios checked out, for C# or any other key, and I think that these figures are $-$ inexplicably for me $-$ simply inaccurate. –  TonyK Feb 24 '13 at 21:16
    
@TonyK: As far as I'm aware the game was coded in Intel 386 assembly language. The figures are simply inaccurate as they are programmed into a Yamaha OPL2 synthesiser chip (as found on popular sound cards of the day) and this introduces rounding errors due to the limited range of frequency values that can be programmed into the chip. The trick now of course is to duplicate those same rounding errors... –  Malvineous Feb 25 '13 at 7:31
add comment

It may seem a good guess to assume that these are statndard frequencies of musical notes from the musical scale. To have a formula that is as simple as possible, we shall assume the equal-tempered scale, where each note differs from the base note $a=440\,\text{Hz}$ by a factor of $(\sqrt[12]{2})^k$ for some integer $k$. Especially, we have a factor of $2$ for every twelve steps. Unfortunalety, this does not match at all with your given data. For example 127 seems to be slightly above $a''$ (i.e. $a$ plus $24.35$ half tones) and 98 seems to be slightly below $d''$(i.e. $a$ plus $16.95$ half tones). The index difference of $29$ seems to be too big for the seven half tone steps. Apparently whatever process ultimately converts the indices to an audible sound has some builtin nonlinearity.

EDIT: After dropping the value for 127 and using Wolfram alpha, I suggest $$f(k)\approx\exp(0.0430399 x+9.74885)$$ as a simple fit. Observe that this corresponds to a musical scale having $\approx16$ instead of $12$ steps, so four steps correspond to three conventional half-tone steps. This would allow to produce somewhat accurately for example C, D#, F#, A, but the others not so well. Then again, the 12 step scale is not the answer to all questions.

share|improve this answer
    
It's not nearly as bad as that. Only the last value seems to be off; and a computer game doesn't necessarily have to use tuning to $440$ Hz, so what matters is mostly the factors between the frequencies. –  joriki Feb 24 '13 at 10:28
    
@joriki Acctually, I'd personally suspect computer games to be more likely to use a book value such as $440\,\text{Hz}$, whereas "real" musicians use local or stylistic deviations, see A440. I suggest the OP look for an index $i$ producing something close to $440000$ and see if $i+12$ produces $\approx 880000$. –  Hagen von Eitzen Feb 24 '13 at 10:34
1  
After my recent edit: It looks like rather $i+16$ should correspond to $\approx 880000$. –  Hagen von Eitzen Feb 24 '13 at 10:50
1  
I greatly value your contributions to the site, I'm not trying to prove you wrong; it's just that I do think that your answer in this case distracts from a useful solution, and even more so after your last edit. The first seven values definitely go in semitone steps, and not taking that into account and instead concluding on the basis of a global linear fit that they go in intervals unheard of in popular Western music is unlikely to be helpful. All frequencies except the last are within one tenth of a semitone from a standard scale based on $440$ Hz; most of them are within one twentieth. –  joriki Feb 24 '13 at 10:52
2  
@Malvineous: Why not just use a lookup table? That would be accurate and fast! –  wj32 Feb 24 '13 at 11:57
show 5 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.