/ MCUME_teensy41 / teensyhandy / wrapemu.cpp
wrapemu.cpp
  1  #include <stdio.h>
  2  #include <string.h>
  3  
  4  extern "C" {
  5  #include "emuapi.h"
  6  #include "platform_config.h"
  7  }
  8  #include <Arduino.h>
  9  #include "handy.h"
 10  
 11  
 12  // Emulation includes
 13  
 14  static CSystem *lynx = NULL;
 15  
 16  
 17  
 18  #define AUDIORPTRMASK (((AUDIO_BUFFER_LENGTH-1)<<8)+0xff)
 19  
 20  static ULONG sndbuffer[AUDIO_BUFFER_LENGTH]; // (short)(L<<16)+(short)R
 21  
 22  static long audioowptr = 0;
 23  static long audioorptr = 0;
 24  static long audiorptr  = 0;
 25  static long deltar     = 0;
 26  
 27    
 28  
 29  #define AVG_COUNT 16
 30  static int avgcounter = AVG_COUNT;
 31  static long avgr     = 0;
 32  static long avgw     = 0;
 33  static long inc      = 0;
 34  static long incdelta = 0;
 35  static long sndinc   = 0x100; // default read increment
 36  
 37  // distance between read and write buffer
 38  static long pdelta   = 0x1000;
 39  static bool pdown    = true; 
 40  
 41  
 42  static int dpad_mapped_up;
 43  static int dpad_mapped_down;
 44  static int dpad_mapped_left;
 45  static int dpad_mapped_right;
 46  
 47  #define DISPLAY_ROTATION_OFF   0
 48  #define DISPLAY_ROTATION_LEFT  1
 49  #define DISPLAY_ROTATION_RIGHT 2
 50  
 51  static int ik;    // joypad key
 52  static int pik=0; 
 53  
 54  static int ihk;   // I2C keyboard key
 55  static int iusbhk;// USB keyboard key
 56  
 57  void lnx_Input(int bClick) {
 58    ik  = emu_GetPad();
 59    ihk = emu_ReadI2CKeyboard();
 60  }
 61  
 62  void emu_KeyboardOnDown(int keymodifer, int key) {
 63    int keyCode = -1; //INV_KEY;
 64    if ((key >=0xc0) && (key <=0xdf)) {
 65      keyCode = ((key-0xc0) & 0x1f) + 0x7f;
 66    }
 67    else {
 68      keyCode = key & 0x7f;
 69    }
 70    
 71    //Serial.println(keyCode);
 72    
 73    if (keyCode != -1) {
 74      iusbhk = keyCode;
 75    }
 76  }
 77  
 78  void emu_KeyboardOnUp(int keymodifer, int key) {
 79    iusbhk = 0;
 80  }
 81  
 82  void lnx_Init(void)
 83  {
 84  }
 85  
 86  
 87  void lnx_Start(char * filename)
 88  {
 89    emu_printf("emu starting");
 90  
 91    lynx = new CSystem(filename, MIKIE_PIXEL_FORMAT_16BPP_565, HANDY_AUDIO_SAMPLE_FREQ);
 92    if (lynx->mFileType == HANDY_FILETYPE_ILLEGAL)
 93    {
 94        emu_printf("illegal");
 95        return;
 96    }
 97  
 98  //  gPrimaryFrameBuffer = (UBYTE*)(emu_SMalloc((HANDY_SCREEN_HEIGHT+1)*HANDY_SCREEN_STRIDE*sizeof(HandyPixel)));
 99    gPrimaryFrameBuffer = (UBYTE*)(emu_SMalloc((OUTPUT_SCREEN_HEIGHT)*OUTPUT_SCREEN_WIDTH*sizeof(HandyPixel)));
100    memset((void *)gPrimaryFrameBuffer, 0,(OUTPUT_SCREEN_HEIGHT)*OUTPUT_SCREEN_WIDTH*sizeof(HandyPixel));
101    gAudioBuffer = &sndbuffer[0];
102    memset(&sndbuffer[0], AUDIO_BUFFER_LENGTH*4,0);
103    gAudioEnabled = 1;
104    gAudioBufferPointer = AUDIO_BUFFER_LENGTH/2;
105  
106    int  rotation = DISPLAY_ROTATION_OFF;
107  
108    uint32_t crc32 = lynx->mCart->CRC32();
109    emu_printh(crc32);
110    switch (crc32)
111    {
112        case 0x97501709: // Centipede
113        case 0x0271B6E9: // Lexis
114        case 0x006FD398: // NFL Football
115        case 0x1D9EC645:
116        case 0xBCD10C3A: // Raiden
117            rotation = DISPLAY_ROTATION_LEFT;
118            break;
119        case 0x7F0EC7AD: // Gauntlet
120        case 0xAC564BAA: // Gauntlet - The Third Encounter
121        case 0xFE19F59F:
122        case 0xA53649F1: // Klax
123        case 0xB8C75C2C: // Klax      
124            rotation = DISPLAY_ROTATION_RIGHT;
125            break;
126        default:
127            if (lynx->mCart->CartGetRotate() == CART_ROTATE_LEFT)
128                rotation = DISPLAY_ROTATION_LEFT;
129            if (lynx->mCart->CartGetRotate() == CART_ROTATE_RIGHT)
130                rotation = DISPLAY_ROTATION_RIGHT;
131    }
132    switch(rotation)
133    {
134        case DISPLAY_ROTATION_LEFT:
135            lynx->mMikie->SetRotation(MIKIE_ROTATE_L);
136            dpad_mapped_up    = BUTTON_RIGHT;
137            dpad_mapped_down  = BUTTON_LEFT;
138            dpad_mapped_left  = BUTTON_UP;
139            dpad_mapped_right = BUTTON_DOWN;
140            break;
141        case DISPLAY_ROTATION_RIGHT:
142            lynx->mMikie->SetRotation(MIKIE_ROTATE_R);
143            dpad_mapped_up    = BUTTON_LEFT;
144            dpad_mapped_down  = BUTTON_RIGHT;
145            dpad_mapped_left  = BUTTON_DOWN;
146            dpad_mapped_right = BUTTON_UP;
147            break;
148        default:
149            lynx->mMikie->SetRotation(MIKIE_NO_ROTATE);
150            dpad_mapped_up    = BUTTON_UP;
151            dpad_mapped_down  = BUTTON_DOWN;
152            dpad_mapped_left  = BUTTON_LEFT;
153            dpad_mapped_right = BUTTON_RIGHT;
154            break;
155    }
156  
157  
158    emu_printf("emu started");
159  }
160  
161  void lnx_Step(void)
162  {
163    ULONG buttons = 0;
164  
165    int k=ik;
166  #ifdef TEECOMPUTER
167    int hk = ihk; 
168    if (hk == 'q') {
169      buttons |= BUTTON_OPT1;
170    }
171    if (hk == 'w') {
172      buttons |= BUTTON_OPT2;
173    }
174    if (hk == 'e') {
175      buttons |= BUTTON_PAUSE;
176    }
177  #endif      
178    if ( (k & MASK_JOY2_UP) || (k & MASK_JOY1_UP) )     buttons |= dpad_mapped_up;
179    if ( (k & MASK_JOY2_DOWN) || (k & MASK_JOY1_DOWN) )    buttons |= dpad_mapped_down;
180    if ( (k & MASK_JOY2_LEFT) || (k & MASK_JOY1_LEFT) )    buttons |= dpad_mapped_left;
181    if ( (k & MASK_JOY2_RIGHT) || (k & MASK_JOY1_RIGHT) )   buttons |= dpad_mapped_right;
182    if ( (k & MASK_JOY2_BTN) || (k & MASK_JOY1_BTN) )       buttons |= BUTTON_A;
183    if ( (k & MASK_KEY_USER1) ) buttons |= BUTTON_A;
184    if ( (k & MASK_KEY_USER2) ) buttons |= BUTTON_B;
185    if ( (k & MASK_KEY_USER3) ) buttons |= BUTTON_OPT1;
186  
187    lynx->SetButtonData(buttons);
188  
189    lynx->UpdateFrame(true);
190  
191    HandyPixel * buf = (HandyPixel *)gPrimaryFrameBuffer;
192    for (int j=0; j<OUTPUT_SCREEN_HEIGHT; j++) {
193      emu_DrawLine16(&buf[OUTPUT_SCREEN_STRIDE*j], OUTPUT_SCREEN_WIDTH, OUTPUT_SCREEN_HEIGHT, j);
194    }
195  
196    emu_DrawVsync();
197  
198    pik = k;
199  
200  
201    // #sample written per frame
202    long ptr = gAudioBufferPointer;
203    long wdelta = ptr - audioowptr;
204    if (wdelta < 0) wdelta = AUDIO_BUFFER_LENGTH+wdelta;
205    audioowptr = ptr; 
206  
207    // #sample read per frame
208    int rdelta = deltar;
209    deltar = 0;
210  
211   
212    // Compute average R/W over AVG_COUNT frame
213    avgcounter--;
214    avgw += wdelta;
215    avgr += rdelta;
216    inc = (wdelta<<8)/(rdelta);
217    if (avgcounter == 0) {
218      
219      wdelta = avgw/AVG_COUNT;
220      rdelta = avgr/AVG_COUNT;
221      avgw = 0;
222      avgr = 0;
223      avgcounter = AVG_COUNT;
224  
225      //emu_printi(wdelta);
226      //emu_printi(rdelta);
227  
228      long delta = ptr - audiorptr>>8;
229      if (delta < 0) delta = AUDIO_BUFFER_LENGTH+delta;
230  
231  
232      // we try to be keep read and write buffer at half distance of each other
233      bool down;
234      if (delta < pdelta)  {
235        down = true; // keep going down
236        if (delta < (AUDIO_BUFFER_LENGTH/2)) {
237          if ( (down) && (pdown) )
238            incdelta += 2; 
239          else
240            incdelta = 1;  
241        }
242      }
243      else if (delta > pdelta) {
244        down = false; // goes up again
245        if (delta > (AUDIO_BUFFER_LENGTH/2)) { 
246          if ( (!down) && (!pdown) )
247            incdelta -= 2; 
248          else
249            incdelta = -1;  
250        }
251      }
252      else {
253        incdelta = 0; 
254      }
255      // Hard reset sound buffer?
256      
257      if ( (delta < AUDIO_BUFFER_LENGTH/4) || (delta > (AUDIO_BUFFER_LENGTH-AUDIO_BUFFER_LENGTH/4)) ) {
258        /*
259        memset(sndbuffer,sizeof(sndbuffer),0);
260        gAudioBufferPointer = 0;
261        audioowptr = 0; 
262        audiorptr=(AUDIO_BUFFER_LENGTH/2)<<8;
263        delta = AUDIO_BUFFER_LENGTH/2;
264        */
265        //emu_printf("reset");        
266      }
267      
268      pdelta = delta;
269      pdown = down; 
270      //emu_printi(delta);     
271    }
272    //emu_printi(incdelta);     
273  
274    sndinc = inc+incdelta;
275  }
276  
277  
278  
279  
280  void SND_Process(void *stream, int len) {
281     
282      short * dst = (short*)stream;
283      
284      len = len >> 1;
285      for (int i=0;i<len;i++)
286      { 
287        ULONG val = sndbuffer[audiorptr>>8];
288        *dst++ = (val >> 16);
289        *dst++ = (val & 0xffff);
290        audiorptr += sndinc;
291        audiorptr &= AUDIORPTRMASK;       
292        deltar +=1;   
293      }
294  /*    
295      long pt = (gAudioBufferPointer) - len;
296      if (pt < 0) pt+=AUDIO_BUFFER_LENGTH;
297      for (int i=0;i<len;i++)
298      { 
299        ULONG val = sndbuffer[pt++];
300        *dst++ = (val >> 16);
301        *dst++ = (val & 0xffff);        
302        pt &= (AUDIO_BUFFER_LENGTH-1);
303      } 
304  */     
305  } 
306