Sunday-to-year-lookup (weekday-to-year-lookup)

The problem

Recently, I had a fun problem to solve:

Given a date without year (but a range of possible years – or at least some suspicion) plus the information that this given date was a sunday, can you (easily) determine the year?

Of course, this problem can be expanded to “any weekday” – but *that* problem can be reduced to the “sunday”-one by just moving the date a bit.

Basically, this boils down to “some years are the same in terms of weekday-allocation”. As a simple example: In 1999, there was some advice “if your “device does not support year 2000, set it to yet $otherYearNumber! This way, all weekdays will match”. Our podcast-crew once observed that there are only 14 different “kinds of years”: One for each weekday to start with, multiplied by two because each of these seven sets exists in a “has february 29th”- and a “does not have february 29th”-variant. Going by modern terminology, we called those “premium”- and “plus”-years.

The code

The initial approach was to just get a lot of calendars and look it up, there. I actually did this for the “strong suspicion”-special-case – but I wanted some solution that didn’t require 30 open windows with PDF-viewers. The next approach were some trial-and-error-experiments right in the spreadsheet. Then I remembered, that I’m a software-developer.

Obviously, with the wonders of the modern java-time-package (“modern” as in “since Java 8, released 2014”), functional programming (“modern” as in “rooted in Alonzo Church’s lambda calculus from the 1930s”) and languages to easily glue this together (I used Kotlin, here), this can be programmed in very few lines of code:

fun weekdayCheck(pivotDate: MonthDay, pivotWeekDay: DayOfWeek) {
    val periodBetweenDates = Period.ofYears(
        if(pivotDate == MonthDay.of(Month.FEBRUARY, 29)) 4 else 1
    )
    val allDays = generateSequence(
        pivotDate.atYear(1972), 
        {it.plus(periodBetweenDates)}
    )
        .takeWhile{it.year <= 2025}
    val allMatchingWeekdayDays = allDays.filter{it.dayOfWeek == pivotWeekDay}
    allMatchingWeekdayDays.forEach { println(it) }
}

The limitation to “between 1972 and 2025” is arbitry (partially due to my use-case, partially due to leap-day-support)

The lookup-tables

Toying around with this, a simple table can be constructed (dates are sundays)

1978
1984
1989
1995
2006
2012
2017
2023
1972
1977
1983
1994
2000
2005
2011
2022
1982
1988
1993
1999
2010
2016
2021
1976
1981
1987
1998
2004
2009
2015
1975
1986
1992
1997
2003
2014
2020
2025
1974
1980
1985
1991
2002
2008
2013
2019
1973
1979
1990
1996
2001
2007
2018
2024
01-01
01-08
01-15
01-22
01-29
01-02
01-09
01-16
01-23
01-30
01-03
01-10
01-17
01-24
01-31
01-04
01-11
01-18
01-25
01-05
01-12
01-19
01-26
01-06
01-13
01-20
01-27
01-07
01-14
01-21
01-28

02-05
02-12
02-19
02-26

02-06
02-13
02-20
02-27

02-07
02-14
02-21
02-28
02-01
02-08
02-15
02-22
02-29
02-02
02-09
02-16
02-23
02-03
02-10
02-17
02-24
02-04
02-11
02-18
02-25
Jan-01
Jan-08
Jan-15
Jan-22
Jan-29
Jan-02
Jan-09
Jan-16
Jan-23
Jan-30
Jan-03
Jan-10
Jan-17
Jan-24
Jan-31
Jan-04
Jan-11
Jan-18
Jan-25
Jan-05
Jan-12
Jan-19
Jan-26
Jan-06
Jan-13
Jan-20
Jan-27
Jan-07
Jan-14
Jan-21
Jan-28

Feb-05
Feb-12
Feb-19
Feb-26

Feb-06
Feb-13
Feb-20
Feb-27

Feb-07
Feb-14
Feb-21
Feb-28
Feb-01
Feb-08
Feb-15
Feb-22
Feb-29
Feb-02
Feb-09
Feb-16
Feb-23
Feb-03
Feb-10
Feb-17
Feb-24
Feb-04
Feb-11
Feb-18
Feb-25

Because of that pesky Leapyear-difference, I restarted the table at march

1981
1987
1992
1998
2009
2015
2020
1975
1980
1986
1997
2003
2008
2014
2025
1974
1985
1991
1996
2002
2013
2019
2024
1973
1979
1984
1990
2001
2007
2012
2018
1972
1978
1989
1995
2000
2006
2017
2023
1977
1983
1988
1994
2005
2011
2016
2022
1976
1982
1993
1999
2004
2010
2021
03-01
03-08
03-15
03-22
03-29
03-02
03-09
03-16
03-23
03-30
03-03
03-10
03-17
03-24
03-31
03-04
03-11
03-18
03-25
03-05
03-12
03-19
03-26
03-06
03-13
03-20
03-27
03-07
03-14
03-21
03-08

04-05
04-12
04-19
04-26

04-06
04-13
04-20
04-27

04-07
04-14
04-21
04-28
04-01
04-08
04-15
04-22
04-29
04-02
04-09
04-16
04-23
04-30
04-03
04-10
04-17
04-24
04-04
04-11
04-18
04-25

05-03
05-10
05-17
05-24
05-31

05-04
05-11
05-18
05-25

05-05
05-12
05-19
05-26

05-06
05-13
05-20
05-27

05-07
05-14
05-21
05-28
05-01
05-08
05-15
05-22
05-29
05-02
05-09
05-16
05-23
05-30

06-07
06-14
06-21
06-28
06-01
06-08
06-15
06-22
06-29
06-02
06-09
06-16
06-23
06-30
06-03
06-10
06-17
06-24
06-04
06-11
06-18
06-25
06-05
06-12
06-19
06-26
06-06
06-13
06-20
06-27

07-05
07-12
07-19
07-26

07-06
07-13
07-20
07-27

07-07
07-14
07-21
07-28
07-01
07-08
07-15
07-22
07-29
07-02
07-09
07-16
07-23
07-30
07-03
07-10
07-17
07-24
07-31
07-04
07-11
07-18
07-25

08-02
08-09
08-16
08-23
08-30

08-03
08-10
08-17
08-24
08-31

08-04
08-11
08-18
08-25

08-05
08-12
08-19
08-26

08-06
08-13
08-20
08-27

08-07
08-14
08-21
08-28
08-01
08-08
08-15
08-22
08-29

09-06
09-13
09-20
09-27

09-07
09-14
09-21
09-28
09-01
09-08
09-15
09-22
09-29
09-02
09-09
09-16
09-23
09-30
09-03
09-10
09-17
09-24
09-04
09-11
09-18
09-25
09-05
09-12
09-19
09-26

10-04
10-11
10-18
10-25

10-05
10-12
10-19
10-26

10-06
10-13
10-20
10-27

10-07
10-14
10-21
10-28
10-01
10-08
10-15
10-22
10-29
10-02
10-09
10-16
10-23
10-30
10-03
10-10
10-17
10-24
10-31
11-01
11-08
11-15
11-22
11-29
11-02
11-09
11-16
11-23
11-30
11-03
11-10
11-17
11-24
11-04
11-11
11-18
11-25
11-05
11-12
11-19
11-26
11-06
11-13
11-20
11-27
11-07
11-14
11-21
11-28

12-06
12-13
12-20
12-27

12-07
12-14
12-21
12-28
12-01
12-08
12-15
12-22
12-29
12-02
12-09
12-16
12-23
12-30
12-03
12-10
12-17
12-24
12-31
12-04
12-11
12-18
12-25
12-05
12-12
12-19
12-26
Mar-01
Mar-08
Mar-15
Mar-22
Mar-29
Mar-02
Mar-09
Mar-16
Mar-23
Mar-30
Mar-03
Mar-10
Mar-17
Mar-24
Mar-31
Mar-04
Mar-11
Mar-18
Mar-25
Mar-05
Mar-12
Mar-19
Mar-26
Mar-06
Mar-13
Mar-20
Mar-27
Mar-07
Mar-14
Mar-21
Mar-28

Apr-05
Apr-12
Apr-19
Apr-26

Apr-06
Apr-13
Apr-20
Apr-27

Apr-07
Apr-14
Apr-21
Apr-28
Apr-01
Apr-08
Apr-15
Apr-22
Apr-29
Apr-02
Apr-09
Apr-16
Apr-23
Apr-30
Apr-03
Apr-10
Apr-17
Apr-24
Apr-04
Apr-11
Apr-18
Apr-25

May-03
May-10
May-17
May-24
May-31

May-04
May-11
May-18
May-25

May-05
May-12
May-19
May-26

May-06
May-13
May-20
May-27

May-07
May-14
May-21
May-28
May-01
May-08
May-15
May-22
May-29
May-02
May-09
May-16
May-23
May-30

Jun-07
Jun-14
Jun-21
Jun-28
Jun-01
Jun-08
Jun-15
Jun-22
Jun-29
Jun-02
Jun-09
Jun-16
Jun-23
Jun-30
Jun-03
Jun-10
Jun-17
Jun-24
Jun-04
Jun-11
Jun-18
Jun-25
Jun-05
Jun-12
Jun-19
Jun-26
Jun-06
Jun-13
Jun-20
Jun-27

Jul-05
Jul-12
Jul-19
Jul-26

Jul-06
Jul-13
Jul-20
Jul-27

Jul-07
Jul-14
Jul-21
Jul-28
Jul-01
Jul-08
Jul-15
Jul-22
Jul-29
Jul-02
Jul-09
Jul-16
Jul-23
Jul-30
Jul-03
Jul-10
Jul-17
Jul-24
Jul-31
Jul-04
Jul-11
Jul-18
Jul-25

Aug-02
Aug-09
Aug-16
Aug-23
Aug-30

Aug-03
Aug-10
Aug-17
Aug-24
Aug-31

Aug-04
Aug-11
Aug-18
Aug-25

Aug-05
Aug-12
Aug-19
Aug-26

Aug-06
Aug-13
Aug-20
Aug-27

Aug-07
Aug-14
Aug-21
Aug-28
Aug-01
Aug-08
Aug-15
Aug-22
Aug-29

Sep-06
Sep-13
Sep-20
Sep-27

Sep-07
Sep-14
Sep-21
Sep-28
Sep-01
Sep-08
Sep-15
Sep-22
Sep-29
Sep-02
Sep-09
Sep-16
Sep-23
Sep-30
Sep-03
Sep-10
Sep-17
Sep-24
Sep-04
Sep-11
Sep-18
Sep-25
Sep-05
Sep-12
Sep-19
Sep-26

Oct-04
Oct-11
Oct-18
Oct-25

Oct-05
Oct-12
Oct-19
Oct-26

Oct-06
Oct-13
Oct-20
Oct-27

Oct-07
Oct-14
Oct-21
Oct-28
Oct-01
Oct-08
Oct-15
Oct-22
Oct-29
Oct-02
Oct-09
Oct-16
Oct-23
Oct-30
Oct-03
Oct-10
Oct-17
Oct-24
Oct-31
Nov-01
Nov-08
Nov-15
Nov-22
Nov-29
Nov-02
Nov-09
Nov-16
Nov-23
Nov-30
Nov-03
Nov-10
Nov-17
Nov-24
Nov-04
Nov-11
Nov-18
Nov-25
Nov-05
Nov-12
Nov-19
Nov-26
Nov-06
Nov-13
Nov-20
Nov-27
Nov-07
Nov-14
Nov-21
Nov-28

Dec-06
Dec-13
Dec-20
Dec-27

Dec-07
Dec-14
Dec-21
Dec-28
Dec-01
Dec-08
Dec-15
Dec-22
Dec-29
Dec-02
Dec-09
Dec-16
Dec-23
Dec-30
Dec-03
Dec-10
Dec-17
Dec-24
Dec-31
Dec-04
Dec-11
Dec-18
Dec-25
Dec-05
Dec-12
Dec-19
Dec-26

Leap days / Leap years

When I first did the calculation, I only looked at the timespan between 1973 and 1999 – and was “surprised” that only one leap day was a sunday. After some thinking, I realised that this actually was *above* average: with seven possible weekdays and ~4.1237 years between leap years, the “chance” of having a leap sunday is ~1/28,866; When looking at only 27 years, I was “lucky” to get even one.

But that means that there must have been weekdays that never got a leap day in that time frame. Toying around some more yielded the following info:

SundayMondayTuesdayWednesdayThursdayFridaySaturday
1976
2004
1988
2016
1972
2000
1984
2012
1986
2024
1980
2008
1992
2020

So that confirms it: in the initial timeframe, the odd one out was Tuesday. This table also shows that outside of the pesky 100-year-rule (with the 400-year-rule-exception), the pattern repeats every 28 years.

The year-groups

To conclude things, the following “types of years” can be extracted from that info:

cool nameStarts withFirst sundayLeap day isExamples
“Sunday-Premium”Sunday01-01
Jan-01
1978, 1989, 1995, 2006, 2017, 2023
“Sunday-Plus”Sunday01-01
Jan-01
Wednesday1984, 2012
“Monday-Premium”Monday01-07
Jan-07
1973, 1979, 1990, 2001, 2007, 2018
“Monday-Premium”Monday01-07
Jan-07
Thursday1996, 2024
“Tuesday-Premium”Tuesday01-06
Jan-06
1974, 1985, 1991, 2002, 2013, 2019
“Tuesday-Plus”Tuesday01-06
Jan-06
Friday1980, 2008
“Wednesday-Premium”Wednesday01-05
Jan-05
1975, 1986, 1997, 2003, 2014, 2025
“Wednesday-Plus”Wednesday01-05
Jan-05
Saturday1992, 2020
“Thursday-Premium”Thursday01-04
Jan-04
1981, 1987, 1998, 2009, 2015
“Thursday-Plus”Thursday01-04
Jan-04
Sunday1976, 2004
“Friday-Premium”Friday01-03
Jan-03
1982, 1993, 1999, 2010, 2021
“Friday-Plus”Friday01-03
Jan-03
Monday1988, 2016
“Saturday-Premium”Saturday01-02
Jan-02
1977, 1983, 1994, 2005, 2011, 2022
“Saturday-Plus”Saturday01-02
Jan-02
Tuesday1972, 2000

You can also see that the years in each “premium”-group are six years apart – unless there is a leap-year between then… in that case, the next year in that group is 11 years away. Thankfully, 2000 was a leap year – this analysis could have easily become more complicated if “100-year-but-not-400-year-rule”-year was involved.

Teardown Boogieboard / LCD-Writer / E-Writer

The concept

Some years ago, while browsing on Amazon, those “Boogie Board”s by Kent Displays caught my eye. I was curious, ordered the first one – and have been a fan of the concept ever since.

Their purpose is rather simple: You can write or scribble or draw on it via pressure. A pen is included – and often directly attached in a nice way. For some of these devices, the pen can also be used to form a simple stand.
Once you’re finished, you press the button – and the board is clear, again.

Whenever I showcase that concept to someone, there are some rather typical reactions:

  • “So it’s like those kid-toys where you draw with and magnet and then slide a bar to clear.” (I found those under “Magna-Doodle” – or the more generic term “Magnetic drawing board”)
  • “So it’s like that kid-toy where you push on the plastic with a pen to draw… and then pull it apart from the wax to erase.” (see: “Magic slate”)
  • “How does it save? It doesn’t save? So it’s utterly useless?” (*)
  • “Where can I get one of those? This is exactly what I always needed!”

I’m in the group of people who can use such ethemeral notepads. I think they are useful for short checklists, quick memos and easy scribbling. Very often, the “Kid in car”-use-case is mentioned: You don’t neet lots of pens or paper and you don’t have to worry about kids drawing on the windows. “Kids” is a good use-case in general: It’s easy to always carry one of those (the smaller ones) in your jacket and hand it to a child to pass waiting time (e.g. in restaurants or so).
One might also think about whether such a device has a better environmental footprint than using lots of paper.

(* I’ve used one product which tries to record the drawing; the images can be read from a PC. Also, there has been an app to optimize photos from these devices into monochrome drawing-files)

The competition

Unfortunatley, this is a product for which I found Kent Displays (which seems to be the original inventor) to lag behind their competition.

  • Rather subjective point: They don’t seem to cater to the european merket very well. I had to import some of their products from America. There were some products I was very interested in – but was absolutely unable to get here.
  • It seemed like they were stuck on their two main sizes (11.4 cm / 4.5 inches as smaller; 21.6 cm / 8.5 inches as bigger) for a long time – at a time where the competition already went well beyong 10 inch. I really like the small ones (see above: great for always having one in your pocket) – but for some use-cases, size is everything.
  • It seemed like the competition innovated more quickly: The first time I saw a “erase protection”-slider (for preventing accidental deleting) it wasn’t on a KentDisplay-device. Also, I’ve seen “partial erasing” (in addition to fully clearing the image) on a competitor’s device, first.
  • The pricing-difference is “remarkable”: The small one (4.5inch) costs about 20 EUR; the bigger one (8.5 inch) costs about 30 EUR. These prices seem to never have changed in the almost ten years since I bought my first onse. When browsing at the competition, you can get 12-inch for 15 EUR – and small ones for sub-10-EUR. Obviously, quality has its price and production location may play its part, too. I still believe that the “originals” are worth it – but the alternatives aren’t exactly horrible, either. Also, pricing might be subjective and related to location, again.

Nowadays, you find a lot of those “others” via the search term “LCD-Writer” or “E-Writer”. Even the original “Boogie Board” seems to redirect to the other ones when used as a search term.

How it works

From what I gathered, most of these devices seem to be just giant one-pixel-monochrome-LCD-displays that react to pressure – but don’t require power to keep that image (similar to E-Readers). Once you press the button, the battery is used to power-cycle the LCD, thus clearing it. Power only is required for clearing; so – in theory – such a device might be usable for a long time (lots of erase-cycles; some ads estimate a number) before you need to change the battery.

How it not-works

However, most of the devices that broke down for me couldn’t be resurrected with a new battery. Some of these devices are even built in a way that the battery cannot be exchanged. The original 4.5-inch-devices are among them. I always planned to see whether I could still open it at the right place and insert a new battery (or add some connector pads for an external power source) once it doesn’t work any more. This is the case now.

Taking them apart

Some time ago, I already took apart one of the cheap ones

I kind of expect the “original” ones to be similar. The main thing should be the pads connecting to the LCD-layers (not tearing apart those layers, themselves) and the battery.

Obviously, on that device I broke too much (destroyes the LCD?). I wouldn’t even get it to work with a new battery. Yet, I could confirm that the battery had run dry (far below the 3V operating voltage). When I attached an external power supply, pressing the button made “something happen” at the LCD-connector pad. So I thought that if I manage to replace the power supply without breaking the LCD, I might by able to salvage some of the broken devices.

(“something happens”: My voltmeter shows that AC voltages above 100V are used)

Knowing where to cut and what to keep safe, I managed to isolate the battery part on the next device:

Getting the battery out is a bit of a hassle. But after some cursing, I was able to get exposed connector pads and attach some stable power supply with some crocodiles. I pressed the button and.. (drumroll…) the display cleared!

I don’t plan to put a new battery in there. I’ll have to think about how to connect a “clearing device” for “sometimes-clearing. I’ll also have to try whether the circuits are compatible with P5V – being able to clear it from a standard USB-powerbank without additional converters definitely would be nose.

Not shown: I got two more cheap ones to work with external power supply.

I decided to try with a bigger one that does allow replacing batteries – but didn’t work with a new battery. After all, there rarely is anything to lose on non-working devices.

As it turned out, this one actually worked fine (only needed new good battery). Still: exposing the pads made it easier to expose one battery I considered “good” (by voltage) as unsuitable.

Finally, it was time to look at the original ones. Of course, I had no real reference on where to cut – so I merely estimated. As it turns out, there is a lot of “safe area”: everything is hidden under an additional piece of plastic:

At this poine, I’d like to underline the previous statement of “worth the higher price”: This looks like quality. Even if you were never supposed to replace the battery in one of those: It looks like everything was prepared for it. If “drained” battery” is the main problem, I can imagine putting in a new one and glueing it all up and using the device for another ten years – with only a slight optical downgrade.

And with a new battery, those are “as good as new”. The original batteries seemed fine in terms of voltage; but as soon as there is drain, they quickly drop – and it seems like it’s not enough power for LCD-clearing any more.

Once I knew about the battery “compartment”, I even tried to open the blue one without cutting. Unfortunately, I messed up and peeled apart some of the LCD (?), thus destroying part of the screen. This destruction also is like to spread when using the device – so the device is doomed to be completely unusable at some point in the future. More care is needed to prevent such incidents (seems like “cutting” is the better choice after all). At least I have “uncovering the bottom part once it’s completely unusable” to look forward to.
Still: Both got a bit of a life-extension – countering the manufacturer’s “once battery is empty, device is e-waste”-announcement.

Final patient for this session is a larger Jot. Battery replacement did not work (used a battery that works in other device) – so let’s go the usual “uncovering”-route, again:

Once again, the relevant part is protected by a piece of plastic. Once again, I peeled away too much. This time, the LCD is connected on the top of it (I couldn’t flip open the plastic piece completely). And this time, exchanging the battery with a different power supply did not help. Voltmeter does not show anything on the LCD-connectort; I guess some other part of the electronics has broken down.

So the only thing left to do is take a final picture of the board… and say goodbye to this little device.

Spoiler-Free Ring-collection guide for Zelda-Oracles

This information is compiled from other sources. It aims to be a spoiler-free-guide (only using the numbers) for collecting all rings, grouped by categories.

What to do when rings are missing?

10, 42: Plant Gasha Seeds in rare spots (tier5)

These two rings are tier5 and will only drop from Gasha nuts planted in the “rare” spots.

  • In Seasons, those are “Tarm Ruins” and “Goron Mountain Base (close to temple remains)”.
  • In Ages, those are “Crescent Island (below the One Eyes Tokay statue)” and “Sea of storms” (only in linked game)

12, 23, 47, 49, 50, 51: Plant Gasha Seeds in rare spots (tier4)

These six rings are tier4. Other planting spots may yield them, too, but the rare spots probably are your best bet.

3, 21, 37, 59, 60, 63, 64: Plant Gasha Seeds (tier3)

These seven rings are tier3. The rare spots can still yield them

16, 19, 30, 35, 36, 58, 61, 62: Plant Gasha Seeds (tier2)

These eight rings are tier2 and can be dropped from all spots except the “rare” ones.

11, 28, 31, 32, 33, 43, 44, 45: Plant Gasha Seeds (tier1)

These eight rings are tier1 and should be dropped from common planting spots.

(Some of these rings can also be gotten during regular gameplay or in minigames)

15, 52: Play on GBA (or patch ring secret)

These two rings are only available when playing on GBA. Unless you are playing with an original cartridge, this likely is not an option. There are ways to patch your ring-password, though.

(obviously, there are ways to patch your ring-password to instantly have *all* the rings – thus skipping this guide).

