Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


ZeroByte last won the day on November 5

ZeroByte had the most liked content!


Recent Profile Visitors

1904 profile views

ZeroByte's Achievements

Rising Star

Rising Star (9/14)

One Year In Posting Machine Rare First Post Collaborator Rare Reacting Well

Recent Badges




Community Answers

  1. I think the biggest hurdle is the tool chain. Probably the thing to do would be to update the zsm2zfx tool to be able to read the current ZSM format as input, and then use Furnace as the platform, so at least you can create and export directly in ZSM (Deflemask wouldn't allow for very creative use of VERA PSG, as it has no such chip, and VERA doesn't exist in VGM standard)
  2. I've done a few different things over time.... For Flappy Bird, I would use Deflemask to get my YM patches the way I needed for the effect, and then export them as instruments, and convert them into my "YMP" (ym patch) format. Then I'd manually generate the sequence data in the source code. Rinse. Repeat. For things that are basically an algorithmic-style sound (pitch sweeps up and down, volume fades, etc) I would hammer in a quickie BASIC program to make stuff, and when I got it sounding the way I wanted, I'd mod the code to also print the registers+values as they were being written into VERA. This of course borks the timing, but I've already determined they were what I wanted.... then I'd use the emulator's -echo mode to copy/paste the results and then write them into source for use with my engine. Lastly, I've made a couple of effects as Deflemask "tunes" (using voice 0 of the YM2151) and exported them as VGM. I had a tool that would take this VGM and convert to ZSM (a previous ZSM standard that no longer exists). I have the core of a sound effect format for Zsound (ZFX) but it's only just a bare-bones playback routine that's available. There are not any supporting toolchain components for the SFX. Whenever I get back around to this side of the house, I'd like to make an on-system tool for SFX creation, using a dopesheet style UI where you draw lines that describe a value over time. (e.g. a line sloping up, tied to frequency would make a rising pitch sweep) If anyone would like to collaborate with me on the SFX side of Zsound, I'd be more than happy to oblige.
  3. They seem pretty comparable to the emulator using SD card.
  4. MACPTR is essentially a frontend for the DOS module's fat32.s functions. It does a lot under the hood, but the meat and potatoes occurs in the routine fat32_read: in fat32.s MACPTR calls file_read, which calls fat32_read fat32_read in turn calls other, even lower level functions to do the actual reading from SD, tracking block numbers, etc, but I've never been any further down the rabbit hole to tell you what those do - but they're all in fat32.s I would imagine.
  5. By default, it expects you to call it at 60hz, and it will resample time to 60hz automatically when you start a song. If the song's play rate in the header is 120hz, the player will tick the music twice per call to playmusic. So in other words, you do nothing, you call it once per frame, it converts the song speed automatically. There is a routine to set music speed (.XY = hz) - when you call this, it adjusts the tick rate to whatever you specified instead of what the song specifies. So let's say your 120hz tune is playing and you call setmusicspeed = 240. You continue calling playmusic once per frame, but now the song will tick 4 times per call, which means the music will now be 2x normal speed. And yes, you can ask Zsound what the normal speed is at any time using the get_music_speed API call. You can use the reply from this to then set_music_speed back to that value. What I was describing above is for cases where you don't want Zsound to automatically resample time for an assumed 60Hz call rate. The procedure is a workaround. If you set_music_speed = 60Hz, then the player will only advance the music by one tick per call. The player doesn't have any idea how fast you're actually calling it - so if you have a, say 700hz tick rate song, you can call playmusic at this rate and the music will play at normal speed. The API call I would present would be either a parameter on the initialization (enable/disable time scaling) or else have an API call that disables/enables time scaling. Essentially, set_music_speed(60) disables time scaling. When time scaling is disabled, you can ask what the tune's rate is (or just go read the header from memory if you prefer) and drive the player at that frequency yourself. The main reasons to do so would be if you had more timing-sensitive effects in the music. (e.g. if the Concerto tunes came out sounding wrong at 60hz, you could opt to drive the ZSM at 128hz directly which would eliminate such errors).
  6. By default, the Zsound player resamples time to 60hz regardless of the ZSM tick rate, but you can play back files at the native tick rate if you use a time source like VIA timer IRQs to drive the playback function. You'd need to either call set music speed = 60hz and then call the playback function at the actual speed in order to do this, or else call stepmusic directly on each tick (stepmusic doesn't preserve things like bank / VERA data port states, so plan accordingly if calling that). I've got an internal variable in the code that specifies whether the player should scale to 60hz or not - just no way to manipulate it in the API yet. Would this make more sense as an argument to the zsound init routine, or as an API call to enable/disable it? I'm thinking init() argument makes more sense, really....
  7. This is some fine work, @kliepatsch, and thanks for the shout-out on Calliope. After playing the song in Calliope, I see what you mean. It's neat how the software chooses random channels for stuff in a way that a human wouldn't - definitely makes an interesting show on the PSG LEDs. Whenever I get around to adding a "tap" feature to Zsound's ZSM player, I'll be able to make the FM lights do the same thing instead of just being static "channel used/unused" indicators.
  8. Actually, Flappy Bird specifies its own VRAM map so the official R39+ changes to screen memory didn't affect it. I did do some direct dips into the Kernal's BRAM vars (which is explicitly discouraged for exactly this reason) and I guess I should go fix this once and for all....
  9. wiatvsync() comes with cbm.h And yes, it's typically used as a quick and easy way to time software with the 60hz screen refresh, for instance some animation that should only update once per frame, your loop can have waitvsync() in it to ensure that it only executes once per 60hz frame. It's less useful for things like avoiding tearing because your code won't get to execute until after the VBLANK interrupt has finished which may or may not be after the VBLANK period is over (i.e. into visible raster time).
  10. Sprites only come in 4bpp and 8bpp color depths. Palette offset is essentially meaningless in 8bpp mode (although it does affect the colors, and I'm sure there's some clever schema in arranging the palette and sprite assets to get some kind of effect from it, but that's going into mad science / demoscene territory). The palette offset value is designed such that you should think of the master palette as being divided into 16 different 16-color palettes. Palette offset selects which of these 16 palettes a 4bpp asset uses. I.e. palette_offset = row, pixel value = column.
  11. My most recent retro collection purchase was the beat-em-up collection from Capcom. It's fun to pop that in with the kids and start trashing bozos. My most recent "HD remake" title was Secret of Mana II. It was interesting how they made it play a lot more like the action-RPG titles of today (like Xenoblade)
  12. My $0.02's worth - I understand about the intermediate 48px size, but I really can't honestly say one of the other sizes that should be discarded in favor of 48px. 8 and 16 - no way. Those are tile-sized aspects and there are far too many uses for such, and furthermore, there are far too many "little" things that would become bloated in VRAM if 8x8 were dropped as a sprite size, especially. I've already done many programs where I used free slots in the tilemap as sprite slots or else used letters/numbers from the tilemap as digits, e.g. the score counter in Flappy Bird.... 64 - useful for bosses / making panels for things like radar / HUD overlays / popup dialogs, etc. (for instance, in games like StarFox where a character's portrait pops up along with their dialog/voice clip, having a 64x64 sprite for this is perfect) 32 is probably the only one I'd say is "up for discussion" as an atomic size that could be considered expendable in favor of 48. Both are "middle" sizes, and maybe 40 or 48 offer more utility than 32, but the extremes are both quite valuable and dare I say, indispensable?
  13. So you're not animating by having all frames in VRAM and updating indexes, but by giving each object a VRAM allocation and each one updates its pixel data directly? That definitely would consume lots of CPU at scale w/o a DMA chip. That's how Sega did Sonic's animation, but the Genesis has DMA....
  14. FWIW, using multiple sprites is pretty low overhead in the way I did it for Sonic Demo: .struct SPRITEREG addr .word 1 xpos .word 1 ypos .word 1 orient .byte 1 attr .byte 1 .endstruct sonic_spriteregs: ; shadow registers for Sonic sprites (initial values) ;sonic's body .byte $10, $08, <sonic_x, >sonic_x, <(sonic_y+8), >(sonic_y+8), $0c, $a0 ;sonic's ears .byte $00, $08, <sonic_x, >sonic_x, <sonic_y, >sonic_y, $0c, $20 sonic_frames: ; VRAM locations for frames of Sonic's animation (SPREG format) .word $0810, $0820, $0830, $0840 .word $0800, $0804, $0800 $0804 animate_sonic: lda sonicframe inc and #3 ; sonic frame = 0..3 sta sonicframe asl ; use frame as X index (*2 because data stored as words, not separate HiByte / LoByte tables) tax lda sonic_frames,x ; sonic body address LoByte sta sonic_spriteregs + SPRITEREG::addr lda sonic_frames + 8,x ; sonic ears address LoByte sta sonic_spriteregs + 8 + SPRITEREG::addr lda sonic_frames+1,x ; sonic body address HiByte sta sonic_spriteregs + 1 + SPRITEREG::addr lda sonic_frames+9,x ; sonic ears address HiByte sta sonic_spriteregs + 9 + SPRITEREG::addr lda dirty ora #DIRTY_SPRITE sta dirty ; flag sprite address as dirty so VBLANK IRQ will update VERA rts A similar approach in C would use something akin to this: uint16_t sonic_frames[2][4] = { {0x810, 0x820, 0x830, 0x840} , {0x800, 0x804, 0x800, 0x804} }; Again, not saying "do this, n00b" - just sharing what I've done in case anyone else finds it useful or informative.
  • Create New...

Important Information

Please review our Terms of Use