[RetroHack] Start of competition
Thomas Harte

Sorry for starting a new thread — I thought that as I want to make sure everyone who might be interested would notice this it was not a suitable candidate for adding into the bottom of the old thread where it would be only a post edit.

So: the RetroHack competition starts now, with the release of version 1.0 of the RetroHack simulation library.

The rules aren't exactly worded yet, but here is the general timbre:

Submissions are to be made by midnight, GMT, on Sunday 18th of November. They can either be posted to a thread that will be deliberately created on Allegro.cc or emailed directly to me.

Your project, once unarchived (i.e. in a state from which the source code could be built and then executed, including all data files in whatever format the executable will expect them), must occupy no more than 512 kB of disk space. The size of the source code of any libraries that the project uses other than the RetroHack library and any libraries that you would reasonably expect to be supplied with a compiler will be included in this size count.

The entries will be bundled together and released as a source bundle and as executables for both OS X and Windows. Judging will be performed by a popular vote. Categories and marking criteria will be created, the number of which will depend on the interest the competition attracts. They will seek to reward both artistic and technical achievements.

Fixes may be made to the RetroHack library over the course of the competition. In that case each new release of the library will be given a new version number. Entries may use any of the released versions of the library, but a reason must be given if they are found not work with the version of the library that is current at the end of the competition. It is not the entrants responsibility to ensure that they keep up to date with any mid-competition library updates.

Anyway, here it is: http://members.allegro.cc/ThomasHarte/RetroHack/LibRetroHack.zip.
The documentation is here and the AY datasheet is here.

Jakub Wasilewski

Great. I'm a little exhausted after work (which involves a lot of tedious trial-and-error lately - writing extensions for Thunderbird is a P.I.T.A.), so I'll probably only give the library a cursory look.

Oh, by the way, there is a typo on p16 of the docs - it should say RT_VSYNC, not AY_VSYNC.

StevenVI

Exciting. The retro feeling of Tetrominoes was fun. I especially liked the Neo Geo-esque beginning. If I make a game I may have to copy that into mine.

I just fear that a month is too long for me to stay interested.

Thomas Fjellstrom

you don't have to spend the entire month on it. Its more than a 3 day project with all the optimizing you may need to do, but hey, its not a 30 day project :P

StevenVI

Yeah.... I was reading the Wikipedia page for CGA to get some motivation, and it dawned on me that I would have to make a game that was actually FUN to play, having no graphics to rely on in place of entertainment value.

I think that coming up with a fun idea would take me the most time. I'm currently thinking.

Onewing

Looks fun, but I've been in speedhack-mode (10-12 hour days) all of October for work (milestone due by the end of this month) and I just won't have it in me.

Good luck everyone!

X-G

Are there any other rules, regarding, say... disk usage by the program or anything else that might be difficult to arrange on a "genuine" system?

gnolam

I love the idea. :)
But I won't participate. Promises should be kept.

HardTranceFan

Wohoo :D. I'm looking forward to this.

And as Harry Carey says, now to come up with a fun idea over the next few weeks...

MiquelFire

I might make something, but we'll see. I may not have the time.

lambik

I suspect there is an error in the keyboard table: there are two RIGHT SHIFTs (line 9, bit 6 and line 7, bit 2) I think one of these should be RIGHT CTRL, most likely the 9,6 combo.
Also there isn't a built-in character set as far as I can see so these will have to be done with sprites, am I right? If so, is there a limit to the number of sprites?

Jeff Bernard

Alright, I got a good keyboard handler... now I just need to figure out how these graphics work to start making a game.

And yes, line 9 bit 6 is Right Control.

Simon Parzer

I just compiled the example programs with Linux and I have to say that the sound stutters. It ran okay with the Windows examples, though.

HardTranceFan

A question about the music format - how do I create a .PSG chip tune, or where can they for found? I've been searching the 'net most of the morning, but with no success.

n/m. I read the previous thread and think I've got my query answered.

Thomas Harte
Quote:

Oh, by the way, there is a typo on p16 of the docs - it should say RT_VSYNC, not AY_VSYNC.

Quote:

suspect there is an error in the keyboard table:...

Both fixed!

Quote:

I just compiled the example programs with Linux and I have to say that the sound stutters.

Any chance of trying the new retrohack.c file attached to this post? It substantially increases the frequency of the get_audio_stream_buffer checks. If it fixes the problem I'll make it version 1.1 of the library.

Simon Parzer
Quote:

Any chance of trying the new retrohack.c file attached to this post? It substantially increases the frequency of the get_audio_stream_buffer checks. If it fixes the problem I'll make it version 1.1 of the library.

No change. It especially stutters as soon as the CPU usage goes up. Sometimes I just have to move the mouse or click somewhere and it stutters really bad.
"Stutter" is maybe not the correct word. It's more that the current sound buffer hangs for half a second so it repeats itself.

I increased BUFFER_SIZE to 4096 and now it's a lot better.

Thomas Harte
Quote:

I increased BUFFER_SIZE to 4096 and now it's a lot better.

I'm going to try and put together a version with a dynamic buffer size, to fix this problem without introducing undue latency on the other platforms. I hope you'll be able to help test it?

In the mean time, RetroHack now has a hastily constructed webpage: http://members.allegro.cc/ThomasHarte/RetroHack.

EDIT: further to the Linux sound issue, I'd be grateful if you give the attached version of retrohack.c a go. It attempts to automatically pick the buffer size at runtime. On my machine it usually goes for 512 or 1024, which is good because I can hear the sound breaking up if I manually force lower numbers.

Simon Parzer
Quote:

EDIT: further to the Linux sound issue, I'd be grateful if you give the attached version of retrohack.c a go. It attempts to automatically pick the buffer size at runtime. On my machine it usually goes for 512 or 1024, which is good because I can hear the sound breaking up if I manually force lower numbers.

Works fine initially, but as soon as I put high load on the CPU (moving windows around, running some CPU intensive programs), the output gets broken permanently, it skips a lot and continues to do so even after the CPU is idle again.

Now, about another issue: Fullscreen. My video card supports it (320x240), but my monitor/graphics adapter kinda doesn't. Image doesn't fill the screen and aspect ratio is wrong. It can handle 640x480 fullscreen, though.
Also, some effects (scanlines, blur) would be nice, so it really looks like from an old monitor. Some emulators do this. :-X

Thomas Harte

Oh, I see what I did! It can't cope with buffer sizes over 4096, yet tries to select them anyway, and if it ends up with one then it sticks with it forever.

So, hopefully both those two things fixed, try the attached?

EDIT:

Quote:

Now, about another issue: Fullscreen. My video card supports it (320x240), but my monitor/graphics adapter kinda doesn't.

The full screen logic is "try for 320x240, if Allegro can't set that then use 640x480". So really this is an Allegro/X-Windows issue. But I'll think about it.

Quote:

Also, some effects (scanlines, blur) would be nice, so it really looks like from an old monitor. Some emulators do this.

I've never been a big fan of those effects (see also: the way I've never implemented them in any of my emulators, you'll probably also need to see ElectrEm to see one of my emulators, but the Linux port is long broken so you probably can't anyway), but I'll look into it. If I implement anything it'll be a classic computer to TV thing like the chrominance being slightly out of sync with the luminance. Which isn't that hard to achieve with the way I have the palette set up...

EDIT2: Oh, baring in mind those comments I think now is a good time to further discuss the rules re: new library releases mid-competition. The burden is primarily on me to (a) fix bugs; and (b) not break backwards compatibility. The "a reason must be given if they are found not work with the version of the library that is current at the end of the competition" is present so that if I have made some sort of idiotic mistake that means the entire point of the competition can be avoided (as per an early version of the code, which credited you with extra cycles if you blitted stuff mirrored across the y-axis) and an entrant deliberately exploits that to gain an unfair advantage then there is a mechanism for removing that advantage.

Simon Parzer
Quote:

I've never been a big fan of those effects

As long as they aren't overdone they look nice, I think.
Look at these two screenshots from OpenMSX. Left one without enhanchements, Right one with standard settings. Looks even better in fullscreen.

http://www.allegro.cc/files/attachment/593525http://www.allegro.cc/files/attachment/593526

HardTranceFan

Thomas, is the colour palette set? If so, what are the colours? Or can we use Allegro to change it?

Jeff Bernard

He posted the palette in the other thread. There are 256 different colors:

{"name":"265c57e56dbd2a086b195d8a5a9786fa.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/8\/c8625b7b33034646cfde9848f83ed9e5.png","w":382,"h":328,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/8\/c8625b7b33034646cfde9848f83ed9e5"}265c57e56dbd2a086b195d8a5a9786fa.png

HardTranceFan

Heh, I missed that one :). Cheers.

Jeff Bernard

Grrr... this palette is so limiting... I can't find any good reds to even recreate Mario.

593527

Simon Parzer
Quote:

So, hopefully both those two things fixed, try the attached?

Ok, the sound works fine now. :)

Victor Williams Stafusa da Silva

Hopefully i could do something.

Simon Parzer