7, 9, 18, 24, 25, 26, 29, 39: Complete Ages

If you are playing Oracle of Seasons: don’t bother! You will not be able to find these rings before transferring them over from Ages.
If you are playing Oracle of Ages: keep searching! Those eight rings are available somewhere.

6, 8, 13, 14, 17, 40, 46, 56: Complete Seasons

If you are playing Oracle of Ages: don’t bother! You will not be able to find these rings before transferring them over from Seasons.
If you are playing Oracle or Seasons: keep searching! Those eight rings are available somewhere.

5, 34, 48: Complete Ages (linked)

If you are playing Oracle of Seasons: don’t bother. If you are playing Oracle of Ages but before a linked game: don’t bother. Those three rings can only be collected when playing Ages in a linked game (after Seasons)

4, 20, 22: Complete Seasons (linked)

If you are playing Oracle of Ages: don’t bother. If you are playing Oracle of Seasons but before a linked game: don’t bother. Those three rings can only be collected when playing Seasons in a linked game (after Ages)

Some of those “linked” rings are hidden behind link-secrets, so be sure to do all of those, too.

1, 2, 27, 41, 53, 54, 57: Complete game

There is no special requirement for those eight rings. They can be collected in either game.

38: Complete game (linked)

This one ring does require to play in a linked game – but is available in both of them (Seasons after Ages; or Ages after Seasons)

55: Do not search, just start over

This one ring cannot be “found” in the games… but it will automatically be in your inventory when you restart a game with the password you get after completing a linked game.

Summary

Ring #MethodCount
10, 42Gasha Tier 52
12, 23, 47, 49, 50, 51Gasha Tier 46
3, 21, 37, 59, 60, 63, 64Gasha Tier 37
16, 19, 30, 35, 36, 58, 61, 62Gasha Tier 28
11, 28, 31, 32, 33, 43, 44, 45Gasha Tier 18
15, 52GBA (or patch)2
1, 2, 27, 41, 53, 54, 57Any Game Completion7
38Any Game (linked) completion1
7, 9, 18, 24, 25, 26, 29, 39Ages Completion8
6, 8, 13, 14, 17, 40, 46, 56Seasons Completion8
5, 34, 48Ages (linked) completion3
4, 20, 22Seasons (linked) completion3
55Start with Hero’s secret1

Hyrule Warriors, Definitive Edition, Fairy Stats Mechanics

Abstract

Conserning the Fairy Stats Mechanics (regarding food, stats and refreshes), I’ve read the statement that the game mechanics work in your favour and you can basically do no wrong. You cannot be permanently locked out of something – you could only take longer to reach your goal by using less optimal strats.
I wanted to verify that statement. This is the documentation of that experiment. The short answer is: That statement is true.

The fairy stats mechanics

The fairies in “Hyrule Warriors: Definitive Edition” have ten status numbers (we are interested in): Eager, Relaxed, Aspiring, Valuant, Resolute, Smiley, Dizzy, Shrewd, Friendly and Sparkly. Each of these numbers is in a range of 0 to 255. Five of those are “active” and visible for a fairy at a given time. The remaining five are hidden and are presumed zero for requirements.

Those values are used to unlock magic powers that can then be used in battle. Once the requirements for a power are met, the power is unlocked permamently and the player can start training to other status values (also called “personality” in-game). The requirements for a magic power always is a combination of “stat x has to be at value y at minimum”. The exact minimum values are not directly displayed in-game but can be found out rather easily.

The player can manipulate the fairies’ stats by feeding them. The exact effects of the food vary by type of the food, quality of the food and even preference of the fairy. The exact effects are not relevant for this experiment. Unfortunately, with each given food item, the fairy grows levels and at Lv99, the numbers can no longer be manipulated.

At that point, a fairy can be “refreshed” – their level is reset to zero but the status values also change (most of the time and especially in early game, this means a large cut). At that point, one of the active personalty traits can be exchanged for one of the inactive. The theory says that although a refresh results in lower values (for most of the times), the values will always be better-of-equal than they were after the last refresh. If a fairy never has been refreshed before, the first refresh results in better-or-equal stats compared to the values after finding the fairy.

Determining the current status values of a fairy

Obviously, I need a way to determine the current stats of any fairy to be able to compare than to anything. The game screen does not list them as absolute values; directly reading values from memory or savegame is not available to me at the moment. So I have to determine them indirectly:

The game shows how many points a fairy is missing towards a given magic power. Thus, if (as an example) “Weapon Master” requires a stat of 255 on “friendly” and the game says that my fairy only needs 26 more, I can conclude that my fairy has 255-26=229 points on “friendly”. I used a small LibreCalc-table for calculation: Just insert what the game determines “missing” on the stats towards different magic powers and the current status values are automatically calculated.

Determining the requirements for magic powers

Okay. The exact number requirements for magic powers are not given directly in the game, either. I can, however, use the same trick as before: If I know the exact current status value of one fairy, I simply add the number that is missing (as told by the game) and know the exact requirement. I only have to do that once for each magic power (and not even for all of them).
Example: If I have known 26 points on “Friendly” and the game says that 229 are missing toward “Weapon Master”, I can say that the requirement is 26+229 points.

So by knowing one of “current stat” and “real requirement”, I can calculate the other with the information given by the game. This sounds like a Catch-22, at first, but I have status values with known zeros (currently-hidden personality traits; also many fairies on their starting stats). In that case, the missing number is the true requirement.
Example: If my fairy does not even have “Friendly” active and the game says that 255 points are missing towards “Weapon Master” (and even uses a different color to highlight that the trait is inactive at the moment), I know that this magic power has the maximum possible requirement for “Friendly” (remember that values are between 0 and 255).

Also, the numbers are known and on the Internet. I tend to use this for checking my results but not just copy the values.

Obviously, I can only use these calculations until the required starts are met. This is no problem with stats that require 255 points. Six of these can be found on the rainbow-colored-skills (Im playing Definitive Edition on Switch) as each these requires 255 in one stat. However, this leaves four stats that never require 255 on any skill (Relaxed, Aspiring, Valiant and Dizzy). This would only become a problem when a fairy’s current are high (>200) and we will not reach that point in the Experiment.

The experiment itself

I start my experiment with a freshly-caught darkness fairy called Chomp. Therefore she is Lv1 and has no refreshs. By using the “difference”-method described above, I can see the following stats:

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Chomp, starting stats

Oh.. also, the starting stats of all fairies have been posted by fans over the internet. This always is nice for double-checking your values.

I then raise her to Lv99 using less-than-optimal food:

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Before Refresh1020400030206000

Seriously: You need to do things wrong to only gain 196 points in total (and lose 40 in the process). However: effective feeding is not the scope of this experiment. It’s the opposite: The experiment should show that I cannot screw it up however hard I try.

I now refresh the fairy without changing name or personality traits:

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Before Refresh1020400030206000
After Refresh1022440402340000

So I can already observe some things:

  • My stupid investment in “Dizzy” payed off: The new value is 20 higher than before. A much smaller variant can be seen in “Smiley”: I increased by 10 but gained 3 points.
  • “Relaxed” and “Aspiring” also gained 10% from their initial value – without me investing anything in them.
  • “Resolute” is back to the basic 40 in spite of me having reduced it to zero by bad food choice.

Again, I raise to Lv.99 in one of the worst ways possible:

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Before Refresh1020400030206000
After Refresh1022440402340000
Before Refresh2022440>225>20040000

Unfortunately, my big investments were in stats I cannot/did not perfectly observe. The exact numbers are not too relevant at this point, anyway.

I refresh again, but this time, I exchange stats: Resolute leaves, Eager comes in:

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Before Refresh1020400030206000
After Refresh1022440402340000
Before Refresh2022440>225>20040000
After Refresh202448004644000

At first, this looks like a very stupid thing to do: Resolute is calculated as 0 after such a large investment. I don’t know yet whether the stat is simply hidden (as it is inactive) or really reset to zero (Spoiler: It is merely hidden).
The visible values offer the following observations:

  • My initial investment in still “Dizzy” pays off: 4 points are added – this is more than 1 percent (10% of 10%) of my 186-point-investment. I didn’t need to do anything in this round.
  • “Relaxed” and “Aspiring” still crawl 10% of their initial base value – without me ever touching them.
  • “Smiley” does a jump to the “Dizzy”-one in the first round: 23 points gained indicate a previous value of 230>=x<=239.

In the next feeding round, I do a horrible job, again:

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Before Refresh1020400030206000
After Refresh1022440402340000
Before Refresh2022440>225>20040000
After Refresh202448004644000
Before Refresh32022448004644000

As I refresh, I switch out “Relaxed” and let “Friendly” come in:

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Before Refresh1020400030206000
After Refresh1022440402340000
Before Refresh2022440>225>20040000
After Refresh202448004644000
Before Refresh32022448004644000
After Refresh320052005048000
  • “Relaxed” disappears – as expected.
  • “Aspiring” crawls another four points. By doing nothing, I already gained more than 10 points. The next refresh will show whether the 10%-bonus applies to points gained by lazyness.
  • “Dizzy” and “Smiley” still both return on their previous large investments.
  • “Eager” does not do as well as it had an initial of zero. However, the new base value puts it on the same path as “Relaxed”.

I raise to Lv99, again – carefully avoiding “Aspiring” and putting a lot to “Friendly” and “Eager” – the newcomers:

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Before Refresh1020400030206000
After Refresh1022440402340000
Before Refresh2022440>225>20040000
After Refresh202448004644000
Before Refresh32022448004644000
After Refresh320052005048000
Before Refresh415605200504801960

I do the next refresh and exchange “Dizzy” for “Resolute” – fearing that my large round-2-investment was for naught.

EagerRelaxedAspiringValiantResoluteSmileyDizzyShrewdFriendlySparkly
Lv1020400402020000
Before Refresh1020400030206000
After Refresh1022440402340000
Before Refresh2022440>225>20040000
After Refresh202448004644000
Before Refresh32022448004644000
After Refresh320052005048000
Before Refresh415605200504801960
After Refresh4350570645500190
  • “Dizzy” disappears – again, this is no surprise.
  • “Resolute” is back – stronger then before. It did not really rise in its absence but got an expected 24-point-boost before disappearing.
  • “Aspiring” accelerates growth – without ever being toucht by me. Similar to that “Smiley” is getting faster – but also required an investment to get to a “new starting value” of 40.
  • “Eager” gained the expected 10% of 156 on top of the new base.

Collected Observations

I think at that point I can stop wasting fairy food. I can consider that experiment a success and the theory true:

  • Inactive values only get hidden and return with their previous value (plus the last bonus) when activated, again
  • Initially-zero-stats never return to their low values once something was invested in them. An investment of 10 will result in a rise of 1 that will never be lost. An investment of 100 will result in the base value increased by 10, this ensuring growth for each round the value is not slahed below 10.
  • Non-touched-values accelerate growth by themselves over time – as long as they have at least the 10 points required for a 1-point-growth. Ten rounds of not touching an “base-10”-value will result in a new base-20-value. Five rounds of an unslashed base-20-balue will result in it becoming a base-30-value – and so on. Investing 100 points in an iteration will put into the next base-(n+1)-tier, instantly.
  • If a value is decreased below its base value (base=after the last refresh), it returns to (at least) that starting value after the next refresh.

Conclusion

Given enough time and food, you should be able to raise a fairy with 255 in all stats. Values will never be lowered on refreshs – although five traits will be hidden at any time.

Obviously, some time of strategy cuts down the number of refreshs (and food) required. You may want to keep good food for reaching the values for a specific magic power in one refresh – but early strong investments pay off when more refreshs are required or planned.

