Author Topic: Lynx emulator  (Read 57742 times)

Spiller (OP)

  • *
  • Posts: 106
Lynx emulator
« on: October 17, 2009, 08:41:54 am »
I have been working on porting a Lynx emulator to the native firmware. For this I took the flatmush astrolander sources and extended them to support C++ and the linux toolchain. I am planning on releasing both the SDK and the Lynx emulator sources in a few weeks.

I have a working prototype of the emulator since yesterday. Sound is still a challenge though. Anyone working with the flatmush sources able to provide some pointers on how to handle the sound? The entry.a lib exports some pcm_ functions but I have no clue how to use them.
« Last Edit: October 17, 2009, 08:45:29 am by Spiller »

alekmaul

  • *
  • Posts: 330
    • Portabledev
Re: Lynx emulator
« Reply #1 on: October 17, 2009, 09:24:45 am »
I made threading model to play sound for dingoo os native.
Don't use pcm_xxx functions, they are bad for dingoo os native.
Just take a look at that, it's a320_sound.c file :
Code: [Select]
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include "../../lib/ucos2.h"

#include "a320_snd.h"

typedef void waveout_inst;

typedef struct {
unsigned int sample_rate;
unsigned short format;
unsigned char channel;
unsigned char volume;
} waveout_args;


waveout_inst *_audio_music = NULL;
waveout_args tempArgs = { A320SAMPLE_RATE, 16, 1, 20 };
  
#define  TASK_START_PRIO 5
#define  TASK_STK_SIZE   1024                      // Size of each task's stacks (# of WORDs)
#define  NO_TASKS        1                         // Number of identical tasks

OS_STK   TaskStk[NO_TASKS][TASK_STK_SIZE];          // Tasks stacks
OS_STK   TaskStartStk[TASK_STK_SIZE];
char     TaskData[NO_TASKS];                        // Parameters to pass to each task



static volatile int a320_sound_pausei;
static volatile int a320_audio_done;
static volatile int a320_sound_thread_exit;  // Flag to end wiz_sound_thread_play() thread
volatile int a320_curSound;

inline int a320_getCurSound()
{
  int curSnd=a320_curSound;  
  curSnd--; if (curSnd<0) curSnd+=16;
  return curSnd;
}

static signed short a320_sound_buf[SNDLENGTH];  // Sound buffer
signed short a320_sound_emu[SNDLENGTH];  // Sound buffer

void a320_sound_pause(int yes) { a320_sound_pausei=yes; }

void a320_new_sound_play(void *none) {
  signed short w;

  do {
    if (a320_sound_pausei == 0) {
      int k;
      unsigned char * bleh = (unsigned char *) a320_sound_buf;
      for (k = 0; k < SNDLENGTH; k++) {
        a320_sound_buf[k] = a320_sound_emu[k];
      }
      waveout_write(_audio_music, a320_sound_buf, SNDLENGTH);
      a320_audio_done=1;
}
    else
      OSTimeDly(1);
} while(a320_sound_thread_exit == 0); // Until the end of the sound thread
  
a320_sound_thread_exit=0;

  OSTaskDel(TASK_START_PRIO);
}

void a320_sound_thread_mute(void)
{
//memset(a320_sound_buf_tot,0,(SNDLENGTH*16*2));
}

void a320_sound_thread_stop(void)
{
  a320_sound_pausei = 1;
a320_sound_thread_exit=1;

a320_sound_thread_mute();
}

void a320_sound_wait(void)
{
while (!a320_audio_done)
OSTimeDly(4);
  a320_audio_done = 0;
}


void a320_sound_init(void) {
  a320_sound_thread_exit=0;
  a320_sound_pausei = 1;
  a320_curSound = 0;
  a320_audio_done=1;

  _audio_music = waveout_open(&tempArgs);

 a320_sound_thread_mute();

  OSTaskCreate(a320_new_sound_play, (void *) 0, (void *)&TaskStartStk[TASK_STK_SIZE - 1], TASK_START_PRIO);
}

void a320_sound_stop(void) {
  a320_sound_thread_stop();

  while (a320_sound_thread_exit);  // to avoid pb with waveout_close -> can hang ??

  waveout_close(_audio_music);
}

and that is a320sound.h file :
Code: [Select]
#ifndef __a320_sound_h__
#define __a320_sound_h__

#define A320SAMPLE_RATE 48000
#define SNDLENGTH 4096

extern signed short a320_sound_emu[SNDLENGTH];  // Sound buffer


extern inline int a320_getCurSound();

extern volatile int curSound;
extern void *a320_sound_bufs[16];

#endif
You put these files in your src/lib directory (or where you want), you start threading model in your main file with a320_sound_init(); and you stop sound with a320_sound_stop(); just before exiting your main function.

You fill your buffer in a320_sound_emu buffer , this is the buffer that is copied in threading function to another buffer.

Also , i modified ucos2.h to have correct threading function prototype :
Code: [Select]
typedef unsigned int OS_STK;
extern uint8_t OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, uint8_t priority);