Does anyone know of a tracker/sequencer program that can create .psg files? I have to write one if I don't find one (It can be an ATARI/MSX/whatever program as long as I'm able to emulate it).

And no, stealing music isn't a solution for me.

Jeff Bernard

A little clarification on the rules: With the 512 kb space limit. Let's say my game is less than 512 kb out of the zip and runs. Now, my game has saving in it, and what if the created save file brings the filesize greater than 512 kb? Does the RetroHack Machine have a "memory card" system, or are we saving directly to the "battery"?

Simon Parzer: I've been looking for one too. Not much success (as I haven't found one), but if I do, I'll post it here.

Thomas Harte
Quote:

Thomas, is the colour palette set? If so, what are the colours? Or can we use Allegro to change it?

Whatever you do, don't use Allegro! As it's a library "other than the RetroHack library and any libraries that you would reasonably expect to be supplied with a compiler", it's size would count towards the total size of your entry. And as the source code is currently 5.1 MB, you'd be disqualified for breaking the 512 kB rule...

Quote:

Does anyone know of a tracker/sequencer program that can create .psg files?

The Wikipedia paye for AY-3-8910 mentions "SoundTracker", but the wikilink seems to go to a different tracker with the same name.

Note that the AY in the RetroHack machine is clocked at exactly the same rate as a ZX Spectrum.

Probably one of us (me?) should look into providing a tracker or wider file format support as a service for everyone else — especially as there's no rule against using other people's code. Just remember that it count's towards your file size total.

Quote:

Does the RetroHack Machine have a "memory card" system, or are we saving directly to the "battery"?

Oh, I hadn't thought about that at all. The rule, as worded, concerns the file size before the program is built or run, so the save games would not be counted. Since I don't want to be changing rules mid-competition, I guess that's how it'll have to stay.

Quote:

Ok, the sound works fine now.

Great! I'll make that version 1.1 of the library assuming it passes all of my tests too.

I don't think my code liked being adapted from a threaded SDL implementation to an Allegro "please can I have a sound buffer to fill now, if I'm awake at all" type arrangement.

EDIT:

Quote:

Grrr... this palette is so limiting... I can't find any good reds to even recreate Mario.

Then recreate Luigi!

I admit the palette doesn't quite span the full gamut, and isn't very close to the traditional RGB TTL-logic of many 80s machines. But its similar (though more expansive) to that on platforms like the C64.

Richard Phipps

Come on guys, you had very limited colours and palettes on the 8-bit (and even the 16-bit machines). Use your imagination and work within the limitations! :P

HardTranceFan
Quote:

Does anyone know of a tracker/sequencer program that can create .psg files?

The only ones I found a few days ago are MSX trackers. Use the emulator to log the AY changes to a psg file for use with your RetroHack game. Thomas mentioned FUSE Spectrum (Linux). In windows fMSX creates a psg file (my attempts with it resulted in about 30 seconds of music being a few hundred kb in size) and apparently X128 can do it too, but I can't confirm as it doesn't want to run on my machine :-/.

Quote:

Probably one of us (me?) should look into providing a tracker or wider file format support

Either option would be great and make life a little easier on us, particularly as there's a deadline and a few restrictions to adjust to.

Quote:

Quote:

Ok, the sound works fine now.

Great! I'll make that version 1.1 of the library assuming it passes all of my tests too.

Heh, and version 1.1 makes for crappier sound for me. It's slower, the pauses between notes seems to be a little random (either that, or a note is played for a longer period than it should). If it'll help, I can get a wav dump of the tetris demo so you can hear what it's like.

Thomas Harte
Quote:

In windows fMSX creates a psg file (my attempts with it resulted in about 30 seconds of music being a few hundred kb in size) and apparently X128 can do it too, but I can't confirm as it doesn't want to run on my machine

No, X128 is an ancient DOS emulator that I think was extremely popular a little less than 10 years ago.

PSG files are gigantic because they're really, really stupid. At best they are a tagged list of the changes that were made to AY registers during each frame. At worst, as with the ones I got from FUSE, They're a list of the value in every single register, every single frame - and they're almost twice as large as they need to be for that because the format is based around "identifier of changed register, new value" pairs so FUSE is wastefully writing 16 bytes every frame that could easily be implicit.

The proper tracker formats seem to have notes, envelopes, loops, etc, as you'd expect. Which probably make both the tunes I've included about 2 kB in size rather than <whatever> hundred kB they are at the minute.

I'll get onto this as soon as I have a spare minute.

Quote:

Heh, and version 1.1 makes for crappier sound for me. It's slower, the pauses between notes seems to be a little random (either that, or a note is played for a longer period than it should). If it'll help, I can get a wav dump of the tetris demo so you can hear what it's like.

Just to confirm: you mean the version attached to this post and not any of the previous ones? If so then it may not help that it periodically dumps '.'s to stdout. But I doubt if that's a serious timing problem as it doesn't do it much. A WAV would be great.

Allegro is sufficiently frustrating that I'm tempted just to leave the buffer size hardcoded at 1024 (as in the current official libraries) and leave it as a compile time option as neither OS X or Windows seem to have an issue with that sort of buffer size and — as an extremely broad generalisation — Linux people are used to having to adjust things anyway.

HardTranceFan
Quote:

Just to confirm: you mean the version attached to this post and not any of the previous ones? If so then it may not help that it periodically dumps '.'s to stdout. But I doubt if that's a serious timing problem as it doesn't do it much. A WAV would be great.

Yes, that retrohack.c file.

Attached are 2 mp3 files:
OriginalTetrominoes.mp3 is the output from the original game you supplied as an example program.
WithNewRetroHeader.mp3 is the output compiled with the new retrohack.c file.

Any chance that you compile and post a new version of the tetrominoes.exe? Then I can check to see if it's my compiler, or maybe something I'm doing (though I've compiled with the original .c file and there were no problems).

Thomas Harte
Quote:

Attached are 2 mp3 files

Oh, you're right, that's horrid. I'll get right onto it. I expect I've forgotten to initialise something.

Vanneto

I get an undefined reference to rt_Init() linking error. :P What am I doing wrong?

Im using the function like this:

1// something.hpp
2#ifndef ...
3#define ...
4#include "retrohack.h"
5 
6class Something
7{
8 public:
9 static bool Init();
10};
11#endif
12 
13// something.cpp
14bool Something::Init()
15{
16 bool result = rt_Init();
17 if (result != true) return false;
18 return true;
19}

Simon Parzer
Quote:

I get an undefined reference to rt_Init() linking error. :P What am I doing wrong?

Maybe you forgot to add retrohack.c to your project?

Vanneto

Nope, already thought about that. Its in the project alright...

Thomas Harte
Quote:

I get an undefined reference to rt_Init() linking error. What am I doing wrong?

Oh! My mistake! Try this:

 extern "C" {
   #include "retrohack.h"
 }

It'll be fixed in version 1.1.

microcat

What about the allegro timers? Is it okay to use them in this competition?
I was thinking about making a game where you have to race against the clock, do I have to find alternate methods?

I think it's a bit unclear what parts of allegro we can use and what parts we can not. In tetrominoes.c, for example, I seem to recall a call to load_pcx, blit and others. I assume we can use all the allegro functions as long as we use the retrohack ones for graphic display and sound playing?

Vanneto

You should use the RetroHack machine timers...

Jeff Bernard

I believe you can't use any Allegro routines. At least, I'm not going to.

What you say in tetrominoes was how Thomas Harte made his .fnt file from a bitmap font. If you looked at the source, you would notice that GrabFont() is never called.

Elias

Is there something like in Speedhack where you can see screenshots with the current progress of contestants? I always liked watching those.. :)

Jeff Bernard

Nope. :(

I've set up a special blog for RetroHack on my website. It's pretty much up to everyone themselves.

HardTranceFan

My current screen shot is a blank screen. Although I've checked out the example programs, searched for .psg files and trackers, hunted for appropriate graphics and scratched my head in desperation for a semi-decent game idea, I've not started any coding what-so-ever.

My initial intention is create a utility to convert my 256 colour bitmap sprites to images with the palette that is used by the RetroHack library, so that the colours are as close to the original sprite as possible.

I'm aiming to complete a simple game (due to time constraints & house renovations), but hopefully one that contains a smidgeon of fun.

[edit]
Thomas, any chance of modifying the library to play .ay files?
[/edit]

Jakub Wasilewski

My current screenshot is a green screen. However, the sound is what is interesting.

I've began putting together my own tracker, and lo and behold, it uses its own format for storing music. I deemed that using the .psg playing functions would be a bit of a cop-out (come on, no '80s computer shipped with a "please play my music" subroutines in their ROM ;)), so I went all the way. Of course, I will probably fail miserably (due to timing issues and the need to interleave AY/blitter calls), but it's still worth a try. As of now, the tracker routine loads and plays "samples", but is oblivious to the order they should be played :).

The other thing I already have is a python converter for graphics, again converting to my homegrown format (which allows even 256-colour bitmaps - if you have the time to blit them).

I have a clear idea for what my game will be, and the type of gameplay is heavily influenced by the way the blitter works. It will be rather simple, so hopefully I will be able to finish it in time, even in between classes and work.