10 rounds from “Base-10” to “Base-20” plus 5 rounds from “Base-20” to “Base-30” plus 4 rounds from “Base-30” to “Base-42” plus 2 rounds from “Base-42” to “Base-50″… sums up to 39:

The World ends with you – Final Remix – Mastering “those” pins

There’s a completionist inside of me. So when I played “The World Ends With You – Final Remix” (TWEWY) for the Switch, there was a time of plain fun and story but there was a time of “playing for real”, afterwards. This also means doing each Pin Evolution at least once and mastering each Pin at least once. Part of this turned out to be not so simple.

By the way: I am not going to explain the basic game, here. I assume that someone who finds this post already knows the basics and is only searching for the details – which I was searching for, some time ago.

Pins gain experience, called PP in this game. Gain enough experience and the Pin grows a level. Gain enough Levels and the Pin can “evolve” into another Pin. It can also be “mastered”, thus no longer growing and no longer evolving into anything else.

My first “Gotcha” was that there are two kinds of experience in the Game: One is gained by Battles, one is gained by Standby (having the Pin equipped and not playing the game – putting the Switch into Standy). Well, the main “Gotcha” was that this difference influences evolution. At first I thought that a Pin can either be mastered or evolved into another Pin. It turns out that some Pins have two evolution. One “prefers” Battle PP, the other one “prefers” Standby PP.

So. Easy then, right? If a Pin states that it might evolve, just aquire two of them, have one equipped during battles until it evolves (or not), then equip the other during standby until it evolves (or not). That way you can get both Evolution directions. But wait – how do I “master” a Pin with two evolutions?

The DS-Game (turns out that the “Final Remix” is not the first version of the game) solved this problem by having *another* kind of experience. Just collect that one until the Pin reaches its final level. The Switch-version is a bit more tricky. Like in the DS-game, majority decides the potential evolution direction. But if it was “simple majority” (more than 50%), a Pin would always evolve. So a Pin has to have much more than 50% majority in one kind of experience to trigger that evolution direction. Some sources on the Internet claim that the limit is at 80% and my experiments indicate that this may be right.

  • 0-20% Battle -> 100-80% Standby: Evolution into Standby direction
  • 0-20% Standby -> 100-80% Battle: Evolution into Battle direction.
  • 20-80% Battle -> 80-20% Standby: No Evolution. Pin will be mastered.

There is another “catch”: There are different weights. Standby PP are “worth” nine times as much as Battle PP. There also is another “Gotcha”: Some pins have an evolution level for one of their directions that is lower than their max level – but I have not yet experiences a problem with this rule, yet.

After all this dry talk, let’s show some experiment results:

Experiment 1: Burning Cherry

Pin 062 is a “Mus Rattus”-Pin, “Burning Cherry”. It can be bought at “Shibukuya Main Store” – easily buyable Pins are great in case experiments go wrong. Battle PP Evolution is 064 (Burning Berry); Standby PP Evolution is 063 (Burning Melon).

I battled until it was Lv3 and only 128 PP were missing to Lv4. Then I collected Standby PP.

The Pin evolved into Burning Melon (Standby direction). So what has gone wrong?

Burning Cherry has a “fast” evolution curve (can be seen in the menu). This means the folling Exp-Table:

Lv1->Lv2Lv2->Lv3Lv3->Lv4Lv4->Lv5
Next58133190241
Total58191381622
required PP in the “fast” evolution curve, look it up on the net or calculate it from the game

My Pin had 128 PP missing to Lv4, so it had 381-128=253 Battle PP. The remaining 368 PP (=622-253) were standby PP. If Standby has simple Majority even without weight, that is a bad thing. With the weight, it was 369*9=3321 Battle PP – out of a sum of 3574. A simple Google Table with functions confirms that this is too much.

ForMaxBattleStandbyWeighted?SumB%S%
CherryLv3, 128 missing622253369332135747,08%92,92%
Maths behind my first experiment failure

Experiment 2: Masamune

Pin 081 is a “Jupiter of the Monkey”-Pin, “Masamune”. It can be bought at “AMX”. Battle PP Evolution is 083 (Nenekiri); Standby Evoluion is 082 (Onikiri)

I battled it to Lv5 with 221 PP missing. Then I collected Standby PP – and got the Standby-Evolution again. What went wrong, here?

Masamune also has a “fast” evolution curve but goes to Lv7.

->Lv2->Lv3->Lv4->Lv5->Lv6->Lv7
Next58133190241287330
Total581913816229091239

My Masamune had 909-221=688 Battle PP. That means that 1239-688=551 PP were filled with Standby. This is no longer simple majority but with weight it turns into 4959 out of 5647 (4959+688) – equivalent to 87 out of 100

ForMaxBattleStandbyWeighted?SumB%S%
MasamuneLv5, 221 missing12396885514959564712,18%87,82%

Experiment 3: Another Cherry

Now that I think that I got the maths down (and created this nifty table to update during battling), I tried another cherry and more-or-less carefully battled until the formula pulled the S% lower than 80%. This was the case at 580 (42PP missing to Lv5)

ForMaxBattleStandbyWeighted?SumB%S%
Cherry6225804237895860,54%39,46%

The rest was filled with Standby PP – and this time, it was a success: The Cherry got mastered.

Experiment 4: Another Masamune

I did the same for another Masamune: ForMax is =58+133+190+241+287+330, Battle is =1239-157 (as the last battle pushed me to “157 until Lv7). This is the quasi-inversion of the majorities from experiment 3.

ForMaxBattleStandbyWeighted?SumB%S%
Masamune123910721671503257541,63%58,37%

Again, the remainder (167) was then filled with Standby PP and the Pin did not evolve but was mastered, instead.

Experiment 5: Hounder Magnum

Hounder Magnum is in the “Somewhat Slow”-curve:

->Lv2->Lv3->Lv4->Lv5->Lv6
Next78176252320381
Total782545068261207

I collected 81 PP in the first Battle, 237 in the second and 202 in the third. This put me at 520 Battle PP – less than half of 1207. So I did another battle, got 358 PP – and the Pin evolved into Battle direction. This was not one of those “early evolutions”. This was me failing to see that “Hounder Magnum” will always be mastered at Lv5 – which I hit with the fourth battle – full Battle PP, no chance for any Standy PP to be gathered.

On the other hand: If I had not done the battle, I would have gotten a Standby Evolution instead. (520+306 ouf of 826 -> 520 + 2754 out of 3274 -> 15,88% + 84,12%). Maybe I could have done a battle with less PP gained.

Experiments 6 and 7

Now that I knew what not to do, the next experiments were successful. I will not put describe in the same details as the others. If they didn’t prove that “even slightly less than 80%” is okay, I would have omitted them.

ForMaxBattleStandbyWeighted?SumB%S%
Natural MagnumNormalLv57215291921728225723,44%76,56%
One Love MagnumSomewhat SlowLv612078403673303414320,28%79,72%

Generalization (Formula)

With the power of math, I can now determine the “allowed” range for every MaxPP and therefore for every Pin with two Evolution directions. As I don’t want to copy LaTeX or complicated formulas into WordPress, I’ll only touch some steps and leave the details as an exercise to the student:

  • B+S = Max (obviously)
  • B+9S = MaxW (weighted Max), therefore MaxW = B+S+8S = Max+8S
  • 9S / MaxW = Ratio, therefore Ratio =9S/(Max+8S) (I want MaxW out of this and Max is known/can be easily determined for every Pin). Max+8S always is non-zero.
  • (…)
  • Max * Ratio = S (9-8 Ratio) <=> S = Max*Ratio / (9-8 Ratio)

It may seem “less nice” that the Ratio is in both numerator and denominator but as we want the ratio to be between 0,2 (20%) and 0,8 (80%), we can just insert those as constants. For a ratio of 0.2 this resolves to S = Max/37; B=(36/37)*Max. For a ratio of 0.8 this resolves to S = (4/13)*Max; B=(9/13)*Max. Keep the Standby PP (and vice versa the Battle BB) in this range and you should be safe. I don’t know whether you can really “overshoot” with BattlePP (this having a non-const Max) but if you start with BattlePP and then fill up with StandbyPP, there is no risk.

So let’s add those calculations to the level curves:

Fast->Lv2->Lv3->Lv4->Lv5->Lv6->Lv7
Next58133190241287330
Total581913816229091239
S for 0.21,5675675685,16216216210,297297316,8108108124,5675675733,48648649
S for 0.817,8461538558,76923077117,2307692191,3846154279,6923077381,2307692
B for 0.256,43243243185,8378378370,7027027605,1891892884,43243241205,513514
B for 0.840,15384615132,2307692263,7692308430,6153846629,3076923857,7692308

Note how this matches the first four experiments: 253 BattlePP for Cherry (Lv5) is lower than the required 430 whereas 580 BattlePP is higher than 430 but lower than 605. 688 BattlePP for Masamune (Lv7) is lower than 857 but 1072 is safely in the range.

Normal->Lv2->Lv3->Lv4->Lv5->Lv6
Next68154220279333
Total682224427211054
S for 0.21,837837838611,9459459519,4864864928,48648649
S for 0.820,9230769268,30769231136221,8461538324,3076923
B for 0.266,16216216216430,0540541701,51351351025,513514
B for 0.847,07692308153,6923077306499,1538462729,6923077

My Natural Magnum (Lv5) with 529 BattlePP is just slightly higher than the required 499 – so no risk of Evolution.

Somewhat Slow->Lv2->Lv3->Lv4->Lv5->Lv6
Next78176252320381
Total782545068261207
S for 0.22,1081081086,86486486513,6756756822,3243243232,62162162
S for 0.82478,15384615155,6923077254,1538462371,3846154
B for 0.275,89189189247,1351351492,3243243803,67567571174,378378
B for 0.854175,8461538350,3076923571,8461538835,6153846

My “One Love Magnum” (Lv6) had 840 BattlePP was very close to the lower limit – but safely evaded evolution. My next “Hounder Magnum” (Lv5) is waiting in Standby and has 578 BattlePP – close to but sufficiently higher than 571. I’m confident about this one.

Mastering “Octo Squeeze” might become funny/tricky: According to one translation, it has a max Level of 6 but a Battle-Evolution on Lv4.

Slow->Lv2->Lv3->Lv4->Lv5
Next108269405531
Total1083777821313
S for 0.22,91891891910,1891891921,1351351435,48648649
S for 0.833,23076923116240,6153846404
B for 0.2105,0810811366,8108108760,86486491277,513514
B for 0.874,76923077261541,3846154909

Very Slow->Lv2
Next108
Total108
S for 0.22,918918919
S for 0.833,23076923
B for 0.2105,0810811
B for 0.874,76923077

So that’t is. I still have some Pins to master but I think that now I know how much BattlePP to put into them – and how careful I have to be with choosing battles and chains. I hope this explanation was of some use to you, too.

Addendum: Octo Squeeze – the special case

As promised, mastering this one pin is a bit trickier.

Most Pins with two evolution directions only have one “evolution level” at their max level. Let’s take “Burning Cherry” (062) as an example: Reach Lv5 with dominant Battle PP – and Battle Evolution occurs. Reach Lv5 with dominant Standby PP – and Standby Evolution occurs. Reach Lv5 without any type dominant (more than 80% after applying weight) and the Pin is mastered.

Some Pins have on additional “evolution level” before its max level.. “Happy Beam” (012) is an example: Reach Lv5 with dominant Standby PP and Standby Evolution occurs. Reach Lv5 with dominant Battle PP and no evolution occurs – you are free to continue until Lv6. If Battle PP still is dominant when reaching Lv6, Battle Evolution occurs. If Standby PP is dominant at that point, no evolution occurs – same as without any dominant PP type.
With the previously described strategy, this is no problem as we start with amassing Battle PP. It is okay if that type is dominant at lower levels – as long as we stop before reaching MaxLv.