Hope it will help you.

edit:
Please use the code tags when pasting chunks of code, not quote tags, thanks :D mog
« Last Edit: October 19, 2009, 01:57:23 pm by omgmog »

Spiller (OP)

  • *
  • Posts: 106
Re: Lynx emulator
« Reply #2 on: October 17, 2009, 12:58:14 pm »
Thanks!

capt_bugaloo

  • *
  • Posts: 91
Re: Lynx emulator
« Reply #3 on: October 17, 2009, 05:06:44 pm »
I have been working on porting a Lynx emulator to the native firmware.
Aw man - the Atari Lynx is one of my favorite consoles of all time.  I own one now with about 35 carts.
If you are able to port a working emulator, especially for native, you will be my hero!   ;D

Spiller (OP)

  • *
  • Posts: 106
Re: Lynx emulator
« Reply #4 on: October 18, 2009, 06:33:17 pm »
Still working on this. First sound implemented thanks to Alekmaul. I hope to fix the first beta in a couple of days.

alekmaul

  • *
  • Posts: 330
    • Portabledev
Re: Lynx emulator
« Reply #5 on: October 18, 2009, 07:38:49 pm »
If you need help for a menu or something else, just tell me, i can help you.
I have a lynx (first version and still alive ^^) and i LOVE this console !!!

Spiller (OP)

  • *
  • Posts: 106
Re: Lynx emulator
« Reply #6 on: October 19, 2009, 08:58:44 am »
Current state is working and playing many roms. Remaining problems:

- Sound is not 100%. Working on this.
- Dingoo is sometimes locked up when starting the emulator. No clue yet.
- Lynx virtual machine is sometimes locked up when starting a game. No clue yet.
- Load and save state functionality is there, but not accessible from the menu yet.

alekmaul

  • *
  • Posts: 330
    • Portabledev
Re: Lynx emulator
« Reply #7 on: October 19, 2009, 09:09:53 am »
If Dingoo locks, it's perhaps an alignment problem.
Try to use -Wcast-align in your CC options to see if something can be misaligned and can lock the console.

Goon8

  • Guest
Re: Lynx emulator
« Reply #8 on: October 19, 2009, 09:18:32 am »
OMG the Atari Lynx.. I almost completely forgot about this console! EDIT: I REALLY forgot how HUGE this thing was! 6 AA battery's!

http://www.gametrailers.com/user-movie/lynx-atari-system-commercial/48257

Absolutely. freakin'. awesome! Looking forward to playing some Lynx titles!  ;D

« Last Edit: October 19, 2009, 09:22:41 am by Goon »

Spiller (OP)

  • *
  • Posts: 106
Re: Lynx emulator
« Reply #9 on: October 19, 2009, 09:27:58 am »
Just been playing with the sound again. I'll explain the problem I'm trying to solve. The emulator uses two buffers, one where the Lynx writes its sound output (buffer1) and one in which (part of) the sound output is copied for the native system to be output (buffer2). To keep the two in sync there's a counter which counts the position where the Lynx is currently writing in buffer1 (bufferpos). When the sound thread comes along it copies the contents of buffer1 to buffer2 up until bufferpos. I'm not entirely sure but it looks like the original emulator always outputs the entire buffer2 to the sound device. It blocks the thread while writing.

I have above implemented for the Dingoo. The sound is recognizable, but quite bad still. I figured it doesn't make sense to output the complete buffer2 if only part of it was written to, so I'm trying to feed bufferpos to waveout_write. However when I do so there is no sound at all.

Do you know if waveout_write is blocking as well? Or does it return immediately? Can you think of any other way to keep the two buffers synchronized?

alekmaul

  • *
  • Posts: 330
    • Portabledev