One question, though - are teams allowed? Nothing really deep, I just want to convince one of my friends to write some music for the game. Most people will use ripped files anyways, so I think that should be okay :).

Thomas Harte
Quote:

I think it's a bit unclear what parts of allegro we can use and what parts we can not. In tetrominoes.c, for example, I seem to recall a call to load_pcx, blit and others. I assume we can use all the allegro functions as long as we use the retrohack ones for graphic display and sound playing?

Quote:

What you say in tetrominoes was how Thomas Harte made his .fnt file from a bitmap font. If you looked at the source, you would notice that GrabFont() is never called.

Oh, yeah, no Allegro functions are allowed! GrabFont was meant to be commented out, I guess I uncommented it for some reason and forgot to comment it again. The only reason it's not deleted is that I thought other people might like a quick and way to get some writing done in their games and probably wouldn't like that horrid variant of Tahoma that I picked and then found disgusting.

Quote:

Thomas, any chance of modifying the library to play .ay files?

If I can find a documentation then yeah — why not? Except that at this stage it won't go in the library but will instead be some extra code that people may chose to use if they want, the fundamental difference being that it'll count towards your 512 kB.

The only things I intend to do to the main library are fix the header so that you don't have to manually declare it extern "C" if you're a C++ user and try to get dynamic audiostream size selection working to alleviate the problems with high latency machines as described by Simon Parzer.

Quote:

come on, no '80s computer shipped with a "please play my music" subroutines in their ROM

The BBC Micro does...

Quote:

One question, though - are teams allowed?

Yep. I stand by the principle that it's too late to add or modify rules significantly now.

Paul Pridham

Does this have to be a game per se? Could one make an interpretive interface on top of the Retrohack library instead, like the old interactive BASICs and such used for making games back in the 8-bit days?

Jakub Wasilewski
Quote:

The BBC Micro does...

Wasn't aware of that, sorry. I've never seen a BBC Micro in real life, and I'm not even sure they were ever available here (Poland being part of the socialist block back then).

Anyway, I just want to get the most kick out of participating and trying new things - hence doing my own tracker is just something to boost my own satisfaction :).

Elias

Just starting here.. and I'm wondering about colors, each sprite can use one 16-color palette out of the following 48 palettes - did I interpret that right?
593583

Karies

Jakub! Also You could release your tracker for other person using... like me :P

HardTranceFan

n/m - I think I'm a bit slow when it comes to understanding the colour schemes...

Thomas Harte

Big long, rambling post...

Quote:

Wasn't aware of that, sorry. I've never seen a BBC Micro in real life, and I'm not even sure they were ever available here (Poland being part of the socialist block back then).

Anyway, I just want to get the most kick out of participating and trying new things - hence doing my own tracker is just something to boost my own satisfaction .

Makes sense. And I was aware that the PSG file format is quite bloated and hard to create data for when I was implementing it. An earlier version of the library also had a RetroHack-specific file format implemented which tried to reach something a lot like a tracker format from compression of a PSG, but I couldn't really justify the time it was taking to get right. And it wouldn't have fixed the latter problem anyway.

Quote:

Thomas, any chance of modifying the library to play .ay files?

It seems I may need to implement a fully functional Z80 emulator to fully support AY files, at least based on the docs I eventually found bundled with a program called AYMakeR. Well, strictly speaking I think I'd need a Z80 emulator and a 68000 emulator, but I'm assured that most PC players don't support the 68000 code so I think I can ignore that. Luckily I have a full Z80 emulator to hand but it's both very multithreaded (as an easy way to implement coroutines — I care about the accuracy of my emulators) and about 45 kB in size. Which is quite a lot out of 512 kB. Nevertheless I'll see what I can do.

Responding to a request not on this thread, I also want to put some sort of graphics conversion tool together...

Quote:

Just starting here.. and I'm wondering about colors, each sprite can use one 16-color palette out of the following 48 palettes - did I interpret that right?

The main difference I can see between yours and the ones I've just got the RetroHack simulator to spit out (subject to an observation below, source code attached) is in the RT_MIX set. Did you notice that the low two bits of the colour info in the sprite get separated, one becoming the high bit on the Cb channel and the other becoming the high bit on the Cr channel?

This has actually uncovered another bug in version 1.0 of the library — it doesn't cram RT_MIX in correctly. An attached example program should display all the colour combos.

At the minute, with the bug, it shows (please ignore my haphazard cropping):

http://www.allegro.cc/files/attachment/593580

When fixed it should show:
http://www.allegro.cc/files/attachment/593581

If you want to apply the fix yourself in the run up to version 1.1 then go into retrohack.c, find the two instances of "RT_MIX" (should be at or around lines 321 and 338) and change the lines beneath so that they're masking the first two things by 0xc instead of 0xb, i.e.

putpixel(newgraphic->images[c], x, y, (((Colour & 0xc) << 4) | ((c&0xc) << 2) | ((Colour & 0x2) << 2) | ((c&0x2) << 1) | ((Colour & 0x1) << 1) | (c&0x1))^COLOUR_MASK);

and

newgraphic->MaskCols[c] = (((maskcol & 0xc) << 4) | ((c&0xc) << 2) | ((maskcol&0x2) << 2) | ((c&0x2) << 1) | ((maskcol&0x1) << 1) | (c&0x1))^COLOUR_MASK;

Respectively.

Quote:

Jakub! Also You could release your tracker for other person using... like me

Just to reiterate for any third parties dropping into the conversation: this is explicitly allowed.

Richard Phipps

Has anyone got any progress to show yet?

X-G

Just this:

http://www.allegro.cc/files/attachment/593582

I have to be honest, the thing that's most difficult to work around right now is the colors available. Not the bit depth... 16 colors is enough to make some real dandy sprites. No, the problem is the overabundance of green tones, the lack of any deep dark tones, and the fact that you can't mix-and-match colors the way you want. It means you end up wasting 60-80% of all the colors in each palette, which is annoying. The luma gamut is wider than it needs to be, and the chroma gamuts are too small. It makes you have to do some funky things, but that's all right. It's what this is about, working under constraints. Just mentioning what's giving me the most trouble right now.

EDIT: Improved him a little.

http://www.allegro.cc/files/attachment/593584

Elias
Quote:

The main difference I can see between yours and the ones I've just got the RetroHack simulator to spit out (subject to an observation below, source code attached) is in the RT_MIX set. Did you notice that the low two bits of the colour info in the sprite get separated, one becoming the high bit on the Cb channel and the other becoming the high bit on the Cr channel?

Thanks, indeed. (I updated the picture in my previous post to not confuse anyone.)

Thomas Harte

Right. A new test version 1.1 of the RetroHack library is attached. It hopefully addresses the issues found with:

  • plain #including the library from C++

  • the RT_MIX colour palette

  • sound playback on machines with high latency

Please test! I'll rebuild the sample programs for OS X and Windows, and be back promptly.

EDIT: Never mind! I've finally managed to recreate HardTranceFan's sound issues under Windows on my own machine. Hopefully I can get completely to the bottom of this now.

Elias

The demo still works here in linux :)

You might want to fix the following warnings for gcc -W -Wall to work:

gcc -o retrohack.o -c -W -Wall -Wno-unused-parameter -I/usr/local/include retrohack.c
retrohack.c: In function '__ay_Init':
retrohack.c:792: warning: suggest parentheses around assignment used as truth value
retrohack.c: In function '__ay_Update':
retrohack.c:1099: warning: suggest parentheses around assignment used as truth value
retrohack.c:1120: warning: comparison between signed and unsigned
retrohack.c:1120: warning: comparison between signed and unsigned
retrohack.c:1128: warning: comparison between signed and unsigned

[edit:]
I just hit a problem costing me some time to solve - some colors in the 1x1 bitmap palette have the same RGB value, which causes Gimp to use them in a non-deterministic way on saving. So in case someone else hits this problem, just very slightly changing one of the two colors for all pairs of identical colors so they are unique makes it work.

Oh, and I'm making a sequel to my last retrohack entry - "Tom the Tomato 2". This is the current placeholder for Tom, but I also got an artist now so it should improve a lot yet. http://www.allegro.cc/files/attachment/593586

HardTranceFan

I now don't even have a blank screen anymore - my PC crashed on boot up this morning!

Thomas Harte

Right, I think I cracked the sound problems. Under Windows, Allegro seems to have an interesting 'feature' whereby get_audio_stream_buffer() won't return anything for quite a while, then will suddenly have four or five buffers ready to fill at once. That removes any way to know anything useful about where Allegro is in playing your audiostream (and is strictly contrary to the documented behaviour of the function, but I'll post in the right place to complain about that), which is what was confusing my code.

I've rejigged it to deal with that, though it has the disadvantage that if your setup is one of those affected then sound latency can be quite bad. At the minute I can't think of a way to avoid that with Allegro, so commiserations to affected people. Fingers crossed this misbehaviour is related to the Allegro/sound driver combination and not to the Allegro/Windows combination.

OS X, Linux and any other platform where Allegro works as described in the manual should be unaffected and continue to work well.