And then there is “Octo Squeeze” (118).

ForMaxBattleStandbyWeighted?SumB%S%
Octo SqueezeSomewhat SlowLv61207738Battle at Lv4

This pin has two evolution levels before its max level. Reach Lv3 with Standby PP dominant and Standby Evolution occurs. If Battle PP is dominant at that point and you are free to continue to Lv4 – but be careful: Although MaxLv is Lv6, Battle Evolution can occur at Lv4. This is what happened to me in my first try: Targetting the range for Lv6 (835-1174 BattlePP) I reached Lv4 with 100% Battle PP and triggered the evolution.
Fortunately, there is a simple cure: The Pin only has one evolution level per evolution direction. Pass it without evolution and you are safe. Basically: Ignore the given MaxLv at the Pin and treat it like it had MaxLv at Lv4.

ForMaxBattleStandbyWeighted?SumB%S%
Octo SqueezeSomewhat SlowLv4?50640997873128231,90%68,10%
Octo SqueezeSomewhat SlowLv5?826409417375341629,83%90,17%
Octo SqueezeSomewhat SlowLv6?1207409798718275915,39%94,61%Master

I started with Battle PP and passed Lv3 with 100% BattlePP – thus skipping the Standby Evolution. I then stopped at 409 BattlePP – safe in the 350-492-region for Lv4-SomewhatSlow-Pins. The remainder was filled by Standby. When reaching Lv4, no type was dominant (although Standby was more than double after applying weight), so Battle Evolution was skipped (I guess that dominant StandbyPP would have worked, too). Lv5 was reached with StandbyPP dominant (90%) – but there is no evolution for Lv5 on Octo Squeeze. Same with reaching Lv6 – the Pin was mastered.

I don’t know why some Pins can evolve earlier. They are that rare that it seems strange to even bother with this mechanism. It’s even weirder that exactly one Pin has two lower evolution levels – it’s not even that special. Why not use this idea on many more pins – or none at all?
On the other hand: I should simply be happy that not more Pins are that complicated and that even that one Pin has a simple “fix”: Just pretend it has a MaxLv of Lv4!

Midi and the Guitar Hero drums – revisited

Unfinished Business

Regarding my MIDI-projects, I left a cliffhanger: My Guitar Hero drums only send MIDI-data when a Wiimote is connected and that Wiimote is connected to a Wii. I didn’t check whether a Wiimote-bluetooth-PC-connection would suffice but it still seems unneccessary overhead. To quote that old post:

“At some point in the future, I want to try a non-Wiimote-power-supply.”

Soldering a power supply to the circuit board itself was no option (at least not the first one); that left the Wiimote-connector to be considered. I could take that apart or I could try to interface this. Taking apart the connector would limit its potential for music gaming sessions so I prefer leaving the drum set intact and experiment at that outer interface (hmm. This is starting to read like blackbox-testing…).

Connector

Obviously, that idea requires one of those Nunchuk-connectors – as they are present at the bottom of Wiimotes. My option at that time was sacrifying a Wiimote for its connector. If I wanted to play man-in-the-middle, I’d also need a connector-plug – as present on Nunchuks. In those cases, cutting an extension cord and building one of those breakout-boxes is my favourite Modus Operandi.
But as nobody really needed to extend the cable between Wiimote and Nunchuk, those extension cords were not really available – just another reason to postpone that project.

Things have changed. Nintendo introduced something that fuelled the need for Nunchuk-extension cables:

HNI_0095

In case you don’t know these: Those are miniature versions of the classic Nintendo Entertainment System and the Super Nintendo. They are powered via Micro-USB, can be played on HDMI-devices and come pre-loaded with games. People were successful in loading other games (or even other console emulators) onto these devices but this is not today’s scope.
More interesting is the Controller connector: Nintendo didn’t use the classic 7-pin 4021-parallel-to-serial-approach but used the I2C/TWI connector from the Nunchuk. This has the advantage that those controllers can be used at the Wii (as limited classic controllers) and Wii-controllers work on the mini-consoles (the home-button even is mapped to reset).
A common complaint about these controller is that the cables are too short. So suddenly there was a market for extension cords and I could get some cheap ones. So after just a few years, my plan to build a Breakout-box was pushed forward.

Breakout-box

You might have seen them on other projects:

  • Buy a cheap case
  • Buy some horribly expensive 2.6mm-bananaplugs,
  • Drill holes into the case

HNI_0096

  • Solder bananaplugs to spliced extension cable
  • Screw plugs into case
  • And.. fail. As it turns out, two pins are shorted: VCC is available on two pins. On the other hand, shield has its own wire – so I needed to drill another hole.

Breakoutbox is finished and works. A little try on the NES Mini confirms that VCC is about 3.3V – and that the controller goes dead if data or clock-line is missing. I hoped that power would suffice for at least some thing – the Turbo-button might have shown a reaction. That’s not a good sign – if the drums refuse to work without data/clock, this would become more complicated.

Next up is Mario Kart Wii. This game is my secret go-to-utility when it comes to the Nunchuk-port: Once in multiplayer-controller-registration, is instantly shows when something is connected to the port and what device was detected. It helped me a lot when I was fixing some broken cables/controllers.
This time, it is not very helpful. It seems like main communication is done when something gets connected to the wiimote. Disconnecting or connecting single wires does not show any results.
I’ve even read somewhere that in reality, only one wire is used to power the connected device – but it shorts this wire to another one to show it is present. My extension cable already shorts those two wires, so I cannot test that.

Big guns/drums

Finally, I connected the drum-kit: The Breakoutbox lets me see that there only is power if the Wiimote is connected (or trying to connect). Mario Kart does not recognize it as a Classic Controller or Nunchuk. Most importantly: The Wiimote still sends power even if the I2C-pins are disconnected – and the drum kit still sends midi-signals when only the power is connected. It does not demand an I2C-connection to the Wiimote before sending data.

So only one thing left to do: Disconnect the Wiimote and inject P3.3 via a different power supply:

HNI_0097

You can see that nothing is connected to yellow or green (clock and data) and the right-hand-side of the box is completely unused. Near the bottom you can also see the Midi-cable plugged into “MIDI OUT”.

Aaand. It works. I may want to use a different power supply (USB with conversion to 3.3V? Perhaps two AA-batteries might suffice) but the main thing is: You don’t need a wiimote or a bluetooth connection to use the Guitar Hero drum kit as a Midi device. Maybe it’s even easier with the drum kit for other game consoles (only Wii accessoires tend to demand a Wiimote).
I won’t judge whether the drum kit is really useful as a Midi-instrument. My drumming skills are not good enough for that. I won’t judge whether the drum kit is cheaper of more expensive than “real” Midi drums.
That was not the scope of this experiment. I answered I question I had years ago and I am happy with that.

Midification of a toy keyboard

Again: This post is a bit dated. The pictures seem to have been taken in 2011.

What to do after learning a little Midi?

So after learning the simple ropes, I decided it was time for a simple project. I could have tried to build a simple synthesizer (MIDI in plus using the AVR timers for square wave generation -> chiptune) but that would have meant learning much more about music with the AVR. Instead I went for the midification of an existing keyboard.

Midification is a play on the word “modification” and means modifying an existing instrument to use MIDI. I know: Once you explain a joke, it stops being funny.

Crappiness before the operation

I still had some simple children’s keyboard lying around.

hni_0019

I got it for about free and this is just slightly more than the price I would have been willing to pay for it. It’s crap. It sounds terrible, you can only press one key at a time (all the keys together form a single resistor value, very simple DAC-conversion to save wires), the keys are very low quality (metal plates pushing on the resistor legs), they are very small (although that can be blamed on “children’s” keyboard). Volume can be binary switched between “noise” and “slightly louder noise”.
It has a demo-function (labeled “store”) which plays “Für Elise”. It sounds “less terrible” than the sounds created via keyboard. Is is much louder than what you can play manually. It also trolls you as it uses notes you cannot play on the keyboard.
To finish up the crappyness, the right speaker doesn’t work (after opening the keyboard, I switched this to “simply doesn’t exist”). Also the left speaker looks greatly different from what you’d imagine from the outside. They cheat at every corner..

hni_0020

You can have a bit of fun attaching a variable resistor (potentiometer). According to my notes, the built-in keys range from 0 to 118 kOhm with higher resistor value resulting in a deeper noise. Remember “Für Elise”? The note created with 0 Ohm is still deeper than the first note of the built-in-song. You’d need negative resistance to play the song with that keyboard..

This keyboard is just so crappy; when I got it, I knew that I’d have to save it for something special – I just didn’t know what to do with it.. However, then I didn’t know much about MIDI, yet.

What to keep?/Wire madness

The first decision in such a case is always: “What can be kept? What should be replaced?” although in this case it’s rather “What needs to be kept? What can be improved?”. Of course, the keys itself should be kept or else I could just build something completely new. Still, I need to get rid of the resistors as I want to support multiple keys pressed at the same time and don’t mess with analog values. If I kept the common ground, I’d had to waste 25 pins on my AVR just for the keys, so I have to split that too.

I could have used the SNES-approach (using 4021 parallel-to-serial converters) but that would have meant to use a lot of pullup-resistors. Also, I didn’t have 4021 lying around. So I decided to try the matrix-approach. With the ATTiny2313 in mind (I had one of those, plus ATMega seemed overkill for that task), and 25 being 5*6 (well, It’s better to leave some room for extensions. Also, I wanted to use the switches),

So first thing to do was to divide the common GND bar into five parts consisting of five keys each. I did this by simply cutting this high-quality metal with an ordinary kitchen knife and then isolating the parts with isolation tape:

hni_0021

Please note that the longer tape between bar two and three holds a short wire. This way the connection to key ten is improved plus this gives me a better point to solder, later on. It is in no way sourced in my inability to count and a mistake of cutting at the wrong place.

As most parts of the bar are held only by a single screw, I was afraid that this might become instable (well, even more instable than before) but it seems like the screw plus the tape keep the keys in place. A quick check with my trusted Pryficus E5 revealed that in fact the connections had been terminated.

Next, I needed to get rid of those resistors and replace them with simple wire.

hni_0026

Every key is connected to some others (yellow wires) but those other keys have a different gnd (black wire), so to determine which key is pressed, you iterate through the gnd-lines and check which yellow line is connected to it. Most computer keyboards use a similar approach (matrix). However, without precautions, this can result in “ghosting” (in certain combinations, some keys are regarded as pressed that aren’t). For my toy project, I didn’t care about that.

The board to output true Midi-signals to a Midi-Din-Port is rather simple. The relevant parts don’t differ from the other midi-post: 220-Ohm-Pullup-resistors, 74LS00 for output signals – plus the socket for the programmed AVR:

hni_0027

The AtMega comes into play

Of course, this maze of wires was not immediately soldered onto the interface board: I used the AVR-eval-board for testing and programming until everything worked fine. I re-purposed some interface-block (connected to the eval-board via IDE-cable) to act as a breakout-box for the AVR-pins:

hni_0028