Re: Lynx emulator
« Reply #10 on: October 19, 2009, 09:59:46 am »
Yes, waveout_write is blocking (it's the reason why we are using thread, to avoid blocking all the process).
I think the best thing is to fill the output buffer only when the frame is finished, to be sure that all is ok.

So, you have :
* A buffer (buffer1) to be fill during one frame
* A buffer (buffer2) in the thread where you fill it with buffer1

I think you should fill the buffers with the same number of bytes (for example 4096 or 2048), don't forget that you must use 44100 (or 48000) and 16 bits signed shorts.

I'm doing such thing in my emulators and you also have same thing in Gnuboy for dingoo os native.

Spiller (OP)

  • *
  • Posts: 106
Re: Lynx emulator
« Reply #11 on: October 19, 2009, 04:30:29 pm »
I finally got the sound to work! It appeared to be a simple sign problem. The two audio formats described in audio.h are:

Code: [Select]
/* Audio Sample Format */
#define AFMT_U8                 8
#define AFMT_S16_LE             16

It seems that both are signed however. Last thing to fix with the audio is the volume. It is way too low now. Tried both the volume parameter of waveout_open and waveout_set_volume...

capt_bugaloo

  • *
  • Posts: 91
Re: Lynx emulator
« Reply #12 on: October 20, 2009, 03:41:49 am »
Excellent!  I am really looking forward to this release...

alekmaul

  • *
  • Posts: 330
    • Portabledev
Re: Lynx emulator
« Reply #13 on: October 20, 2009, 05:25:39 am »
It seems that both are signed however. Last thing to fix with the audio is the volume. It is way too low now. Tried both the volume parameter of waveout_open and waveout_set_volume...
As i said in my previous post, use only 16 bits signed short values for sound.
About sound volume, just take a look at spoout, you have the soruce code and sample to change volume with X and Y :
Quote
        if (key_curr.status & CONTROL_BUTTON_X)  {
          if (!key_x_pressed) {
            sndLevel = sndLevel == 100 ? 0 : sndLevel + 10;
            waveout_set_volume(sndLevel>>1);         
            key_x_pressed = 1;
          }
        }
        else
          key_x_pressed  = 0;

        if (key_curr.status & CONTROL_BUTTON_Y)  {
          if (!key_y_pressed) {
            sndLevel = sndLevel == 0 ? 100 : sndLevel - 10;
            waveout_set_volume(sndLevel>>1);          
            key_y_pressed  = 1;
          }
        }
        else
          key_y_pressed  = 0;
I begin with sndLevel=40 (with values between 0 and 100) so we can go to 0..50 with volume, which is nice on dingoo

Spiller (OP)

  • *
  • Posts: 106
Re: Lynx emulator
« Reply #14 on: October 20, 2009, 08:47:58 am »
Thanks for the volume example. About the signed short thing: this emulator is using 22kHz 8 bit sound, which seems to be accepted fine by waveout_open and waveout_write but as said the volume is low. The waveout_set_volume example you gave me doesn't change this. I'll have a look to see if I can "upgrade" the sound system to 16 bit sound. :)

alekmaul

  • *
  • Posts: 330
    • Portabledev
Re: Lynx emulator
« Reply #15 on: October 20, 2009, 09:00:52 am »
Hum, i think you can try 44100hz instead of 22Khz.
To convert 8bits sounds to 16 bits, just take a look at gnuboy from joyrider, and you have the solution (it's in lib/sdl/sdl.c, in the threading function)  :
Quote
           
void a320_sound_thread_play(void *none)
{
    int teller = 0;
    int teller2 = 0;
    signed short w;
    do {
        if(a320_sound_paused == 0)
        {
            byte * bleh = (byte *) a320_sound_buffer;
            for (teller = 0; teller < SNDLEN>>1; teller++)
            {
                w = (uint16_t)((gb_sound_buffer[teller] - 128) << 8 );
                *bleh++ = w & 0xFF ;
                *bleh++ = w >> 8;
            }
        waveout_write(_audio_music, a320_sound_buffer, SNDLEN);
        audio_done = 1;
        }
        else
            OSTimeDly(1);
   } while(!a320_sound_thread_exit);
    a320_sound_thread_exit=0;
    OSTaskDel(TASK_START_PRIO);
}
In this code, gb_sound_buffer is the 8 bits buffer filled from the emu and a320_sound_buffer is the 16 bits signed buffer sent to wave_out

Spiller (OP)

  • *
  • Posts: 106
Re: Lynx emulator
« Reply #16 on: October 20, 2009, 09:16:05 pm »
First beta can be found here:

http://www.speedyshare.com/534817175.html

Place LynGOO.SIM together with lynxboot.img in your GAME folder and have fun with some LNX files!

This version still contains several glitches and load/save state is not implemented yet. You will have to google lynxboot.img as I'm not allowed to bundle it with the emulator.
« Last Edit: October 20, 2009, 09:30:25 pm by Spiller »

Chris23235

  • **
  • Posts: 603
Re: Lynx emulator
« Reply #17 on: October 20, 2009, 10:33:14 pm »
Hope you didn't mind I made a post in the release forum, tried Blue Lightning, runs great.

EDIT: I tried S.T.U.N. Runner, runs fantastic for a Beta, has slightly wrong colours sometimes and the screen flashes at the map screen. This game runs to slow on the original CPU Speed and to fast on 430 MHz. It would be great, if you cam implement a frame limiter.
« Last Edit: October 20, 2009, 10:42:37 pm by Chris23235 »

remax

  • Guest
Re: Lynx emulator
« Reply #18 on: October 20, 2009, 11:21:48 pm »
California Games runs great
Ninja Gaiden seems ok but i never played it
World Class Soccer is unplayable (there are big paquet of frame that are forgotten).

segakiki

  • *
  • Posts: 88
Re: Lynx emulator
« Reply #19 on: October 21, 2009, 12:23:39 am »
Its not working for me!
ive put the lyngoo.sim and the lynxboot.img file in the game folder and then created a lynx folder with all the unzipped .lnx files. nothing...
No File Found!
what am i doing wrong?
ive got firmware version 1.1

 

Post a new topic