Split this file from alcaro/minir.

This commit is contained in:
Alcaro 2014-09-21 17:51:54 +02:00
parent ed11b1ffd5
commit 1a123402ab

207
playwav.c Normal file
View File

@ -0,0 +1,207 @@
#include "libretro.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
//NOTE: This core does not work on big endian systems.
#define BUFSIZE 128
#define AMP_MUL 64
retro_environment_t environ_cb = NULL;
retro_video_refresh_t video_cb = NULL;
retro_audio_sample_t audio_cb = NULL;
retro_audio_sample_batch_t audio_batch_cb = NULL;
retro_input_poll_t poller_cb = NULL;
retro_input_state_t input_state_cb = NULL;
#ifndef EXTERNC
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
#endif
#ifndef EXPORT
#if defined(CPPCLI)
#define EXPORT EXTERNC
#elif defined(_WIN32)
#define EXPORT EXTERNC __declspec(dllexport)
#else
#define EXPORT EXTERNC __attribute__((visibility("default")))
#endif
#endif
struct WAVhead {
char ChunkID[4];
uint32_t ChunkSize;
char Format[4];
char Subchunk1ID[4];
uint32_t Subchunk1Size;
uint16_t AudioFormat;
uint16_t NumChannels;
uint32_t SampleRate;
uint32_t ByteRate;
uint16_t BlockAlign;
uint16_t BitsPerSample;
char Subchunk2ID[4];
uint32_t Subchunk2Size;
} head;
unsigned int bytes_per_sample;
void* rawsamples;
unsigned int sample_pos;
unsigned int samples_tot;
unsigned int g_samples_to_play;
unsigned int sample_rate;
enum { st_off, st_on, st_auto } state;
#include<stdio.h>
static void emit_audio()
{
unsigned int samples_to_play;
if (state==st_off) return;
if (state==st_on) samples_to_play=BUFSIZE;
if (state==st_auto) samples_to_play=g_samples_to_play;//no locking here, despite threading; if we touch this variable, threading is off.
unsigned int samples_played=0;
while (samples_to_play >= BUFSIZE)
{
unsigned int samples_to_read=samples_to_play;
if (samples_to_read > BUFSIZE) samples_to_read=BUFSIZE;
if (sample_pos > samples_tot) sample_pos = samples_tot;
if (sample_pos + samples_to_read > samples_tot) samples_to_read=samples_tot-sample_pos;
int16_t samples[2*BUFSIZE];
if (samples_to_read != 0)
{
uint8_t* rawsamples8=(uint8_t*)rawsamples + bytes_per_sample*sample_pos;
int16_t* rawsamples16=(int16_t*)rawsamples8;
for (unsigned int i=0;i<samples_to_read;i++)
{
int16_t left;
int16_t right;
if (head.NumChannels==1 && head.BitsPerSample==8) { left=right=rawsamples8[i]*AMP_MUL; }
if (head.NumChannels==2 && head.BitsPerSample==8) { left=rawsamples8[i*2]*AMP_MUL; right=rawsamples8[i*2+1]*AMP_MUL; }
if (head.NumChannels==1 && head.BitsPerSample==16) { left=right=rawsamples16[i]; }
if (head.NumChannels==2 && head.BitsPerSample==16) { left=rawsamples16[i*2]; right=rawsamples16[i*2+1]; }
samples[i*2+0]=left;
samples[i*2+1]=right;
}
}
if (samples_to_read!=BUFSIZE) memset(samples+samples_to_read*2, 0, sizeof(int16_t)*2*(BUFSIZE-samples_to_read));
unsigned int played = audio_batch_cb(samples, BUFSIZE);
sample_pos += played;
samples_played += played;
if (samples_to_play < played) break;
samples_to_play -= played;
if (played != BUFSIZE) break;
}
if (state==st_auto) g_samples_to_play-=samples_played;
}
static void enable_audio(bool enabled) { state=enabled; }
EXPORT void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
EXPORT void retro_set_audio_sample(retro_audio_sample_t cb) { audio_cb = cb; }
EXPORT void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; }
EXPORT void retro_set_input_poll(retro_input_poll_t cb) { poller_cb = cb; }
EXPORT void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
EXPORT void retro_set_environment(retro_environment_t cb)
{
environ_cb=cb;
state=st_auto;
struct retro_audio_callback aud={ emit_audio, enable_audio };
if (environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, &aud)) state=st_off;
}
EXPORT void retro_init(void) { rawsamples=NULL; }
EXPORT void retro_deinit(void) {}
EXPORT unsigned retro_api_version(void) { return RETRO_API_VERSION; }
EXPORT void retro_get_system_info(struct retro_system_info* info)
{
const struct retro_system_info myinfo={ "WAV player", "v1", "wav", false, false };
memcpy(info, &myinfo, sizeof(myinfo));
}
EXPORT void retro_get_system_av_info(struct retro_system_av_info* info)
{
const struct retro_system_av_info myinfo={
{ 320, 240, 320, 240, 0.0 },
{ 60.0, head.SampleRate }
};
memcpy(info, &myinfo, sizeof(myinfo));
}
EXPORT void retro_set_controller_port_device(unsigned port, unsigned device) {}
EXPORT void retro_reset(void) { sample_pos=0; g_samples_to_play=0; }
EXPORT void retro_run(void)
{
poller_cb();//why is this needed
if (state==st_auto)
{
g_samples_to_play+=head.SampleRate/60.0;
emit_audio();
}
static uint16_t pixels[240][320];
memset(pixels, 0xFF, sizeof(pixels));
unsigned int x=320*sample_pos/samples_tot;
if (x<320)
{
for (unsigned int y=0;y<240;y++)
{
pixels[y][x]=0x0000;
}
}
video_cb(pixels, 320, 240, sizeof(uint16_t)*320);
}
EXPORT size_t retro_serialize_size(void) { return sizeof(sample_pos); }
EXPORT bool retro_serialize(void* data, size_t size) { memcpy(data, &sample_pos, sizeof(sample_pos)); return true; }
EXPORT bool retro_unserialize(const void* data, size_t size) { memcpy(&sample_pos, data, sizeof(sample_pos)); return true; }
EXPORT void retro_cheat_reset(void) {}
EXPORT void retro_cheat_set(unsigned index, bool enabled, const char* code) {}
EXPORT bool retro_load_game(const struct retro_game_info* game)
{
retro_reset();
free(rawsamples);
if (game->size < 44) return false;
memcpy(&head, game->data, 44);
if (game->size != 44+head.Subchunk2Size) return false;
if (head.NumChannels!=1 && head.NumChannels!=2) return false;
if (head.BitsPerSample!=8 && head.BitsPerSample!=16) return false;
bytes_per_sample = head.NumChannels*head.BitsPerSample/8;
samples_tot = head.Subchunk2Size/bytes_per_sample;
rawsamples=malloc(head.Subchunk2Size);
int16_t * rawsamples16=(int16_t*)rawsamples;
memcpy(rawsamples, (uint8_t*)game->data+44, game->size-44);
enum retro_pixel_format rgb565=RETRO_PIXEL_FORMAT_RGB565;
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565)) return false;
return true;
}
EXPORT bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info, size_t num_info) { return false; }
EXPORT void retro_unload_game(void) { free(rawsamples); }
EXPORT unsigned retro_get_region(void) { return RETRO_REGION_NTSC; }
EXPORT void* retro_get_memory_data(unsigned id) { return NULL; }
EXPORT size_t retro_get_memory_size(unsigned id) { return 0; }