The software consists of several parts:

  • Simple Midi commication stuff (initializing USART port, sendings commands via sending chars)
  • “Reading the matrix” – putting a single “row” into active low and checking which “columns” show the GND value – meaning that the key to connect this column to the row is pressed. The “active-low”-method is documented in the source and protects the AVR; some key combinations could result in a HI and a LO pin being short-circuited to each other and therefore damaging the chip.
  • Storage of the previous values to determine whether a key was pressed or released.
  • Simple channel switch: One of the physical switches is used to choose two different channels. Those can have different “instruments” and can also keep some notes playing by switching the channel before releasing the key.
  • Instrument change switch: I decided to use the play/store switch to change into a mode selecting the instrument (for the currently active channel). The whole “find-highest-white/black”-logic is used to determine the new instrument (white keys select 00,10,20,30,40,… black keys add +0, +1, +2,…).

I am aware that the source is not beautiful and I should not have mixed english and german comments. I promise that my coding skills have improved since then!

#include <stdlib.h>
#include <util/delay.h>

#define DDR_MATRIX_ROWS DDRB
#define DDR_MATRIX_COLS DDRC
#define PORT_MATRIX_ROWS PORTB
#define PORT_MATRIX_COLS PORTC
#define PIN_MATRIX_ROWS PINB
#define PIN_MATRIX_COLS PINC
#define FIVE_BIT_SET (0x1f) // 0b00011111
#define SIX_BIT_SET (0x3f) // 0b00111111

//#define DEBUG_LEDS
#ifdef DEBUG_LEDS
#define DDR_LED DDRD
#define PORT_LED PORTD
#define LED1 (1<<PD5)
#define LED2 (1<<PD6)
#endif // DEBUG_LEDS

void usart_midi_sendchar(unsigned char c){
  while (!(UCSRA & (1<<UDRE))){} /* warten bis Senden moeglich */
  UDR = c; /* sende Zeichen */
  //return 0;
}

void usart_midi_init(){
  // midi runs on 31250 bps
  // F_CPU is number in hz
  #define BAUDINT (F_CPU/16/31250UL - 1)
  UCSRB |= (1<<TXEN); // UART TX einschalten

  UBRRH = BAUDINT >> 8; 
  UBRRL = BAUDINT & 0xff; 
  //return 0;
}

uint8_t noteLookup(uint8_t row, uint8_t col){
  return 53 + (row*5)+col;
}

void sendMidiCommand(uint8_t command, uint8_t param1, uint8_t param2){
  static uint8_t prevCommand;
  if (prevCommand != command){ // skip status byte if its the same as before
    usart_midi_sendchar(command); 
    prevCommand = command;
  }
  if (0== (param1 & (1<<7))){ // non-params signaled by highest bit set
    usart_midi_sendchar(param1);
  }
  if (0== (param2 & (1<<7))){ // non-params signaled by highest bit set
    usart_midi_sendchar(param2);
  }
}


uint8_t checkRow(uint8_t row){
  // "activate" one row
  PORT_MATRIX_ROWS &=~ (1<<row); // set to low
  DDR_MATRIX_ROWS |= (1<<row); // to active low

  // at this point, some connected cols may go low
  _delay_us(500);
  uint8_t nowIn = PIN_MATRIX_COLS; // get value of cols
  DDR_MATRIX_ROWS &=~ (1<<row); // afterwards set to low, again
  return (nowIn &= FIVE_BIT_SET); // filter by relevant values
}

uint8_t blackMask(uint8_t currentRow){
  /*
   * complete: wbwbwbw wbwbw wbwbwbw wbwbw w
   * complete: 0000011 11122 2223333 34444 4
   * row 0: wbwbw -> wbwbw
   * row 1: bwwbw -> wbwwb
   * row 2: bwwbw -> wbwwb
   * row 3: bwbww -> wwbwb
   * row 4: bwbww -> wwbwb
   * needs to be given backward
   *
   * let white be 0 and black be 1
   */
  switch(currentRow){
    case 0: return 0x0A; // 0b00001010
    case 1:
    case 2: return 0x09; // 0b00010010 -> 0b00001001
    case 3:
    case 4: return 0x05; // 0b00010100 -> 0b00000101
  } // switch
  return 0x00; // error case
} // blackMask

uint8_t findHighestWhite(uint8_t currentIn[5]){
  int8_t currentRow;
  int8_t currentKey = 14; // 15 white keys
  for (
    currentRow = 4;
    currentRow >= 0;
    currentRow--
  )
  {
    uint8_t currentMask = blackMask(currentRow);

    int8_t currentCol;
    for (
      currentCol = 4;
      currentCol >= 0;
      currentCol--
    )
    {
      uint8_t currentBitFilter = (1<<currentCol);
      if (0 != (currentMask & currentBitFilter)){ // not white key
        continue;
      }
      // currentMask is set
      if (0 == (currentIn[currentRow] & currentBitFilter)){ // key pressed
        return currentKey;
      }else{ // key not pressed
        currentKey--;
        continue;
      }
    } // iterate filter for this row
  } // for all rows
  // if we reach here, no white key is pressed
  return 0xff;
}
uint8_t findHighestBlack(uint8_t currentIn[5]){
  int8_t currentRow;
  int8_t currentKey = 9; // 10 white keys
  for (
    currentRow = 4;
    currentRow >= 0;
    currentRow--
    )
  {
    uint8_t currentMask = blackMask(currentRow);
    int8_t currentCol;
    for (
      currentCol = 4;
      currentCol >= 0;
      currentCol--
    )
    {
      uint8_t currentBitFilter = (1<<currentCol);
      if (0 == (currentMask & currentBitFilter)){ // not black key
        continue;
      }
      // currentMask is set
      if (0 == (currentIn[currentRow] & currentBitFilter)){ // key pressed
        return currentKey;
      }else{ // key not pressed
        currentKey--;
        continue;
      }
    } // for all cols
  } // for all rows
  // if we reach here, no white key is pressed
  return 0xff;
}

int main(void){
  usart_midi_init();

  { // init Matrix:
    /*
     * To prevent pins from having multiple signals
     * colliding with each other, all pins are default-high
     * but only via pullup-resistors (internal).
     *
     * so if we are multiplexing the rows,
     * the cols have their pullups activated.
     * The rows are output, but for most of the time,
     * they are set to input (to not drive anything) without
     * pullup-resistors.
     * 
     * The currently tested row is set to output with LO-level,
     * thus driving all cols low for which the key is pressed.
     * with multiple keys pressed at the same time, also other
     * row pins may get active-low, but don't care (used as inputs)
     */
    DDR_MATRIX_ROWS &=~ SIX_BIT_SET; // use as input
    DDR_MATRIX_COLS &=~ FIVE_BIT_SET; // use as input
    PORT_MATRIX_COLS |= FIVE_BIT_SET; // activate pullup
    #ifdef DEBUG_LEDS
      DDR_LED |= LED1 | LED2; // enable LEDs for debug
    #endif // DEBUG_LEDS
  }

  // row 6 is switches: 1<<0 is volume -> channel. 1<<1 is play/store

  uint8_t prevIn[5]; // previous value for all 5 rows (later 6?)
  prevIn[0] = FIVE_BIT_SET;
  prevIn[1] = FIVE_BIT_SET;
  prevIn[2] = FIVE_BIT_SET;
  prevIn[3] = FIVE_BIT_SET;
  prevIn[4] = FIVE_BIT_SET;
  uint8_t oldProgram[2]; // previous value for both channels
  oldProgram[0]=0;
  oldProgram[1]=0;

  while(1){
    uint8_t nowIn[5];
    { // get information for all
      uint8_t currentRow;
      for (
        currentRow = 0;
        currentRow < 5;
        currentRow++
      )
      {
        nowIn[currentRow] = checkRow(currentRow);
      }
    } // fetched information
    uint8_t switches = checkRow(5);
    uint8_t channel=0;
    if (0== (switches & (1<<0))){ // switch is up = max = higher Channel
      channel=1;
    }
    if (0==(switches&(1<<1))){ // switch is up -> play
      #ifdef DEBUG_LEDS
        PORT_LED &=~ LED1;
      #endif // DEBUG_LEDS
      uint8_t rowIterator;
      for (
        rowIterator = 0;
        rowIterator < 5;
        rowIterator++
      )
      {
        uint8_t col_iterator;
        uint8_t currentMask = (1<<0);
        for (
          col_iterator = 0;
          col_iterator < 5;
          col_iterator++, currentMask = currentMask << 1 // mask to next col
        )
        {
          uint8_t prevNote = prevIn[rowIterator] & currentMask;
          if ((nowIn[rowIterator] & currentMask) != (prevNote)){ // change on this col
            uint8_t playedNote = noteLookup(rowIterator,col_iterator);
            if (0!=prevNote){ // key was previously not press, so send a press
            #ifdef DEBUG_LEDS
              PORT_LED |= LED2;
            #endif // DEBUG_LEDS
            sendMidiCommand(
              0x90 | channel, // note down on channel
              playedNote, 
              0x7F // maximum velocity (first bit 0 for data bytes)
            );
          }else{ // note previously was pressed, send an unpress
            #ifdef DEBUG_LEDS
              PORT_LED &=~ LED2;
            #endif // DEBUG_LEDS
            sendMidiCommand(
              0x80 | channel, // note up on channel
              playedNote, 
              0x7F
              ); // maximum velocity (first bit 0 for data bytes)

            } // pressed or unpressed?
          } // change on col
 
        } // for all cols
        prevIn[rowIterator] = nowIn[rowIterator];
      } // for all rows
    } // play mode
    else{ // store mode
      #ifdef DEBUG_LEDS
        PORT_LED |= LED1;
      #endif // DEBUG_LEDS
      uint8_t highestWhite=findHighestWhite(nowIn);
      uint8_t highestBlack=findHighestBlack(nowIn);
      if (
        (0xff== highestWhite) || // no white key pressed
        (0xff== highestBlack) // no black key pressed
        )
      {
        continue; // main loop, nothing to do
      }
      uint8_t newProgram = 10*highestWhite + highestBlack;
      if (newProgram > 127){ // no valid instrument
        continue; // back to main loop
      }
      if (newProgram == oldProgram[channel]){ // same as old
        continue;
      }
      #ifdef DEBUG_LEDS
        PORT_LED |= LED2;
      #endif // DEBUG_LEDS
      // send program change
      sendMidiCommand(
        0xC0 | channel, // program change
        newProgram, 
        0xFF // no data
        );
      oldProgram[channel]=newProgram;
    } // store mode
  } // continue main loop
} // main (never terminated)

Once the software worked on the eval-board, the wires were soldered to the final board – which fitted nicely behind the non-existing-speaker. Also the Midi-plug was put into the correct place.

hni_0029

Of course, the chip desires power. I thought about using the old battery compartment at some time in the future but started by simply connecting the power wires of an old USB cable.hni_0030

Final verdict

The Midi-port almost looks like it always belonged there and apart from the USB-wiring issue, this could almost seem like professional audio equipment. Okay.. it doesn’t.

hni_0031

I later replaced the power input with small banana plugs (which then have their counterpart on a USB cable – this is just such an easy way of getting P5V).

It still is not good equipment: It still looks like a cheap kid’s toy. The keys are much too small for adult hands. There is no velocity control (pressing keys only slightly to control sound creation). Some keys almost always press other keys, too.

But the keyboard works. It transmits Midi-signals and by mapping the channels to a software synth (I’m using Midi-Ox), it indirectly creates music that would not have been possible with the prediously built-in-chip.

This project shows that midification is not too complicated and may be used on other keyboards or instruments that may even be worth converting into a Midi-input device.

Midi and the AVR

This post might seem a bit dated. According to some timestamps, I prepared it in 2011.

Warriors of Rock and Midi

I like music. I like rhythm. I like rhythm games. So even if my collection started with some PS2-guitars, it was only a matter of time until the temptation was too much and I bought the big guns / drums. It was time for the “Warriors of Rock”!

HNI_0088

Did I say “Warriors of Rock”? Of course, I meant “Band Hero”. No that’s not right, either. As it turns out, some of these sets are identical and only differ in the included game.

When unpacking this set, I was a little surprised to find a port labelled “MIDI IN” on the drum controller.

HNI_0094

More interesting, however, was the port on the other side. It was labelled “MIDI OUT”. HNI_0095

This made me think: “If I can connect this drums to my PC (or some other synthesizer), I can make ‘real noise’ with them. If they are true MIDI devices, they might be useful for more than playing games.” – as it turns out, I’m really bad with coordinating hands and feet when playing drums.

Unfortunately, I couldn’t find a lot of information about these ports and how to use them. On some webpages, people explain that you can connect a “real” drumpad to the Guitar Hero drums. “Real” drummers might have better equipment and just laugh about the “toy”. I guess, if you are used to playing real drums (MIDI or not), this game-controller set might just feel too bad to play on.

Some people explained how to connect the Wiimote (or PS3 or Xbox360)-controller to your PC and then convert the gamecontroller-data back to a usable format. This seemed like an annoying roundabout way for me – I wanted to experiment with pure MIDI.

Also some pages on the net stated that the controller only has MIDI-IN. I wanted to know whether the “MIDI OUT”-port really is “out” or if it’s just been mislabeled. So I opened the controller box to find out which lines from the ports are connected:

HNI_0096

First thing to notice was a larger IC on the MIDI-IN-side: the PC900V. As I read some technical deatils about MIDI, I knew that such an opto-isolator is required (according to MIDI standard) on the MIDI-In-Ports (to isolate signals and prevent humming). Another pretty clue was that PIN2 (center; GND) was not connected to anything: It should be disconnected on MIDI-in-side.

HNI_0097

The MIDI-Out-side had no such IC. Pin2 is connected to other parts on the board (even the Wiimode-I2C-connector) – so it is pretty reasonable to assume that it is GND and this really is a MIDI-out-port.

So it should suffice to take a MIDI-cable and connect it to the MIDI-IN-port on your PC, right?

Unfortunately, most PCs don’t have a MIDI-In-port. My main PC didn’t and I couldn’t get the Yamaha C1 to work. Of course, professional musicians will simply add a special card to their system to get MIDI-In. Once you arrive in the USB-era, there are cheap USB-MIDI-cables (or not-so-cheap-ones, if you prefer less latency) but I remembered that most sound cards (added or on-board) have a classic 15-pin-gameport and some pins on these can be used for MIDI.

AVR and (GamePort)-Midi

I still had such a port on my PC and wanted to try. Midi-to-gameport-adapter should be simple to build. However, I didn’t want to attach my beloved GuitarHero-drumkit-controllerbox to my PC in the wrong way and trash any of those two. So I decided to look into building my own Midi-device with an AVR AtMega microcontroller.

HNI_0098

On the right-hand-side is a Pollin-AVR-AtMega-evaluation-board. It is useful for testing small programs, features some buttons and LEDs and a way to connect an old IDE ribbon cable to access GPIO pins. You might compare this to typical Arduino-boards.

On the left-hand-side is a gameport-breakout-box. Only two pins are connected: GND is Pin4, Midi-In is Pin15 and it is connected to USART-TxD on the AVR. Midi simply is serial data. So the source code mainly tests whether the button is pressed or released (by comparing with previous value) and then sending chars to the serial port:

#include <avr/io.h>
#include 

void usart_midi_sendchar(unsigned char c){
  while (!(UCSRA & (1<<UDRE))){} /* warten bis Senden moeglich */
  UDR = c; /* sende Zeichen */
}


void usart_midi_init(){
  // midi runs on 31250 bps
  // F_CPU is number in hz
  #define BAUDINT (F_CPU/16/31250UL - 1)
  UCSRB |= (1<<TXEN); // UART TX einschalten   UBRRH = BAUDINT >> 8; 
  UBRRL = BAUDINT & 0xff; 
}

int main(void){
  usart_midi_init();
  DDRD |= (1<<PD5) | (1<<PD6) | (1<<PD7); // leds to output
  // DDRD &=~ (1<<PD2) | (1<<PD3) | (1<<PD4); // Buttons to input
  uint8_t prevIn = 0;
  uint8_t channel = 0; // between 0 and 15
  while(1){
    uint8_t nowIn = PIND;
    if (
      (nowIn & (1<<PD2)) && // button 1 pressed
      !(prevIn & (1<<PD2)) // previously not pressed
      )
    {
      usart_midi_sendchar(0x90 | channel); // note down on channel
      usart_midi_sendchar(0x10); // pressed key 16
      usart_midi_sendchar(0x7F); // maximum velocity (first bit 0 for data bytes)
      PORTD |= (1<< PD5); // enable LED
    }

    if (
      !(nowIn & (1<<PD2)) && // button 1 not pressed
      (prevIn & (1<<PD2)) // previously pressed
      )
    {
      usart_midi_sendchar(0x80 | channel); // note up on channel
      usart_midi_sendchar(0x10); // key 16
      usart_midi_sendchar(0x7F); // maximum velocity (first bit 0 for data bytes)
      PORTD &=~ (1<< PD5); // disable LED
    }
    prevIn = nowIn;
  }
}

Connecting this directly to the Gameport is not recommended. I ignored some safety warnings and just hoped for it to work – and it did: Via Midi-Ox I could look at the data and could even route it to the software synthesizer: I built my first own Midi-keyboard – although it only had a single key and always hit with full velocity but the main protocol stuff worked!

If course, if I want to to “real” MIDI, I have to comply with the standards a little more. To me, this means supplying the outout the correct way (with de-coupling) on the correct plug (DIN-plug).

Midi with the MOTU Pocket Express

Fortunately, at about that time, my MOTU Pocket Express arrived. This is an option I didn’t list before: It has midi-connectors and connects to the PC via the parallel port. It’s also nice for seeing blinking lights on MIDI transmission and for splitting one midi input to two outputs.

It also already was old and deprecated when I bought it. I had some trouble getting it to work. First: I couldn’t find real information about the required polarity on the power connector – GND-on-pin or voltage-on-pin? As it turns out (I opened it), It just doesn’t matter (there is the correct gate/bridge in it) and it might even be possible to run it with alternate current.

Afterwards, it was a bit problematic finding drivers. Older hardware tends not to have drivers for modern operating systems anymore and even the drivers for old systems seem to mostly have disappeared. I found one for Win98 which – sometimes – worked without crashing and one for WinXP which just won’t support input. Still, it has some LEDs so I can watchen the Blinkenlichter to the music and on Win98 I can watch the MIDI-telegrams coming in, correctly.

Throwback to the Guitar Hero drums: I could see them sending data! But only if a Wiimote was connected (makes sense for power) and if the Wiimote had a connection to my Wii. This was a “less-than-optimal” situation. At some point in the future, I want to try a non-Wiimote-power-supply.

AVR and MIDI-out on correct connector

Fortunately, at that point the project had moved a bit away from the Guitar-Hero-set. I was hooked on Midi and had a way to look at Midi-data provided on a real Midi-connector. So the next test was connecting my AVR to the official connector with recommended de-coupling.

HNI_0117

This time, the data from Atmel TxD goes through a NOT-Gatter twice (I used 74LS00), then a resistor of 220 Ohm and then to Pin 5 of the MIDI port. P5V is connected to Pin4 with abother 200 Ohm – this setup is almost directly lifted from the MIDI specifications.

I connected the breakout-box to the MOTU-Pocket-Express (in bypass mode) and it shows traffic when I press the key and send data. When connected to a PC (yes, still Win98), the MOTU reports MIDI-signals as well. Again, by routing the messages to WaveTableSynth, I can hear the created note. It’s is much too low (Note 10) to create a good noise, but it works: I upgraded my professional single-key-one-note-full-velocity-keyboard to standard MIDI connector.

AVR and Midi-in via gameport

Next, I wanted the AVR to receive MIDI information. Again, I’m starting with the direct transmission (without optocouple). Midi-Out (TxD) on gameport is Pin12. program does nothing else but wait for USART-data and print it.

It didn’t work. Maybe I made a mistake; maybe it’s not supposed to be that easy. I already bought some opcocouples so I kind of stopped caring how to connect directly to the gameport. At that time I thought about building one of those Gameport-MIDI-cables but I never did.

AVR and Midi-in via optocoupler

Regarding the optocoupler (you can see one in the previous picture): PC817 didn’t work. It seems like quite some people have problems with this one as it just is too slow, distorts the data too much or something. Once I switched to the SFH601, the “default” curcuit worked well:

  • 220 Ohm on the LED side, protected with a diode;
  • 47kOhm as pullup on the receiver side,
  • Emitter Pin of the Phototransistor connected to GND
  • Collector to GND via 100kOhm

I sent some Midi-signals via Midi-Ox and they are shown on the LCD I connected. Debut output via RS232 would be difficult as the USART has to run on 31250 BAUD.

Migration to nicer board

Until now, I did all this on an experimentation board (“breadboard”?) but as the circuits worked rather well, I put them on their own board. It sill is experimentation but I don’t have to worry about having the IC in the wrong orientation (again). Plus: My main breadboard is free for other projects.

HNI_0118

Summary and future

So I “learned the ropes” for Midi in general and on how to use Midi with an AVR. So it was time for a “real project”. I thought about building a simple synthesizer (MIDI in plus using the AVR timers for square wave generation -> chiptune) but that would have meant learning much more about music with the AVR.

Instead I went for midification. But this is a story for another day/post.

Hama Sonic Mobil 183

For my RFID-player-project (put RFID-tagged CDs or toys onto reader to start predefined audiobooks; more about this may be coming), I needed some cheap speakers – powered by P5V (USB) and sourced via 3.5mm plug. Fortunately, many PC users have a similar usecase, so such speakers are available. I ordered some via Amazon but then got impatient and used some quick buy (local Saturn) instead.
The speakers that I didn’t yet use, are “Hama Sonic Mobil 183”. I doubt that they will be used in the next Rfid-player-iteration as they are too roundish in their current forme.

So I decided to take them apart and test whether they would work in another case. This is the teardown.

HNI_0080

Here they are while assembled. The volume control is not on one of the speakers but has it’s own component.
I didn’t find any screws on the outside. So my first instinct was to scrape off the rubbery foot – screws like to hide beneath those.

HNI_0081

But I didn’t find any screws there. The next (and rather only other) possible point of attack was the front and indeed it popped off rather easily.

HNI_0082

That revealed the four screws. You might not see this in the photo but one of the screws looks rather round. It came that way – I didn’t expect much quality for my money anyway (to be fair: the sound is okay).

HNI_0083

Unfortunately, none of the real magic is found behind these screws: The speaker is directly connected to the outside. The cable has a small knot which is hot-glued into place (pull protection).

This simplicity is not even bad news: It means I can screw the speaker into whichever case I like and do not have to worry about the electronics, there.

Still, for the sake of completeness, let’s take a look into the volume control (which should include any amplifier as well):

HNI_0085

Again, there are no exposed screws but there neither is any glued component. Using a simple opening tool, the board is revealed and even nicely labeled on the input side (5V+, GND, AGND, L, R – no more questions). Output labels are missing.

So although I do not like the roundish case, the speakers might still be useful.

And I freely admit that this blog post was nothing special and I mainly wanted to unfreeze technologies and procedures.

Yamaha C1 – the Kraftwerk-computer

Yamaha C1 – a beautiful piece of hardware and a nightmare

“Dear people of the future: Here’s what we found out so far”

The computer itself

Some time ago, I aquired a Yamaha C1 “Music Computer”. It seemed to be a quite beautiful piece of hardware.

YamahaC1_004

YamahaC1_005

I used to say that it has a dozen of MIDI-Ports, but I was wrong. It only has eleven.

YamahaC1_003

At first, one might ask who might ever need eleven MIDI ports. If you’re not familiar with MDI, you might even wondert who might ever need one. It makes sense for musicians: If you have several MIDI instruments and synthesizers, you might want a port for each of them. This is why the computer is called “Music Computer”.

YamahaC1_001

YamahaC1_002

It can really help musicians to record their music, play them back, use a sequencer… Fun thing is: With only an 80286 processor and less than 1.5MB of RAM, you wouldn’t expect it to be powerful enough for music. I believe it is not powerful enough to produce music, but it’s more than capable of handling the signals. If this seems like a contradiction to you, you might want to read up on MIDI.

But MIDI signals are not only user for playing music. They can handle all kinds of other signals as well. The german music group “Kraftwerk” used this computer to control the robots they had on stage. Yes; those weren’t people in simple costumes (like the ones we used in school plays when we were young), those were actual robots, reacting on signals by moving their motors.

Note that I didn’t say “used one of there”. I said “used this computer”. When the hard disc still was working, I was able to copy sequencer and some of the movement data.

As you might have guessed, it doesn’t work any more. Still I’d have loved to use this computer for anything (especially once I learned more about MIDI) and wanted to repair it. That’s when I found the Yamaha C1 to be a complete nightmare.

Opening Up

Opening it up wasn’t too hard. Of course, I needed to keep track of the different screws. The upper part of the computer (keyboard and display) was connected with only a single plug.

YamahaC1_006

The floppy disc had the standard 34-pin-connector (or so it seemed at first), but then the hard disc turned out to be quite a surprise: It’s connector has 26 pins. There is no Molex power plug. The one in the picture is for the floppy drive.

YamahaC1_012

YamahaC1_013

At the point, regular PATA could be rules out. Still I hoped that this might be regular IDE or even SCSI with just a strange pinout. After I found the controller card, the strongest guess was MFN – well, not my guess but that of people who know more about this stuff than I do. This was also fueled by googling one of the chips and finding a post from someone trying MFN.

YamahaC1_015

Another strange thing about this controller card was it’s connection to the main board. It is no standard ISA slot – our strongest guess is that it’s ISA on a pin connector – together with power.

YamahaC1_018

At that point, I started giving up on the idea of changing the HD. The other guys suggesting finding out the pinout of the connector and then building a converter to regular ISA – and then connecting a regular IDE HD. Or I could solder my own ISA-IDE-card for those connector pins. All of this seemed beyond my capabilities so I gave up on that idea.

YamahaC1_009

By the way: The BIOS doesn’t allow setting cylinder count HD heads or so – and don’t even think about “auto-detection”. It only supports the original types whose information was hard-coded into the BIOS.A long time ago, there were just 46 “standards” for cylinder count, heads, etc. Later BIOS had “Type 47” which was “user defined” (so you could at least copy the data from the disc sticker). Even more modern BIOS allowed you to auto-detect the information from the HD and insert the data into the Type-47-fields. Nowadays, of course, auto-detection is the most common way.

Anecdote: A colleague once reported to me that he ran into that problem when replacing/updating a HD and he solved it by reading the BIOS from the EPROM; patching the BIOS and then flashing it to an EEPROM. This obviously requires some EPROM reading and flashing hardware. For the Yamaha C1 this could become a possible path once other HDs can be connected.

According to some old manual, “with hard disc” was only on of the flavours you could get the Yamaha C1 with. Another was “two floppies”. Judging from the BIOS, the 20MB-disc drive is “Type 2”.

YamahaC1_007

YamahaC1_008

Plan “Revive from Disc”

After the “replace HD”-idea was pushed back, I thought about booting the computer from floppy. Yes, dear kids. A long time ago, computers could be booted from floppy disc and didn’t need hard discs, CDs, DVDs or USB-Storage-sticks. A long time ago, computers didn’t even have this luxury and everything was done on discs. And even that was a gratitious update to the times before (google “punch card” if you dare).

I planned on emulating the hard disk via interlnk and a parallel laplink-cable. For the younger ones: “laplink” is a tool for data transfer via the parallel port. Most often, the printer was connected to that parallel port (long before everything was USB). You connected two computers via a special cable (crossover) and then could copy files much faster as if you’d have to write and read them from disk every time.

Interlnk/intersrv is a software-dua included in MS Dos 6.22 (or so) which allows to setup one PC as server and then pretend on the client-PC that the data from the other side comes from a hard disk. It even get’s a device letter.

From what I’ve been told, Dos6.22 should be able to boot even on older hardware, so I tried a DOS6.22 boot disk. My first try failed as I forgot that the Yamaha has 720KB disk drives instead of 1.44MB ones (don’t get me started on 2.88MBB). Still, even when formatting a DD-Disc as bootdisc, the Yamaha refused to boot from it.

Okay, I thought to myself, The computer is old. Maybe the floppy drive is broken, too. I tried replacing it with functional one. Thankfully the BIOS supported 1.44MB disk drives.

At the point, I found another interesting (disturbing) thing: The floppy cable was wrong. Normally, when PIN1 (the marked wire) is left, the connector has the budge on the top. The cable in the Yamaha has the regular budge on the motherboard-side but not at the floppy side. Still, you won’t realize it as the floppy itself has the same orientation. Yet, as soon as you try to connect a regular floppy or try to connect the Yamaha-floppy with a regular cable, you recognize that something is wrong. The floppy light is on, permanently.

So after some careful pushing, I was able to connect this floppy to another computer but it didn’t work. It didn’t work the same way as a regular floppy drive didn’t work at the Yamaha. Later on, I found out the the FDD-cable has another strange twist:

You might know that it is posible to connect two floppy disk drives to a standard FDD-Bus – but how does the computer know which one is a: and which one is b:? Mordern SATA hard discs each have their own cable, on PATA hard discs, you have “Master/Slave”-jumpers (or even “slave present” on even older ones), but floppy disk drives have no such jumpers.

The solution is as strange as it is simple: At some point in the FDD cable, seven wires are crossed. A drive after this cross will be a:, a drive before this cross will be b:

The cable in the Yamaha computer has two wires crossed. So it seems incompatible with everything except itself. I guess that the Yamaha floppy even depends on this strange cable so it’s no wonder it didn’t work on another cable.

Still, it didn’t even work as b: (uncrossed part of the cable) and it even prevented a regular a:-drive from working when it was connected.

The Yamaha reported “No Boot device available”. It didn’t report errors with the disk drive (except when I selected it for the wrong type or primary/secondary). It seemed like the computer really insisted on booting from hard disk – which I considered strange as it should also be able to work with two disk drived. Did it somehow know that it was the HD version and wanted to boot only from HD? Wouldn’t that make it impossible to reformat the HD?

Everything was strange about this computer: it’s BIOS, it’s hard disc controller, it’s floppy disk. Ant with a defect hard disk and a non-booting floppy drive and the impossibility to connect a regular floppy my chances of ever working with the computer looked pretty slim.

YamahaC1_010

YamahaC1_011

This is the point when I started this text. This is the point when I believed everything to be lost and just wanted to record my experience and share the photos I made.

YamahaC1_014

YamahaC1_016

YamahaC1_017

Fortunately, Skern insisted on listening to the hard disk starting up – so I reconnected the controller card and hard disc and switched on the computer. BIOS reported hard drive fail, but no drive seek error for the floppy. Skern listened to the hard disc and said that it sounded rather okay.

And suddenly the computer showed the “DOS 6.22”-test and a prompt. It booted! It only needed the defect hard disk to be connected and set in BIOS and it decided to check the floppy for bootable medium, again.

At the moment, our strongest guess is that the hard disc controller is more than this: It also includes the floppy controller. Without it, the BIOS somehow recognizes the floppy drive but cannot access it as a bootable medium.

This is very “un-intiutive” as the floppy is not connected to the controller card – only the hard disk is (inclusing it’s power supply). So wires for the floppy go through the motherboard-connector into the controller card – and out again.

The next step is expanding the “plain” boot disk (only including command.com) to something usable (fdisk, format) and checking whether the hard disc really is lost. Skern said that chances aren’t bad that it will work again. Testing the computer with a floppy might also yield interesting results. Booting without HD but with controller could prove the floppy-controller-theory. However, it wasn’t ruled out that the computer needs a hard disk drive (even if it’s defect) to accept floppy boots.

YamahaC1_019

After later experiments (post 2011-12-14)

The computer needs the controller card but doesn’t need the hard disk. I haven’t tried connecting a standard 1.44MB drive as b: – I’d need another power connector or would have to split the old one. I also doubt it would work. It wasn’t recognized as a: with the Yamaha cable (the same cable that didn’t make the Yamaha floppy available to a regular PC). I also didn’t try the Yamaha controller with a standard cable and a standard floppy. Once the Yamaha floppy successfully booted from disk, I decided I’ve had the computer open long enough and built it back together again.

Surprises:

Also, the hard disk drive surprised me for a moment: I had no floppy disk inserted and the computer still decided to boot up. For a moment I was able to access the hard disk. It was just for a moment – once I tried to access a database (finances? mails?), it was dead again. It managed to play alive several times afterwards (seems like the cold atmosphere really helps) but never for long.

YamahaC1_021

YamahaC1_020

Back to the original plan

As planned, I connected the Yamaha to another PC via parallel laplink-cable and one I started intersvr there, I could access the host disk drive (I booted from floppy and had no HD at the moment). Running the sequencer tools from floppy proved very unsuccessul – many read errors (although the disk was fine). Still, I managed to get miditest to work and connected the MIDI-ports with a midi cable as requested. After both MIDI-Ins and most of the Outs tested successfully, I decided that no problems should be expected, there.

To fix the problem with read errors, I connected an HD to the “regular” PC (host/server), formatted it with DOS, copied intersvr and the spg sequencer and from then on booted from HD (okay, I forgot one fdisk /MBR to get rid of an old LILA, but this was just two more boots).

I booted the Yamaha with interlnk, again, and served the software with the regular PC. Finally, I could start the sequencer (and MIDI-driver) on the Yamaha.

Unfortunately, I then was hopelessly lost in the software. I hoped that the Yamaha might at least give some beeps over the internal speaker. I hoped to get some response by connecting a MIDI-keyboard to an IN-port and pressing “record” in the software but I had to face that this software would need some more reading.

Fortunately, the manual for it can be downloaded from the internet. SPG is short for “Sequencer Plus Gold” which was programmed by a company named Voyetra. I found the manual on the homepage of turtlebeach.

Unfortunately, that was about the time that the universe deciding hating me. The Yamaha already had some freezed and I didn’t think much about it. But when I loaded one of the song-files (robopop.sng), the graphics screwed up. After a reset I only got a blank screen with two lines. Other reboots resulted in a completely blank screen and also the status LEDs indicate that there are larger problems than just the display. I guess that the graphics chips finally decided to go byebye.

Giving up, finally

So after I took the computer apart; tried a lot of things about the floppy; learned about the controller and even got suggestions to convert a regular controller; after I finally get a DOS to boot and established the connection to another PC in orhder to access the tools and data; just as I got the software to work with the hardware and only needed to learn how to really use the software, the Yamaha dies on my.

I may be wrong – I was wrong about the hard disk and it shows some signs of life. I may try to start up the Yamaha, again, and perhaps it will live, again, but for the time being, I’d like to move to other projects.