Anyway, new test version of the library is here. Also: Windows test programs, OS X test programs.

HardTranceFan
Quote:

Responding to a request not on this thread, I also want to put some sort of graphics conversion tool together...

Oh, yes please! Trying to get my head around the colour schemes is driving me nuts. I completely forgot about the colour formats until Elias pointed out the total of 48x16 colour palettes. I'm used to true colour and the Amstrad colour schemes, and I'm finding this is taking a little bit of thought.

X-G
1import yaml
2import sys
3from struct import pack
4from PIL import Image
5 
6if __name__ == "__main__":
7
8 imagedef = yaml.load(file("gfxconv.yaml", "r"))
9
10 for image in imagedef:
11 print "Processing %s..." % image["infile"]
12 # Open source bitmap
13 srcimg = Image.open(image["infile"])
14 w, h = srcimg.size
15
16 # Open output raw
17 ofp = file("../bin/" + image["infile"][:-3]+"rts", "wb")
18
19 # Write frame size
20 fw, fh = w, h
21 try:
22 fw, fh = image["framesize"]
23 except KeyError:
24 pass
25 ofp.write(pack("BB", fw, fh))
26 ofp.write(pack("B", int(h/fh)))
27
28 # Write palette type
29 ft = {"Y":0, "CbCr":1, "MIX":2}[image["mode"]]
30 pal = image["palette"]
31 composite = (ft << 6) + (pal & 0x1F)
32 ofp.write(pack("B", composite))
33
34 # Convert and write all the image data.
35 for y in xrange(h):
36 for x in xrange(w / 2):
37 left = srcimg.getpixel((x*2, y))
38 right = srcimg.getpixel((x*2 + 1, y))
39 composite = ((left << 4) & 0xF0) + (right & 0x0F);
40 ofp.write(pack("B", composite))
41
42 # Done with this file.
43 ofp.close()
44
45 exit(0)

This is a Python script I whipped out that converts a 16-bit paletted image into a format suitable for uploading to retrohack video memory, plus hints for what mode and nibble to use as well as frame size information. As you can see it's pretty hardcoded right now, but it reads a file called gfxconv.yaml in the same directory which looks like this:

- infile: friedrich.bmp
  mode: MIX
  palette: 1
  framesize: [26, 26]
- infile: friedrich_b.bmp
  mode: CbCr
  palette: 0
  framesize: [26, 26]

It needs pyYAML and PIL, obviously. Do let me know if you find it useful.

Thomas Harte

Further to this general topic, a new RetroHack example program is attached (and will shortly appear on the website).

It loads 8bpp PCX files (and exactly that format only), maps them onto the best fitting RetroHack palette (without dithering), uploads them to graphics memory and returns a colour parameter for you to pass to Blit or MaskedBlit.

The one useful function is:

void *rtSup_LoadPCX(char *Name, int *OtherNibble, int Masked)

Where:
Name is the filename of the graphic to be loaded.
OtherNibble is an integer that will be filled with the value you should pass as OtherNibble in subsequent calls to Blit/MaskedBlit to get the best colour match.
Masked is a boolean (i.e. pass TRUE or FALSE) that hints whether this is a graphic intended for masked blitting or not. If you pass FALSE then all colours in the graphic are given equal importance. If you pass TRUE then the colour with palette entry 0 in your PCX file is treated as a mask colour. Subsequently the routine doesn't care how closely that colour is mapped to the RetroHack palette and makes sure that no other colour in the graphic you are loading is mapped to the same RetroHack spot.

Included in the demo is a luigi.pcx I just downloaded, and it should display this:
{"name":"593596","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/7\/b7f9625dcdda97c7f63abcb571e38c8d.png","w":653,"h":489,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/7\/b7f9625dcdda97c7f63abcb571e38c8d"}593596

Hope this helps!

EDIT: note that it assumes the RT_MIX palettes are working correctly, as in the v1.1 test releases of the library above, not as in the bugged v1.0. So I recommend you test against that. Especially as I'd also like to know if 1.1 is suitable for proper release.

Elias

I found the AY data sheet PDF rather scary, but some googling turned up a page with this table, which has 100% of the same relevant info as the whole PDF (scroll down to Yamahatm YM-2149):
http://sc68.atari.org/developers_technicals.html

So, basically, 14 registers, where I can set frequencies and volume, plus noise channel and envelope :)

Thomas Harte
Quote:

So, basically, 14 registers, where I can set frequencies and volume, plus noise channel and envelope

Yep, that sounds about right. And the only other potentially interesting thing is that per channel mixing is done with an active low bitwise OR. Which explains how you can get a level wave, as per the sample demo.

Paul Pridham

Thomas, what's the license for this code, anyway? There's some neat stuff in there.

Thomas Harte
Quote:

Thomas, what's the license for this code, anyway? There's some neat stuff in there.

It's not really that neat, but since there is the potential for other people to create games that are dependent on my code, I guess a license that is as permissive as possible is desirable. I guess I'll adopt the zlib license unless anybody wants anything more flexible?

Paul Pridham

Looks good to me!

Jakub Wasilewski

Having a job sucks. Especially if you want to participate in a competition, but instead, all your computer time at home goes into earning money...

However, I finally managed to save up some time to actually put in a few hours into Retrohack, and I'm pretty happy with the (preliminary) results. The tracker is coming together nicely and I expect to have it somewhat finished by Saturday. I will probably release the source code and all revelant files once I have a "finished product".

For now, I have a demo I would like you to test - it is a Windows binary with an example one-pattern module (with samples and the track itself ripped from Amiga's Lotus 2 and ported to my own text format). I'd like you to give it a few spins and let me know if there are any problems with the playback on your machine. Don't expect wonders though, the quality will be rather crap :).

Thomas:
The binary is linked against Retrohack lib 1.0. Version 1.1 causes the playback to be completely borked on my machine - it plays a fragment properly, then inserts some silence, then plays back something random and finally resumes playing the tune. I rely heavily on RT_HSYNC timing, so it might be me doing something funky. On the other hand, some people have been reporting problems on Windows, so perhaps it's not my fault.

Another thing regarding 1.1 - there is a problem with the retrohack.h header under C++. The Allegro header is wrapped in 'extern "C"', which makes the compiler misunderstand the definition of the fix class and throw an awful lot of errors. Moving #include <allegro.h> outside the 'extern "C"' helps.

Oh, and the thread became awfully silent lately... Come on people, tell us about your progress!

HardTranceFan

Nothing from this corner as yet. Time has been rather sparse in it's availability. However, next week looks more promising for a few decent hours of coding.

Jeff Bernard

So, I started playing some NES games as research for my RetroHack entry because I want my entry to be kinda like an NES game. In other words, they game would be really fun despite not having breathtaking graphics or sounds.

I've kinda gotten a bit carried away in the sense that I haven't programmed for about a week and I've beaten quite a few NES games and continue to play more.

Jakub Wasilewski
Quote:

I'd like you to give it a few spins and let me know if there are any problems with the playback on your machine.

So, did anyone try it?

Elias
Quote:

Oh, and the thread became awfully silent lately... Come on people, tell us about your progress!

We are making good progress here. Right now, we are using about 20K out of 64K of video ram - but if Paul keeps drawing sprite frames at the rate has has done until now, it will get a problem :) There's only one sprite so far, which means we can only add two more, to still have room for a few tiles.

Oh, and I'm looking forward to your tracker. I wrote a crude ASCII format so you can define instrument envelopes and define tracks by writing the notes (like "C D E F F#") - but a proper tracker certainly would be preferable.

Jeff Bernard
Quote:

So, did anyone try it?

Nope. I've been too busy abandoning everything in my life to play as many NES games as I can.;D

Paul Pridham

Sorry, haven't tried it either. Too busy... we have a game to make.

Oh yea people, it's on! ;)

HardTranceFan

@Jakub: I ran it, but it crashed part way through the tune (about 6 seconds into the piece). But the bit before the crash sounded really good :D.

Jakub Wasilewski
Quote:

I ran it, but it crashed part way through the tune (about 6 seconds into the piece)

Well the test only had one pattern, which lasts about 6 seconds :).

I'm reconsidering the whole idea of sharing this code... It's became a rather convoluted mess of things. It's all became rather idiosyncratic with a lot of work-arounds and hoops you have to jump through - documenting all of it would be a rather lengthy process. I also don't want to spend a lot of time making it easily reusable outside my audio framework, to which module playback is heavily bound...

Well, I've promised to share it, so here goes - if you figure it out, good for you :). Attached what I have to this post. It's not entirely finished, but it's working.

How to make it play something:
1) Prepare a .src file using mod2.src as a template, along with all the needed .wav's in the same directory
2) Compile it with modconvert.py (requires Python)
3) Play it back (AYTest.cpp is an example program that does that, and one we will be using to write the music).

The whole thing is in C++, and the text->binary format converter is in Python. The archive contains all needed source-files, just link all *.cpp files in both directories with Allegro.

Oh, not commented at all. And there be dragons in that code :).

EDIT: Remember, it only works properly with RH 1.0 under Windows.

