I've had 90% of this lying around for a few months and decided to finally finish it.

Its main features are:
  • 4 square wave channels
  • 16-bit frequency control
  • 8-bit duty cycle control
  • L/R mask control
  • jumps inside the song data
  • support for arbitrary code execution to facilitate complex jump structures within the song
  • ~17 kHz effective sample rate (depends on CPU frequency)
  • ~68 Hz refresh rate (depends on CPU frequency)
  • 0cc delay when reading the next note
  • reading song data directly from the archive
  • the entire player is 496 bytes (EDIT: 512 bytes after debugging and a few nice features like pressing ON to interrupt playback)

Its cons are:
  • doesn't run on regular 83+
  • no noise channel
  • file format is pretty big at 6 bytes per note
  • channels are not separated inside the song data meaning you can't have one channel repeating a short bit and another channel doing a longer bit, although the arbitrary code execution it supports could help by generating song data on the fly
  • there is no GUI, right now you just store the name of the appvar you want to play into Ans


Here are a few previews of the sound:
1bit.wav (77 bytes of data) (recorded at 192 kHz samplerate)
lifecaps.mp3 (173 bytes of data) (resampled to 22050 Hz to get rid of aliasing artifacts that happened because I was recording it at 44100 Hz)

The binary data for the second one of these was generated by a script I made that takes care of the quirks of the format for you. This would make it possible to create longer songs (as long as they don't surpass the 32 KiB maximum filesize this thing has).

I plan to release this in a few weeks, probably. However, I also want to create a challenge for you all in reverse-engineering it, so I will probably not release the source code yet.

Here is the binary data of lifecaps.mp3, try to figure out the format! (shouldn't be too hard because I aligned it already)

Code:
00000000: 4602 80 03 0012      F.....
00000006: 0803 80 03 0024      .....$
0000000c: 8401 4c 03 0036      ..L..6
00000012: c200 4c 03 0036      ..L..6
00000018: d203 80 03 0048      .....H
0000001e: 8b04 80 03 0012      ......
00000024: dd02 80 03 0012      ......
0000002a: e901 4c 03 0036      ..L..6
00000030: f400 4c 03 0036      ..L..6
00000036: 8b04 80 03 0024      .....$
0000003c: b905 80 03 0012      ......
00000042: 1905 80 03 0012      ......
00000048: 4a04 80 03 0024      J....$
0000004e: 2502 4c 03 0036      %.L..6
00000054: 1201 4c 03 0036      ..L..6
0000005a: 6703 80 03 0024      g....$
00000060: 8d02 80 03 0012      ......
00000066: 2502 80 03 0012      %.....
0000006c: dd02 80 03 0024      .....$
00000072: 8d02 4c 03 0036      ..L..6
00000078: 4601 4c 03 0036      F.L..6
0000007e: 6703 80 03 0024      g....$
00000084: 4a04 80 03 0012      J.....
0000008a: dd02 80 03 006c      .....l
00000090: d203 80 03 006c      .....l
00000096: 6802 4c 03 006c      h.L..l
0000009c: 3401 4c 03 006c      4.L..l
000000a2: 0000 00 00 4100 0000 ....A...
000000aa: c397dd               ...


EDIT: For posterity, I already explained the format on the Discord channel #z80-ez80.

EDIT: I also already shared the program binary and source in chat. However, although the source is mostly correct, it is a slightly newer version (that is also broken by the way), because I overwrote it. It's mostly the same though, and combining a disassembly of the binary and the source I did include should be good enough.

EDIT: I recovered the original source and added more comments!
This is the song I'm currently working on: mimiga_village.mp3. (by the way both this and lifecaps.mp3 above are covers from the OST of the game Cave Story) The program size has also grown from 496 to 506 bytes (with no new features but fewer bugs), while the size for each channel's player has grown from 47 to 58 bytes, with a faster native jump and better (primarily less buggy) support for arbitrary code execution.

Around 35 seconds is a demonstration of a different duty cycle and of stereo sound. Measures 1-5 (seconds 1-12) are reused for measures 9-13 (seconds 18-29), which was achieved using the aforementioned arbitrary code execution. The fadeout at the end was added in post (originally it keeps repeating forever).

The fourth channel is completely unused during all of this, and I hope to use it for percussion by playing a low duty cycle, high pitched note with lots of aliasing artifacts. In the beginning, the 2nd and 3rd channels are usually playing the same note on a different rhythm, which makes it sound weird. I'm looking for solutions. Also, I didn't finish the 2nd channel yet, it ends around the 50-second mark.

Finally, this song's binary data was completely generated using my script (which keeps getting more and more features and fewer and fewer bugs). Here is a screenshot of the source file format:
Whoa, super cool, I love it! Why doesn't it run on a standard TI-83+?
That is really snazzy! Out of curiosity, and based on the sound quality, is it using pretty much 100% of the CPU, or is there time for the CPU to do other things (like for a game). If the sound is being timed by interrupts, I imagine that might leave time open for some graphics that allows gameplay at the same time.
CalebHansberry wrote:
Whoa, super cool, I love it! Why doesn't it run on a standard TI-83+?

It uses the 15 MHz mode (you can tell my script the exact frequency so it can generate the data with better tuning) and also a memory mapping only available on the 83+SE and above (port 05 and 27, though it would be possible to work around this).

Xeda112358 wrote:
That is really snazzy! Out of curiosity, and based on the sound quality, is it using pretty much 100% of the CPU, or is there time for the CPU to do other things (like for a game). If the sound is being timed by interrupts, I imagine that might leave time open for some graphics that allows gameplay at the same time.

It's a little complicated. I am using SP as a pointer into the song data (POP is by far the fastest way to read a word and increment the pointer). Except for that, the playing of the notes by itself only takes a little over half the CPU time (136 out of 216 clock cycles right now, per channel, although interrupt overhead (EXX, EI, resetting the timer...) would add quite a lot to that), but I idle on every loop to make sure the delay is always the same as when reading a new note. If I were to give up on this (it only reads a new note every 1/1000+ loops, after all), it could be made quite a bit faster. I might also make a lighter engine with fewer features or with duty cycle and L/R mask only available through arbitrary code execution, or with fewer channels (having 4 channels requires an actual sample rate of at least 60 kHz or so for it not to sound horrible, but the higher you get it the better it sounds, currently the actual sample rate is 69444 Hz and the effective rate is 17361 Hz, both at exactly 15 MHz, for me it was 18374 effective and 74296 actual). In any case, the reason it sounds so good is probably because of the 16-bit frequency precision. Most notes in the common range are less than one cent (that's 1/100 of a semitone) off (it only goes above 2 cents below the A#1, though this depends quite a bit on the CPU frequency you set (which was 16048000 for me), for example setting 15000000 makes that same A#1 be 0.29 cents off, while the F2 is 2.24 cents off). Also, the thing I call frequency really is the frequency, not the wavelength. This is what allows me to have a variable duty cycle, and decrementing a 16-bit counter and checking against zero would not take less time than my current approach anyway. An 8-bit counter would be much faster to decrement (because I don't need to waste another 8cc to check the Z flag), but that would make for horrible tuning.
First, let me say that this program is amazing. I actually plugged my HD6xx into my 84 and could totally hear the song. It was amazing! I'm definitely gonna try my hand at composition on this thing, as well as make an on-calc editor.

On the flip side, this seemed to brick my calculator. Even after a hard reset, the calculator seems to be running about 5% its normal speed. It's usable, but you have to hold down a button for several seconds every time you want to do something. Do you have any idea what's going on?
Sam wrote:
On the flip side, this seemed to brick my calculator. Even after a hard reset, the calculator seems to be running about 5% its normal speed. It's usable, but you have to hold down a button for several seconds every time you want to do something. Do you have any idea what's going on?


You need to remove the headphones before you exit the program (it even tells you about this). This resets the link port properly so that the OS doesn't get confused. If you didn't insert/remove the headphones when the program told you to, remove the headphones and run the hex code AFD300C9 (xor a \ out (0),a \ ret), which also resets the link port.
Off an on over the past few weeks I've been working on a Python script to convert a MIDI file into a readable format that works with fghsgh's plaintext to .bin converter. It's a really roundabout way to do it, but just as fghsgh was with the plaintext to .bin converter, I was optimizing for easy. Forget that you have to do .mid > .fghsbeep > .bin > .8xv, lol. Anyway, here's the script: https://pastebin.com/vDADiTvz
You'll need to install this Python MIDI library. Also, the program doesn't really work too well right now because I haven't taught it to differentiate between a note off and not changing a previous note off. If anyone wants to continue where I left off, feel free. It might not create something that will compile immediately with fghsgh's converter, but at least it will get the gist. I'll probably work on the rest of it later.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are GMT - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement