20 May 2010, 21:22 | #1 |
Posts: n/a
|
Help needed with music player
Hello everybody!
I'm a retro gaming and demoscene enthusiast (I say 'retro' because I was about one year old when it happened!), with particular interest in module formats and some experience in decoding esoteric ones. It is this latter occupation which I must now pester you lot about. I've never actually owned or used an Amiga - all my past experience and programming knowledge is on RISC OS (Acorn Archimedes as-was) and ARM assembler, which was why I found it rather daunting when I took on the project of decoding a module format based on a disassembly of the original 68000 player machine code. The guilty party in this case is the Jason Page format, as used in Fire and Ice, Uridium 2, and other games. Try as I might, I couldn't find any documentation at all (when I've solved this last conundrum, I hope to write some of my own), and so I've been writing a converter based first on the unbelievably bug-ridden Archimedes conversion of Fire and Ice, and latterly on the disassembly of the original player available from AMP. It is with this that I have become confused. I posted on the AMP forums about my problem, and was recommended to come here and ask where there were likely to be more 68000 programmers reading. The problem I have is with this piece of code which is called for a particular instrument command: Code:
MOVE.L (A3)+,D0 MOVE.L D0,(_SampleLoopLen,A2) BEQ.B lbC000C3A LSR.W #1,D0 MOVE.W D0,(_SampleLength,A2) lbC000C3A RTS There is another instrument command which does the same thing, but without checking if the value read is 0. These two commands combined mean that the only two values _SampleLoopLen can take are either 0, or that of _SampleLength * 2. All of which makes the code which actually programs the Paula chip rather odd: Code:
TST.L (_SampleLoopLen,A2) BEQ.B lbC000A98 ; silence channel MOVEQ #0,D0 MOVE.W (_SampleLength,A2),D0 ADD.L D0,D0 MOVE.L (_SampleLoopAddress,A2),D1 ADD.L D0,D1 MOVE.L (_SampleLoopLen,A2),D0 SUB.L D0,D1 MOVE.L D1,(_HSampleStartAddr,A4) MOVE.W (_SampleLength,A2),(_HSampleLength,A4) Hence the only possible value the sample start address can take is that of _SampleLoopAddress! I welcome any corrections to the above diatribe, and I hope somebody can point out where I've gone wrong. |
20 May 2010, 22:06 | #2 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,625
|
Jason did some cool work on Paradroid 90 and the subsequent games, always liked how the audio turned out.
Maybe you're the first to rip his player, but it might be that there's someone out there who has a working player source. As for helping, I'll check back when I'm less tired. Sample lengths/loop lengths are usually supplied as half the byte size, as the audio hardware works that way. Loop lengths (which is the same as sample lengths, as audio is always played looped) is always given in words, not bytes. DMA is 16-bit, so it reads a word on each access and then plays two sample-bytes, reads another word, and so on. Here's another Acorn fan btw, welcome and kudos for putting your first post in the right subforum! Hehe. |
21 May 2010, 15:27 | #3 | |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,510
|
Quote:
Are you sure this is the only location where the program writes to HSampleStartAddr? I could imagine the following: The sample's base address is written to HSampleStartAddr and HSampleLength is set to the full length in words from SampleLength. Then audio DMA for the channel is started. As the next step some effects will be applied (while DMA is running) and SampleLoopLen is rewritten, which also makes SampleLength smaller than its initial value (because the loop takes place with a range at the end of the sample). Now the audio registers HSampleStartAddr and HSampleLength are written again with the new values, defining the loop. Paula works that way that it will reload the HSampleStartAddr and HSampleLength into an internal latch whenever the DMA finishes (end of sample is reached). The sample is automatically restarted playing the loop range. |
|
22 May 2010, 16:24 | #4 |
Posts: n/a
|
Oh bother.
That's more or less what I was expecting it to be doing as well, but I can't tell how it's happening! Before I provide more complicated examples, here's a brief grounding on how Jason Page instrument definitions work: A sample number is specified with the note as normal, except it points not to an instrument, but to a list of instructions which give all the details of the address of the instrument, its loops, vibrato, fades, etc. Data is read from this block every 50 Hz clock tick, stopping whenever a special instruction code of $12 is encountered, at which point it updates the current volume and pitch, and fills the hardware buffer. Here's an example from the sixth world of Fire and Ice: Code:
2 0 <- _SampleLoopAddress set to beginning of sample #0 3 22C8 <- _SampleLoopLen = $22C8, _SampleLength = $22C8/2 D 0 0 <- vibrato 13 6000 FFFF FFFF 30 <- fade 12 <- exit and update hardware buffers ------------- 10 <- no idea... (see below) D 3 3 <- another vibrato 4 1A00 <- _SampleLoopLen = $1A00, _SampleLength = $1A00/2 6 0 <- start infinite loop 12 <- exit and update hardware buffers ------------- 7 <- end infinite loop Command $10 executes a single instruction: Code:
ST (_KeyON,A2) One pattern I have noticed is that command $10 is always preceded by a command $12, which means that by the time _KeyON has been ST'd, the hardware buffers have already been updated once. I have a feeling this is important. Now, from the data above, you would assume that this produced a looping sample, $22C8 bytes long, with the repeat start at offset $8C8 and a length of &1A00. But, judging from what I understand of the code below, which is very little, what actually happens is that the entire $22C8 bytes gets played through once, and then it loops on the first $1A00. That can't be right, surely? Here's the complete unabridged hardware updating function: Code:
lbC0009FC ; Compare current volume to master volume, and clip if bigger MOVEQ #0,D1 MOVE.B (MasterVolumeB),D1 LSR.B #2,D1 MOVEQ #0,D0 MOVE.B (_Volume,A2),D0 LSR.B #2,D0 CMP.B D1,D0 BLE.B lbC000A12 MOVE.B D1,D0 lbC000A12 MOVE.W D0,(_HSampleVolume,A4) ORI.B #$10,(_HUpdateHardwareFlag,A4) ; The 'Update Hardware Flag' is not mentioned anywhere else ; in the file. I have a nasty feeling there is some code ; missing which translated this buffer into values read by ; the Paula chip. ; If _SampleLoopLen is 0, write blank data instead TST.L (_SampleLoopLen,A2) BEQ.B lbC000A98 ; D1 = _SampleLoopAddress + 2*_SampleLength - _SampleLoopLen MOVEQ #0,D0 MOVE.W (_SampleLength,A2),D0 ADD.L D0,D0 MOVE.L (_SampleLoopAddress,A2),D1 ADD.L D0,D1 MOVE.L (_SampleLoopLen,A2),D0 SUB.L D0,D1 ; Not a clue what this does... TST.W (_KeyON,A2) BNE.B lbC000A4C MOVE.L D1,(_HSampleStartAddr,A4) MOVE.W (_SampleLength,A2),(_HSampleLength,A4) ORI.B #2,(_HUpdateHardwareFlag,A4) lbC000A4C ; I don't know what these two values are at all, nor are they ; mentioned anywhere else. As above, I think there's code ; missing. The most likely explanation is that they indicate ; the new values to be written into the variables above. MOVE.L D1,($18,A4) MOVE.W (_SampleLength,A2),(_HSampleLoopLength,A4) ORI.B #4,(_HUpdateHardwareFlag,A4) ; Finally, write the period value. MOVE.W (_Pitch,A2),(_HSamplePitch,A4) ORI.B #8,(_HUpdateHardwareFlag,A4) RTS A synth chord from Uridium 2: Code:
2 4 ; _SampleLoopAddress = sample #4 3 A4E ; _SampleLoopLen = $A4E, _SampleLength = $A4E/2 13 B000 1001 FFFF 300 12 ------------- 10 4 800 ; _SampleLoopLen = $800, _SampleLength = $800/2 8 1C0 ; _SampleLoopAddress += $1C0 6 0 12 ------------- 7 This next one is especially interesting. Judging by experimentation, I believe the correct translation of the parameters is a repeat start of $600, and length of $420. The sample itself is $1BC8 bytes long, and is a sort of high 'plink' sound used in the middle of the Uridium 2 title music. Code:
2 8 ; _SampleLoopAddress = sample #8 3 68C ; _SampleLoopLen = $68C, _SampleLength = $68C/2 13 4000 FFFF FFFF 100 12 ; exit and update hardware buffers ------------- 10 8 600 ; _SampleLoopAddress += $600 4 420 ; _SampleLoopLen = $420, _SampleLength = $420/2 5 100 ; update hardware buffers, exit and wait 256 ticks ------------- 0 ; cut note tl;dr version: What does ST (_KeyON,A2) mean? The hardware buffers aren't mentioned anywhere except in the one place described here. _HSampleStartAddr never changes except when specified by command $8, therefore a loop is only possible at the start of the sample, not the end. I don't think this is correct, so what am I doing wrong? I bet _KeyON has something to do with it. |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
BZR Player - a new music player for Win | bLAZER | Retrogaming General Discussion | 1038 | 02 May 2024 18:15 |
Amiga music player on PC | moriez | Amiga scene | 38 | 07 September 2020 16:23 |
Music player with Batman | glr | Looking for a game name ? | 2 | 04 January 2012 14:02 |
Amiga 1200 Mod Player? Help STILL Needed ! | hallatie | Amiga scene | 4 | 08 April 2011 11:27 |
Best music player | quantum112 | support.Apps | 9 | 06 January 2010 09:59 |
|
|