Jeff Bernard

Question- Can I modify the RetroHack library to do a scanlines effect? It looks a lot better (tweaking the library a bit), rather than using the RetroHack's blit function because I can get thinner lines.

Thomas Harte
Quote:

Question- Can I modify the RetroHack library to do a scanlines effect? It looks a lot better (tweaking the library a bit), rather than using the RetroHack's blit function because I can get thinner lines.

As currently drafted, that'd be against the rules. But if you send me the code, I'll try to incorporate it as an option in the coming v1.1 of the library.

Re: all that:

  • I'm not making very good progress with the AY file format. The format itself is a horrid mess, but the problem seems to be my z80 code — I think I've stripped it from its previous project quite poorly and probably broken something. But I'll keep trying.

  • I've pretty much decided I'm going to give up on the sound fixes. As the only affected platform seems to be Linux, I'll just make buffer size a compile time option. Especially as I want to get the RT_MIX palette and C++ #include fixes 'out there'

EDIT: partial update. I have fixed my AY file format music player, and uploaded it to the website. Here's a direct file link. Some documentation and a demo program are included in that archive.

Jeff Bernard

The scanlines modification I wrote is pretty basic (and probably not what actual scanlines are). Basically, it stretch_blits the buffer to a BITMAP* that is the same size as the screen, instead of blitting to the screen. Then it draws horizontal lines of color makcol(0,0,128) (because I think that looks good overlayed onto my game) at certain intervals. I don't have the code in front of me now, but the loop that draws the horizontal lines is (I'm pretty sure): for (i = 0; i < SCREEN_H; i+=3).

Elias

{"name":"593618","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/7\/777a600c4e59720821347fc11f93833b.png","w":640,"h":480,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/7\/777a600c4e59720821347fc11f93833b"}593618
What am I doing wrong here? Both blits are drawn to 160/120 (the center). The one in the lower right corner works just as expected. But when I flip the y scaling - why do I get this shifted and enlarged blit above it? And in case that's the intended behavior, how would I get just a vertically flipped version?

(EDIT)
Ah, figured it out now by glancing at retrohack.c, you have a special case there for when the y scale is < 0.. still, it's weird - the Atari Lynx did not do any such position/size adjustments just because you used flipped drawing.

1#include "retrohack.h"
2 
3int main(void)
4{
5 rt_Init();
6 
7 unsigned char data[256 * 256];
8 int i, j;
9 for (i = 0; i < 256; i++)
10 for (j = 0; j < 256; j++)
11 data[i + j * 256] = ((i / 128) & 1) + ((j / 128) & 1) * 2;
12 void * g = rt_UploadGraphic(RT_MIX, data, 1, 256, 256, 15);
13
14 while (!rtSim_QuitWanted())
15 {
16 if ((rt_ReadKeyboard(0) & 2) == 0) break;
17 
18 // background
19 rt_Blit(g, 0, 0, 0, ftofix(320.0 / 256), ftofix(240.0 / 256), 0, 0);
20
21 // ???
22 rt_Blit(g, 15, ftofix(160), ftofix(120), ftofix(1) / 8, ftofix(-1) / 8,
23 ftofix(1 / 64.0), ftofix(-1 / 16.0 / 32.0));
24
25 // works as it should
26 rt_Blit(g, 15, ftofix(160), ftofix(120), ftofix(1) /8, ftofix(1) / 8,
27 ftofix(1 / 64.0), ftofix(-1 / 16.0 / 32.0));
28
29 rt_Flip();
30 }
31 rt_Exit();
32 return 0;
33}
34END_OF_MAIN()

Karies

Hello!
I have a problem when I try to make sprite rotation. I think the method I'm using is the problem then I want to know if somebody can tell me the good one for pixel rotation.

x2 and y2 are the transformed coordinates:

int x2 = (int)
( (cos((angle*PI)/180)*(i-xcenter))-(sin((angle*PI)/180)*(j-ycenter))+xcenter );

int y2 = (int)
( (sin((angle*PI)/180)*(i-xcenter))-(cos((angle*PI)/180)*(j-ycenter))+ycenter );
data[ (y2*desp) + x2] = byte;

Jakub Wasilewski

A cursory look would suggest you messed up the signs. Y2 should have sin+cos, not sin-cos. Oh, and I would suggest using the Programming Questions forum for general questions not related to RH, there is no need to clutter this thread.

Well, since I'm already making a post here, I might brag a little.

A few minutes ago, I finally managed to merge my blitter code with the tracker playback code without one farking up the other, and I'm really happy about it :). I ended up counting every single expended cycle, including peculiarities such as the AY bus having a different clock resulting in additional cycles for synchronization, and even the single cycle cost for reading the keyboard.

Well, at least now I have a cycle-perfect blitter + sound playback. It probably crashes if the amount of blits needed overloads the blitter for a given frame, but that's something to be solved tomorrow ;).

Karies

:-/ well... that was embarrassing, but... although the problem was easy to solve, it is related to retrohack. I didn't use rotate_sprite allegro method and bitmap struct because I'm beginning to make a retrohack game, and if I would ask in other thread then people could tell me other ways to do it and they couldn't give me the answer.

Thanks Jakub.. and yes, I'm a game programming newbie (trying to make a retrohack game :P)

Thomas Harte
Quote:

What am I doing wrong here?

Nothing, it's a RetroHack bug. It'll be fixed in V1.1 of the library, which I hope to release tonight. In the meantime, you can fix it yourself by going into retrohack.c, finding the segment that starts at like 449 and looks like this:

  else
  {
    srcy = (g->images[0]->h << 22) - 1; // start at the bottom, draw upward

    y += scaley*g->images[0]->h; // move up the required number of pixels
    x -= skew*g->images[0]->h;
    scalex -= scalechange*g->images[0]->h;
  }

And replacing it with:

  else
  {
    int yadd = scaley*g->images[0]->h;

    srcy = (g->images[0]->h << 22) - 1; /* start at the bottom, draw upward */

    y += yadd; /* move up the required number of pixels */
    x -= fixmul(yadd, skew); skew = -skew;
    scalex -= fixmul(yadd, scalechange); scalechange = -scalechange;
  }

Sorry about this!

EDIT: new screenshot:

http://www.allegro.cc/files/attachment/593636

Elias

That screenshot looks much more predictable, thanks :)

Thomas Harte

Grrr. Lost my first post to a login timeout. So, very briefly:

Version 1.1 of the library is now available, with fixes to RT_MIX palettes, vertically flipped sprites with non-zero ScaleChange and/or Skew and C++ #inclusion. Sound code is reverted to the version 1.0 version rather than the various realtime fixes that weren't working under Windows. BUFFER_SIZE may now be set on the compiler command line so that it can be chosen at build time. I think that's fine for now, as the only problems have been with the latency under Linux, where people will tend to build for themselves.

Also, to clarify — the competition ends on the 18th of November (as per the website and posts here), not the 11th as per the scroller in Tetrominoes. That text was sadly left in place from before the competition start was put back by a week.

Comments and feedback are welcome.

HardTranceFan

Heh, guess who didn't read the manual properly and realise there's only 64K of graphics memory? All my plans, dashed because I skimmed over the library docs. Time for some tricky dicky stuff...

[edit]
@Thomas: How can I determine the total space I'm using for sprites? At one point I had 36Kb of .raw files, yet it seemed like not all the sprites were being stored in memory. Are there overheads we should be aware of?

Elias

One pixel uses only half a byte. I do this here:

rt_UploadGraphic(mode, data, 1, w, h, 0);
mem_used += w * h;
printf("%d/64 KB used", mem_used / 2048);

HardTranceFan

Well, what do you know. I was allocating graphics space to fonts way too many times, and a simple 36 character 8x7 font was taking up 55Kb. I've since fixed it and now it's registering as less than 1K.

Thanks Elias, you've helped to spot a bug ;D

[edit]
I've had problems compiling with the latest library (my project is C++) - it keeps coming up with the message:

C:/Program Files/CodeBlocks/include/allegro/fix.h:92: error: declaration of C function `fix operator+(fix, int)' conflicts with
C:/Program Files/CodeBlocks/include/allegro/fix.h:91: error: previous declaration `fix operator+(fix, fix)' here
C:/Program Files/CodeBlocks/include/allegro/fix.h:92: warning: `fix operator+(fix, int)' is already a friend of class `fix'
C:/Program Files/CodeBlocks/include/allegro/fix.h:93: error: declaration of C function `fix operator+(int, fix)' conflicts with
C:/Program Files/CodeBlocks/include/allegro/fix.h:92: error: previous declaration `fix operator+(fix, int)' here
C:/Program Files/CodeBlocks/include/allegro/fix.h:93: warning: `fix operator+(int, fix)' is already a friend of class `fix'
...

However, I managed to get rid of it by putting the #include <allegro.h> before the [ty]#ifdef __cplusplus</tt> in the retrohack.h header file.

Should the library be updated, or am I missing something with my compiling?

Eric Love

Hi guys. I've been out of this scene entirely since I've been working full-time, and popped onto a.cc to show someone, and I see there's a RetroHack. I wished I'd found out earlier - the one week Back2Hack of 2002 was a good one even though only Elias & I made anything (or were there any others?)

In the Back2Hack I spent day one making the system play MIDI files, probably the best feature of my entry, and I'm thinking about trying to do the same thing here, for the benefit of anyone who wants to use such a feature. Would that be helpful to anyone? I haven't tried the code out yet, so I don't know how doable that would be. I'll look more at it tonight.

Elias

Ah, Back2Hack, that was fun. Our game this time is called "Tom the Tomato 2" - now guess what my Back2Hack game was called back then :)

I really wonder if there will be more entries this time - else we should get an easy win :) (Not that we're finished yet, but there's some gameplay emerging already, and still the whole final weekend, so should have something submittable.)

About music, in my case, I made a player which can play tunes given as an ASCII format already, so I'm more concerned with how to create sound effects now. For that need to first investigate why I seem to get sound buffer overruns all the time though - it can't be audiostreams, as in my own synth they work fine with a buffer size of 2048 and in retrohack.c I already upped that to 8192. Likely I'm misinterpreting the AY specs..

For example, can writing the same value to a register multiple times have any effect?

Thomas Harte
Quote:

One pixel uses only half a byte. I do this here: ...

Don't forget the caveat that pixel scan lines have to begin on byte boundaries, so if your sprite is an odd number of pixels wide then storage is allocated for a spare pixel at the end of every scanline, and then not used. So the correct formula to work out memory usage for a single sprite of size w × h is ((w + 1) >> 1) * h.

Quote:

I've had problems compiling with the latest library (my project is C++) - it keeps coming up with the message:
...
However, I managed to get rid of it by putting the #include <allegro.h> before the [ty]#ifdef __cplusplus in the retrohack.h header file.

Oh, good spot. In that case the compiler is effectively being told "here's some C++ code which you should expect to link to from a pure-C file" which obviously doesn't make any sense. I'll fix that and reupload version 1.1 tonight. I think it's acceptable in this case not to increment the library version because this is a mere linking problem and definitely either doesn't change the functionality of the library or makes it work.

Quote:

Hi guys. I've been out of this scene entirely since I've been working full-time, and popped onto a.cc to show someone, and I see there's a RetroHack. I wished I'd found out earlier - the one week Back2Hack of 2002 was a good one even though only Elias & I made anything (or were there any others?)

No, it was just you two. Which is partly why I've not exactly been pushing the Back2Hack angle.

EDIT:
I also think it's time to become certain about the categories that prizes will be considered part of. I'm going to come up with some specific proposals tonight. In the meantime, I've decided to clarify the rules concerning library modifications, for the benefit of Jeff Bernard. Entries with some modifications are acceptable, but in that case both a version with the modified library and a version without will be circulated in the judging pack to provide a means of verification that the modifications don't fundamentally subvert the purpose of the competition, e.g. by increasing the amount of drawing that's allowed to be done each frame.

Jeff Bernard

Woah, woah, woah. Prizes? I was planning on not being able to finish my entry since all I've got is an engine and I've been spending too much time learning NES Assembler when I should have been working on my RetroHack entry.

I may just need to switch into SpeedHack mode for this last week so that I can win some trinket.

Elias

I tried displaying the sound output, and couldn't find the problem I get yet, but I'm wondering about something else now. This code

1#include "retrohack.h"
2#include <stdio.h>
3#include <math.h>
4 
5static void ay(unsigned char reg, unsigned char val)
6{
7 ay_Write(AY_REGSELECT, reg);
8 ay_Write(AY_REGVALUE, val);
9}
10 
11static void ay_frequency(int channel, int tp)
12{
13 ay(channel * 2 + 0, tp & 255);
14 ay(channel * 2 + 1, tp >> 8);
15}
16 
17static void ay_noise(int np)
18{
19 ay(6, np);
20}
21 
22static void ay_mixer(int a, int b, int c, int noise_a, int noise_b, int noise_c)
23{
24 ay(7, 0xff - a - 2 * b - 4 * c - 8 * noise_a - 16 * noise_b - 32 * noise_c);
25}
26 
27static void ay_volume(int channel, int v)
28{
29 ay(8 + channel, v);
30}
31 
32int main(int argc, const char *argv[])
33{
34 rt_Init();
35 rtSim_SetWindowTitle("AY");
36
37 ay_frequency(0, 200);
38 ay_frequency(1, 200);
39 ay_frequency(2, 200);
40 ay_volume(0, 15);
41 ay_volume(1, 15);
42 ay_volume(2, 15);
43 ay_mixer(1, 1, 1, 0, 0, 0);
44
45 while(!rtSim_QuitWanted())
46 {
47 int k[11], i, j;
48 for (i = 0; i < 11; i++)
49 k<i> = rt_ReadKeyboard(i);
50 
51 if ((k[0] & 2) == 0) break;
52 
53 rt_Flip();
54 }
55 
56 rt_Exit();
57 return 0;
58}
59END_OF_MAIN()

produces this when recording back from ALSA's output: {"name":"593678","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/b\/5b5d47136d0d8cc13766169aee23918b.png","w":1234,"h":393,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/b\/5b5d47136d0d8cc13766169aee23918b"}593678

So, is the distortion of the square wave over time supposed to happen? (I assume it simulates the AY..)

And also, why is the audio stream only played at half volume?

Thomas Harte
Quote:

I tried displaying the sound output, and couldn't find the problem I get yet

Apologies, I missed your last post.

Quote:

For example, can writing the same value to a register multiple times have any effect?

I don't think so.

Quote:

So, is the distortion of the square wave over time supposed to happen? (I assume it simulates the AY..)

I'm probably being a bit thick, but we're talking about the sudden change in wave shape just after 0.230, right? I can't really account for that right now. I'll play around. Does a similar thing happen if you set just one channel going?

For reference, there should be some aliasing because it's essentially just doing a point sample to down sample from 3,545,400 Hz to 44,100 Hz. But nothing like that.

EDIT:

Quote:

Woah, woah, woah. Prizes?

Yeah, I didn't really mean to say prizes, but maybe I can rustle something up. I'll think about it.

Elias
Quote:

I'm probably being a bit thick, but we're talking about the sudden change in wave shape just after 0.230, right? I can't really account for that right now. I'll play around. Does a similar thing happen if you set just one channel going?

Yes. I just tried again with only 1 channel now, and then, the effect is gone. I get a perfect square wave, just not centered.

HardTranceFan
Quote:

Yeah, I didn't really mean to say prizes, but maybe I can rustle something up. I'll think about it.

I can't speak for the others, but I'm just doing this for the challenge. And it's quite a bit of fun so far... :D

Paul Pridham

It seems that the sound effects (Win32) are playing a good 1/2 second later than when they are triggered. This kind of sucks for connecting actions to sounds!

Is there something I may be doing wrong to cause this?

Thomas Harte
Quote:

Is there something I may be doing wrong to cause this?

No, it seems to be a limitation in Allegro. See the code in this thread - under Windows, with a buffer size of 1024 bytes, Allegro sits there offering no audio buffers for a very long time then suddenly offers six at once. So you're inevitably going to be at least one seventh of a second behind. But then because Allegro's AUDIOSTREAMS are completely and unhelpfully opaque, there's no real way to know how many buffers may suddenly need filling at once. That creates further problems because of the way the sound system works. So that the changes you request in the AY aren't all grouped together and performed simultaneously with an unknown and arbitrary precision, the machine has to keep a buffer of sound change requests and then map them to changes in the sound wave as it is generated. So the question is: how far back do you store sound events? When do you say "well, I've obviously got too much stuff stored because my events go back too far?" The answer is that you have no idea because Allegro doesn't reveal those details to you. On my particular Windows system, empirical testing suggests that 6 × 1024 samples may need to be generated at any one time, so the correct oldest event keep would be (6 × 1024) / 44100ths of a second. But on OS X it's 2 buffers. And on your machine it could, per the Allegro developer comments (in contrast to the documentation), be any number. So there's nothing much I can do, and nothing much you can do.

The various attempts at automatic AUDIOSTREAM buffer sizing, etc, that were considered for version 1.1 of the RetroHack library were meant to deemphasise these problems. They didn't work correctly across a sufficiently broad range of machines.

I think the real solution is to dust off and finish the SDL implementation of the RetroHack libraries. It has a system that is like AUDIOSTREAMs, but actually works with you rather than trying to surround you in bubblewrap and obscuring all useful functionality. If I'd known that the sound functionality of Allegro had become this useless, I probably wouldn't have tried to organise this competition.

Thomas Fjellstrom
Quote:

under Windows, with a buffer size of 1024 bytes, Allegro sits there offering no audio buffers for a very long time then suddenly offers six at once

Has anyone see that under linux/OSX? If not, its deff a bug in the windows driver.

I don't remember having this problem last time I played with allegro's AUDIOSTREAMS.

edit: IF it is a problem in all platforms, I think its a bug, it should not wait till all buffers are empty. And I'm postive it didn't for me a couple years ago (in linux). So I'd be willing to help fix allegro in that case. even if its just for the compo.

Thomas Harte
Quote:

Has anyone see that under linux/OSX? If not, its deff a bug in the windows driver.

I wasn't very clear, but the same code as on that other thread returns no buffers for a very long time, then two at once, then none for ages, then two at once, etc on my OS X machine.

The attitude of the developers on that thread also seems to be "this is the way we think Allegro should work, we'll fix the docs". So I'm not sure it's worth trying to organise fixes.

Thomas Fjellstrom

As a part time allegro developer, I think its wrong. And I'm not sure the others fully saw what the problem was.

AFAIK, it really should return one of the buffer's the ms its ready. not when more than one are.

Eric Love

Looks like everyone knows where they're going music-wise. Looking at the sound code I think a MIDI driver would've been a bit hard (on my limited time), although the one from Tomb Robber would've been a good starting point.

I wish I'd noticed RetroHack was on earlier. Although I hardly do any game dev any more, it would have been fun to contribute something to this hack. If I'm not busy at the end of the week, I might be up for some testing, if not I look forward to playing the games.

Elias
Quote:

As a part time allegro developer, I think its wrong. And I'm not sure the others fully saw what the problem was.

AFAIK, it really should return one of the buffer's the ms its ready. not when more than one are.

To me it seems, the problem is not at all Allegro's API, but the implementation - in this case likely the OSX sound driver (or OSX mixer if it doesn't use the software mixer - I wouldn't know).

With the Alsa driver it works like this: Creating the audio stream allocate one Allegro SAMPLE, and plays it as a looping sample. The sample is cut into two halves. Now when you request an audio buffer, it will look which half is currently being played, and return the other half. If you now immediately request a buffer again, it will return NULL. Only when the last returned half starts being played, the now un-used other half is returned to the next request. So basically, you never can get a buffer returned two times consecutively. For this to work, it needs to be known which sample data Alsa is currently processing.. not sure right now if this is done by directly asking Alsa or just calculating the sample position from current time. Or maybe it even is advanced by a whole half-buffer.. should still work correctly even then.

Anyway, I believe now the distortion I was getting here is just this multiple-AY-channels-mixed issue, and has nothing to do with Allegro. exstream works perfectly at least.

Thomas Fjellstrom
Quote:

With the Alsa driver it works like this: Creating the audio stream allocate one Allegro SAMPLE, and plays it as a looping sample. The sample is cut into two halves. Now when you request an audio buffer, it will look which half is currently being played, and return the other half. If you now immediately request a buffer again, it will return NULL. Only when the last returned half starts being played, the now un-used other half is returned to the next request. So basically, you never can get a buffer returned two times consecutively. For this to work, it needs to be known which sample data Alsa is currently processing.. not sure right now if this is done by directly asking Alsa or just calculating the sample position from current time. Or maybe it even is advanced by a whole half-buffer.. should still work correctly even then.

Has that changed since I coded it? I recall having it not be in half. it was split up based on the buffer size requested in the config, and then using the alsa config for the buffer sizes... So you could easily have 16 buffers of 1/16th a second, or 1/32 a second or whatever.

Thomas Harte
Quote:

To me it seems, the problem is not at all Allegro's API, but the implementation - in this case likely the OSX sound driver (or OSX mixer if it doesn't use the software mixer - I wouldn't know).

It'll be more the Windows driver, not the OS X driver - my test program on OS X returns buffers in groups of two, but on Windows it returns them in groups of six. Irrespective of this, I think I'll take the opportunity now to register my opinion that the API should be changed for the new Allegro API. Having a callback function, ala SDL, just makes a lot more sense to me, even if it means you really need to implement some sort of mutex/whatever support. Or at least add a framework by which you can say "create me an AUDIOSTREAM then just tell me what buffer size works for you".

Quote:

Anyway, I believe now the distortion I was getting here is just this multiple-AY-channels-mixed issue, and has nothing to do with Allegro. exstream works perfectly at least.

I still wouldn't rule out the RetroHack code. I'm going to keep looking at it.

Thomas Fjellstrom
Quote:

Irrespective of this, I think I'll take the opportunity now to register my opinion that the API should be changed for the new Allegro API.

The audio bits of allegro 5 haven't even really been planned out yet. Now would be a great time to start ;)

Elias

Hm, yes, there can be more than two buffers apparently - not really sure why. But Allegro always expects you to fill a buffer of the given buffer size, so this should not be of concern to the end user.. should still be perfectly fine not immediately filling all the future buffers as long as no overrun occurs.

For 44100 Hz sound frequency and 50 Hz get_audio_stream_buffer call frequency, the minimum buffer size would be 44100/50=882 samples. So 1024 should work fine - I'll try investigate why 2048 seemed the minimum to work properly for exstream.

Thomas Fjellstrom

alsa and oss have the idea of "fragments", and you can specify the size and number of them that you want, so you can configure the amount of latency and whatnot that your app can stand. Which should technically be separate from the AUDIOSTREAM handling if AUDIOSTREAM really is just a SAMPLE... needs some looking into.

Thomas Harte
Quote:

Hm, yes, there can be more than two buffers apparently - not really sure why. But Allegro always expects you to fill a buffer of the given buffer size, so this should not be of concern to the end user.. should still be perfectly fine not immediately filling all the future buffers as long as no overrun occurs.

While that's true, a result of the Allegro API is that there's no way to (a) find out how many free buffers are available; or, more vitally, (b) find out how long it'll be until the buffer you've just received will be played.

Imagine you start and you know you haven't filled any audio yet. A buffer is available so you fill it. Another is available, but you know you don't have to fill it now because you just filled one. How do you know when you need to fill it by? The answer is that you don't. So logically you can't avoid the sort of latency problems we're discussing here.

Conversely, if a buffer was only freed when the one immediately before it was being played then you'd know something - that it needed to be filled in less time than it takes to play the buffer. So you can be pretty good with latency if you're using small buffers.

P.s. how about this for a radical Allegro 5.x suggestion: no sound code. Just build it on OpenAL.

Thomas Fjellstrom
Quote:

P.s. how about this for a radical Allegro 5.x suggestion: no sound code. Just build it on OpenAL.

Thats been suggested. But OpenAL is incomplete at best itself.

One of the original ideas was to have a kick ass api supporting true surround, and positioning. OpenAL doesn't seem to do surround, just positioning.

Elias

Yes, I'm seeing the problem now. So, from just the API view, I'd say it's simple: Always fill only the buffer which is returned. As long as it is big enough (e.g. 44100 / 50 samples plus some space for jitter, if you know you will roughly update 50 times a second), just filling one buffer a time never can cause problems - it will take at least that long to play, and so you are certain to fill the next buffer before it runs out.

Thomas Harte
Quote:

I'd say it's simple: Always fill only the buffer which is returned.

So then you need to be doing explicit timing of your own to second guess things that are well known within Allegro's audio subsystem and just not exposed? That strikes me as a very poor solution given the well-known unreliable and parlous nature of Allegro's timing mechanisms.

Being "reasonably close" in your guesses will never be good enough. Imagine if I ask for a buffer size that is 1024 bytes, but I'm curious as to whether I need to fill a new one every 1023 bytes of sample time. I fill one, I wait, I see if I can fill another. I can so I do. Now I'm 1 sample ahead. On Windows, on my machine, I continue getting ahead until I am at least 6 buffers ahead because that's the first time that Allegro will actually refuse to give me a new buffer. And the only information I can get from Allegro is it either offering me a new buffer or refusing to offer me a new buffer.

EDIT:

Quote:

(e.g. 44100 / 50 samples plus some space for jitter, if you know you will roughly update 50 times a second),

Amongst other things, the manual says "The length should normally be (but doesn't have to be) a power of 2", now you're suggesting that what the manual recommends is actually not recommended?

Elias
Quote:

So then you need to be doing explicit timing of your own to second guess things that are well known within Allegro's audio subsystem and just not exposed? That strikes me as a very poor solution given the well-known unreliable and parlous nature of Allegro's timing mechanisms.

The actual play position should be available in the voices code, but I never looked into that much. Basically, audio streams just are a wrapper on top of SAMPLE and VOICE.

Quote:

Being "reasonably close" in your guesses will never be good enough. Imagine if I ask for a buffer size that is 1024 bytes, but I'm curious as to whether I need to fill a new one every 1023 bytes of sample time. I fill one, I wait, I see if I can fill another. I can so I do. Now I'm 1 sample ahead. On Windows, on my machine, I continue getting ahead until I am at least 6 buffers ahead because that's the first time that Allegro will actually refuse to give me a new buffer. And the only information I can get from Allegro is it either offering me a new buffer or refusing to offer me a new buffer.

The solution to this would be to have Allegro choose a buffer size for you, but I think that would be difficult, as it depends on a lot of things. When you know you are not doing any disk operations or whatever might cause the kernel to schedule out your code for too long, a tight buffer size could work. If you're just concerned about sound quality but not delay, a bigger buffer size works. Hence Allegro simply lets you specify the size.. anything obvious I'm overlooking?

[EDIT:] Ah, of course, I was.. if you fill only one buffer each time, you get more and more ahead if there's more than 2. So as I think I already said, not sure why there ever are more than 2 buffers. But with only two buffers, it should be ok, right?

[EDIT2:] I.e. my interpretion is something like this.. you call the buffer function roughly with 50 Hz, so every 20 ms. Your buffer is some power of two. At point 0, you fill buffer A, and the sound starts playing.. then if you fill one buffer each time, all that happens is that sometimes there will be no buffer returned. Also if you call it more often. Just if you call not often enough, there will of course be overruns.

         0     20    40    60    80    100   120   140
call:    |A    |B    |A    |B    |A    |-    |B    |A    
buffers: [ A    ][ B    ][ A    ][ B    ][ A    ][ B    ]

        0      20    40    60    80    100   120   140
call:    |A |B |- |A |- |- |B |- |A |- |- |B |- |- |A |    
buffers: [ A    ][ B    ][ A    ][ B    ][ A    ][ B    ]

Quote:

Amongst other things, the manual says "The length should normally be (but doesn't have to be) a power of 2", now you're suggesting that what the manual recommends is actually not recommended?

Well, use the next higher power of two? So 1024. But here, with 1024, I still get occasional overruns, so 2048 is the best (which means 46 ms of delay before the last data in the buffer reach the underlying system, in my case Alsa).

Thomas Harte
Quote:

Well, use the next higher power of two? So 1024. But here, with 1024, I still get occasional overruns, so 2048 is the best (which means 46 ms of delay before the last data in the buffer reach the underlying system, in my case Alsa).

I was referring to your suggestion that if I'm already synchronising myself to a 50 Hz beat then I can usurp Allegro's opaque internal sample timing by starting an audio stream with a 44100 / 50 (or whatever) sample length buffer and only requesting a new buffer when I know I'm time synchronised from some other clock. Obviously I can either follow that earlier suggestion, to try and guess close to my play position, or follow this new one and have Allegro be less likely to do whatever the manual is warning may happen.

EDIT: obviously there would never be a problem (other than the usual gross inefficiencies associated with polling for real time events) if the audio stream code kept exactly two buffers internally.

Thomas Fjellstrom

You could just skip AUDIOSTREAM and handle it yourself.

Elias

Hm, in fact, it does not look to me like it can use more than two buffers:

http://alleg.svn.sourceforge.net/viewvc/alleg/allegro/branches/4.3.10plus/src/stream.c?revision=8101&view=markup

http://alleg.svn.sourceforge.net/viewvc/alleg/allegro/branches/4.3.10plus/include/allegro/stream.h?revision=8101&view=markup

It seems a SAMPLE can consist of multiple buffers, which is what this code handles and is somewhat confusing.. but the user only ever gets returned one half or the other - at least after another quick glance now.

Thomas Harte
Quote:

You could just skip AUDIOSTREAM and handle it yourself.

I intend to look into exactly that when I next get a chance. I hadn't registered the existence of voice_get_position. Seems a bit perverse when this is what AUDIOSTREAMS are for.

EDIT:

Quote:

Hm, in fact, it does not look to me like it can use more than two buffers:

Then explain the results of the small sample code in this thread.

Elias
Quote:

Then explain the results of the small sample code in this thread.

Yes, I agree now, the 6 seems wrong. Even 2 should only happen at the very start. But likely I'm mis-interpreting stream.c somehow - since I don't see what good it would be splitting the sample into multiple buffers in any case, whether with more than 2 user buffers or not, just never seems to be an advantage. To quote #allegro from a bit earlier:

Quote:

<elias> hm, i don't get allegro's audiostreams code
<elias> wonder what Shawn was thinking when he made all those buffers.. :P
<Sevalecan> "hic"

Paul Pridham

PortAudio seems to be a good portable streaming audio library: http://www.portaudio.com/

I've seen it used in a project or two, and the results were quite acceptable. Perhaps we can either see how they are doing it, or adapt it for Allegro 5. The license is pretty liberal.

Thomas Harte

Further to the question of low latency audio with the RetroHack simulation library, does anybody care to try the new test version attached to this post? It's main claim to fame is that it dumps AUDIOSTREAMS in favour of doing its own stuff in the SAMPLE structure with an allocated voice.

EDIT: okay, I'm aware of an integer that overflows after about 3 minutes of play. I'll fix that. But I could still do with some feedback on latency and quality of sound for the first three minutes!

EDIT2: that bug is fixed. New version is attached (get V12Test.zip rather than Archive.zip). Feedback is still sought.

Jakub Wasilewski
Quote:

okay, I'm aware of an integer that overflows after about 3 minutes of play. I'll fix that. But I could still do with some feedback on latency and quality of sound for the first three minutes!

So that's what's causing it! And here I was looking for the overflowing counter on my side ;). Should have posted about it I guess - but it didn't seem to do me any good when I posted about the #include <allegro.h> and C++ issue :P. (Just kidding, it was easy to overlook in a rather longish post).

Anyway, I'm not having any time at all lately, so I might not be able to finish with all the others - but I will surely wrap up the game in the following week and post it anyways. It's just too much fun coding for a constrained machine (one can really flex his/hers programming muscles), and thanks to those bugs we have added realism (computers often had their own bugs, but those were rather hard to fix on the spot) :-).

Thomas Harte
Quote:

Should have posted about it I guess - but it didn't seem to do me any good when I posted about the #include <allegro.h> and C++ issue

That wasn't ignored - check out the placing of #include <allegro.h> in both of the test versions of the 1.2 library, attached to my most recent previous post.

If nobody else comments then I'll assume 1.2 is good to go (subject to one additional latency decrease I've thought of while at work) and release it as soon as possible. I think pushing fixes out now is more time dependant than it was earlier in the competition.

Paul Pridham

Thomas, I'd love to test out your change, but won't be able to get to it 'til tonight sometime. I appreciate your efforts.

Elias

I just tested here, and now I get a perfect square wave in my earlier example - so that distortion also was fixed by your change. Also in the game I can't here distortion any longer, and still no overruns or audible delay - so very nice :)

Thomas Harte
Quote:

Also in the game I can't here distortion any longer, and still no overruns or audible delay - so very nice

That's good news. I guess the latency problems were, as I alleged, all in Allegro's AUDIOSTREAMs not matching their documentation. And the "sound going wrong after 3 minutes" was all mine.

Any chance of also trying the code attached to this post? It should reduce latency within the RetroHack code to a maximum of about 60ms (versus ~93ms in the test version 1.2 from last night). After that it's up to Allegro.

Elias

Still works here. [edit:] But then, what would be interesting is, how does it affect Windows - the distortion I got here in Linux with multiple AY buffers likely was unrelated to the audio streams code.

Paul Pridham

Thomas, I just tried the latest version under Win2K, and the sound is much better now. Latency is hardly noticeable, and there was no skipping in Elias's crazy "boot" screen anymore.

Could the fix be patched into Allegro?

Thomas Harte

Okay then, the new code is version 1.2 of the RetroHack simulation library. The only difference between that code and the one linked via my post above is that I've incremented the version number in the header — though I don't suppose that makes any odds since I've not really told anyone that the version numbers are there...

Quote:

Could the fix be patched into Allegro?

It could, but it's so extremely trivial to set up a voice/SAMPLE combo to do the same thing as AUDIOSTREAMS but without the "6 buffers at once" broken functionality that I assume once Elias works out why the code doesn't just work in this way (which'd be about 50 lines of code in total) in general then there'll turn out to be some significant reason or another.

Elias

Well, I don't have Windows so hard for me to test it. Basically, if someone with Windows could try replacing this in stream.c:

   if (len >= i)
      bufcount = 1;
   else
      bufcount = (i + len-1) / len;

with this:

   bufcount = 1;

And confirm audio streams still work, then we could commit that change.

Jakub Wasilewski
Quote:

Well, I don't have Windows so hard for me to test it [...]

I used the Retrohack library itself to test if AUDIOSTREAMs still work, didn't really have time to whip up my own example.

There are minor problems with palyback after making the change indicated - once in a while (3, maybe 4 times in a minute, but not at any regular intervals) you can distinctly hear the audio looping, as if the buffer wasn't properly filled so the same data was played twice or thrice.

There are no such problems when using standard Allegro 4.2.1.

That's WinXP SP 2 + Allegro 4.2.1.

Elias

Hm, with which version of RH was that test? And does RH 1.2 work without problems?

Jakub Wasilewski

I only now checked out the 1.2 Thomas posted. The only difference between them is the volume of the sound produced - 1.2 is significantly louder.

My results are:

RH 1.1 + vanilla 4.2.1 = normal sound
RH 1.1 + patched 4.2.1 = quirky sound with momentary repeats. Sometimes this gets so severe that it makes the distortion really severe, as if it was playing half of the buffers it got or something.

RH 1.2 = louder sound than in RH 1.1, otherwise perfect with both versions of Allegro (patched and vanilla).

The distortions for the patched versions seem to increase in severity when CPU load rises for a moment (even minor things like an IM notification popping up on the tray is enough).

Thread #593696. Printed from Allegro.cc