Simplify sound and add windows instructions
This commit is contained in:
parent
f2c3b79c2d
commit
ef1a152983
71
docs/windows.md
Normal file
71
docs/windows.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# Windows Installation Instructions
|
||||||
|
|
||||||
|
Please note that this software is still in the alpha phase, and it's very unlikely any games will be fully playable.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Windows 10 build 2004 or higher
|
||||||
|
- WSL2
|
||||||
|
- Ubuntu 22.04
|
||||||
|
|
||||||
|
## Building & Installation
|
||||||
|
|
||||||
|
Launch Ubuntu 22.04 and and reset the root password.
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo passwd root
|
||||||
|
su root
|
||||||
|
```
|
||||||
|
|
||||||
|
Now that you're in the root user you can install the dependencies:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt update && apt list --upgradable && apt upgrade
|
||||||
|
sudo apt install wsl g++ mesa-utils cmake make-guile gcc-multilib xorg-dev libxmu6:i386 libstdc++5:i386 libopenal-dev:i386 freeglut3:i386 freeglut3-dev:i386 libglew-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you will need to build libalut (the audio library) from source:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone --recursive https://github.com/vancegroup/freealut.git
|
||||||
|
cd freealut
|
||||||
|
cmake . -DCMAKE_INSTALL_PREFIX:STRING="/usr" -DCMAKE_C_FLAGS:STRING="-m32 -O2"
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you should add yourself to the following groups.
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo addgroup $USER dialout
|
||||||
|
sudo addgroup $USER input
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can clone and build the lindbergh loader repository.
|
||||||
|
|
||||||
|
```
|
||||||
|
cd
|
||||||
|
git clone https://github.com/bobbydilley/lindbergh-loader.git
|
||||||
|
cd lindbergh-loader
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
You should then see the 3 .so files produced in the `build` directory.
|
||||||
|
|
||||||
|
## Launching a game
|
||||||
|
|
||||||
|
You should copy the 3 files from the `lindbergh-loader/build` directory to the directory with the game elf in.
|
||||||
|
|
||||||
|
Then open powershell in windows and do the following steps.
|
||||||
|
|
||||||
|
```
|
||||||
|
cd C:\rom\hod4\elf
|
||||||
|
bash
|
||||||
|
cp ~/lindbergh-loader/build/* .
|
||||||
|
LD_PRELOAD=lindbergh.so LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./hod4M.elf
|
||||||
|
```
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
|
Thanks to dorminirko for the testing and writing of the original guide.
|
@ -10,11 +10,12 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "segaapi.h"
|
#include "segaapi.h"
|
||||||
#include "tsf.h"
|
#include "tsf.h"
|
||||||
|
|
||||||
//#define DEBUG_OUTPUT
|
// #define DEBUG_OUTPUT
|
||||||
|
|
||||||
const GUID EAX_NULL_GUID;
|
const GUID EAX_NULL_GUID;
|
||||||
const GUID EAX_FREQUENCYSHIFTER_EFFECT;
|
const GUID EAX_FREQUENCYSHIFTER_EFFECT;
|
||||||
@ -78,122 +79,41 @@ void dbgPrint(const char *format, ...)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type)
|
/**
|
||||||
|
* Returns the OpenAL Format Enum from the sampleFormat and channels
|
||||||
|
* of the SEGA API.
|
||||||
|
*
|
||||||
|
* @param sampleFormat SEGA API Sample Format
|
||||||
|
* @param channels Amount of channels to use
|
||||||
|
* @returns The OpenAL Format
|
||||||
|
*/
|
||||||
|
ALenum getAlFormat(unsigned int sampleFormat, unsigned int channels)
|
||||||
{
|
{
|
||||||
switch (channels)
|
|
||||||
{
|
|
||||||
case AL_MONO_SOFT:
|
|
||||||
size *= 1;
|
|
||||||
break;
|
|
||||||
case AL_STEREO_SOFT:
|
|
||||||
size *= 2;
|
|
||||||
break;
|
|
||||||
case AL_REAR_SOFT:
|
|
||||||
size *= 2;
|
|
||||||
break;
|
|
||||||
case AL_QUAD_SOFT:
|
|
||||||
size *= 4;
|
|
||||||
break;
|
|
||||||
case AL_5POINT1_SOFT:
|
|
||||||
size *= 6;
|
|
||||||
break;
|
|
||||||
case AL_6POINT1_SOFT:
|
|
||||||
size *= 7;
|
|
||||||
break;
|
|
||||||
case AL_7POINT1_SOFT:
|
|
||||||
size *= 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case AL_BYTE_SOFT:
|
|
||||||
size *= sizeof(ALbyte);
|
|
||||||
break;
|
|
||||||
case AL_UNSIGNED_BYTE_SOFT:
|
|
||||||
size *= sizeof(ALubyte);
|
|
||||||
break;
|
|
||||||
case AL_SHORT_SOFT:
|
|
||||||
size *= sizeof(ALshort);
|
|
||||||
break;
|
|
||||||
case AL_UNSIGNED_SHORT_SOFT:
|
|
||||||
size *= sizeof(ALushort);
|
|
||||||
break;
|
|
||||||
case AL_INT_SOFT:
|
|
||||||
size *= sizeof(ALint);
|
|
||||||
break;
|
|
||||||
case AL_UNSIGNED_INT_SOFT:
|
|
||||||
size *= sizeof(ALuint);
|
|
||||||
break;
|
|
||||||
case AL_FLOAT_SOFT:
|
|
||||||
size *= sizeof(ALfloat);
|
|
||||||
break;
|
|
||||||
case AL_DOUBLE_SOFT:
|
|
||||||
size *= sizeof(ALdouble);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int bufferSampleSize(SEGAContext *context)
|
|
||||||
{
|
|
||||||
return context->channels * ((context->sampleFormat == SIGNED_16PCM) ? 2 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateBufferLoop(SEGAContext *context)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
if (context == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned int sampleSize = bufferSampleSize(context);
|
|
||||||
alSourcei(context->alSource, AL_BUFFER, AL_NONE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
FIXME: Re-enable, only crashed before - so fix this too..
|
|
||||||
ALint loopPoints[] = { buffer->startLoop / sampleSize, buffer->endLoop / sampleSize };
|
|
||||||
alBufferiv(buffer->alBuffer,AL_LOOP_POINTS_SOFT,loopPoints);
|
|
||||||
CHECK();
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateBufferData(SEGAContext *context, unsigned int offset, size_t length)
|
|
||||||
{
|
|
||||||
|
|
||||||
ALenum alFormat = -1;
|
ALenum alFormat = -1;
|
||||||
ALenum alChannels = -1;
|
|
||||||
ALenum alType;
|
|
||||||
|
|
||||||
switch (context->sampleFormat)
|
switch (sampleFormat)
|
||||||
{
|
{
|
||||||
case UNSIGNED_8PCM: /* Unsigned (offset 128) 8-bit PCM */
|
case UNSIGNED_8PCM: /* Unsigned (offset 128) 8-bit PCM */
|
||||||
alType = AL_BYTE_SOFT;
|
switch (channels)
|
||||||
switch (context->channels)
|
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
alFormat = AL_MONO8_SOFT;
|
alFormat = AL_MONO8_SOFT;
|
||||||
alChannels = AL_MONO_SOFT;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
alFormat = AL_STEREO8_SOFT;
|
alFormat = AL_STEREO8_SOFT;
|
||||||
alChannels = AL_STEREO_SOFT;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SIGNED_16PCM: /* Signed 16-bit PCM */
|
case SIGNED_16PCM: /* Signed 16-bit PCM */
|
||||||
alType = AL_SHORT_SOFT;
|
switch (channels)
|
||||||
switch (context->channels)
|
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
alFormat = AL_MONO16_SOFT;
|
alFormat = AL_MONO16_SOFT;
|
||||||
alChannels = AL_MONO_SOFT;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
alFormat = AL_STEREO16_SOFT;
|
alFormat = AL_STEREO16_SOFT;
|
||||||
alChannels = AL_STEREO_SOFT;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -204,31 +124,18 @@ static void updateBufferData(SEGAContext *context, unsigned int offset, size_t l
|
|||||||
|
|
||||||
if (alFormat == -1)
|
if (alFormat == -1)
|
||||||
{
|
{
|
||||||
printf("SEGAAPI: Unknown format! 0x%X with %u channels!\n", context->sampleFormat, context->channels);
|
printf("SEGAAPI Fatal Error: Unknown format - 0x%X with %d channels!\n", sampleFormat, channels);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset != -1)
|
return alFormat;
|
||||||
{
|
}
|
||||||
|
|
||||||
unsigned int sampleSize = bufferSampleSize(context);
|
|
||||||
|
|
||||||
ALint position;
|
|
||||||
alGetSourcei(context->alSource, AL_SAMPLE_OFFSET, &position);
|
|
||||||
|
|
||||||
alSourcei(context->alSource, AL_BUFFER, AL_NONE);
|
|
||||||
// alBufferData(context->alBuffer, alFormat, context->data + (offset / sampleSize), FramesToBytes(context->size / bufferSampleSize(context), alChannels, alType), context->sampleRate);
|
|
||||||
alBufferData(context->alBuffer, alFormat, context->data, FramesToBytes(context->size / bufferSampleSize(context), alChannels, alType), context->sampleRate);
|
|
||||||
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
|
||||||
alSourcei(context->alSource, AL_SAMPLE_OFFSET, position);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static void updateBufferData(SEGAContext *context, unsigned int offset, size_t length)
|
||||||
|
{
|
||||||
alSourcei(context->alSource, AL_BUFFER, AL_NONE);
|
alSourcei(context->alSource, AL_BUFFER, AL_NONE);
|
||||||
alBufferData(context->alBuffer, alFormat, context->data, FramesToBytes(context->size / bufferSampleSize(context), alChannels, alType), context->sampleRate);
|
alBufferData(context->alBuffer, getAlFormat(context->sampleFormat, context->channels), context->data, context->size, context->sampleRate);
|
||||||
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
||||||
|
|
||||||
// updateBufferLoop(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resetBuffer(SEGAContext *context)
|
static void resetBuffer(SEGAContext *context)
|
||||||
@ -253,12 +160,10 @@ static void resetBuffer(SEGAContext *context)
|
|||||||
TSF_MEMSET(res, 0, sizeof(tsf));
|
TSF_MEMSET(res, 0, sizeof(tsf));
|
||||||
res->presetNum = 0;
|
res->presetNum = 0;
|
||||||
res->outSampleRate = context->sampleRate;
|
res->outSampleRate = context->sampleRate;
|
||||||
|
|
||||||
context->synth = res;
|
context->synth = res;
|
||||||
|
|
||||||
struct tsf_region *region = malloc(sizeof(struct tsf_region));
|
struct tsf_region *region = malloc(sizeof(struct tsf_region));
|
||||||
memset(region, 0, sizeof(struct tsf_region));
|
memset(region, 0, sizeof(struct tsf_region));
|
||||||
|
|
||||||
tsf_region_clear(region, 0);
|
tsf_region_clear(region, 0);
|
||||||
|
|
||||||
region->ampenv.delay = 0;
|
region->ampenv.delay = 0;
|
||||||
@ -270,9 +175,9 @@ static void resetBuffer(SEGAContext *context)
|
|||||||
|
|
||||||
context->region = region;
|
context->region = region;
|
||||||
|
|
||||||
// * - Buffer is in the stop state.
|
alSourcei(context->alSource, AL_BUFFER, AL_NONE);
|
||||||
// * - Play position is set to 0.
|
alSourcei(context->alSource, AL_BYTE_OFFSET, 0);
|
||||||
updateBufferData(context, -1, -1);
|
alSourceStop(context->alSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SEGAAPI_Play(void *hHandle)
|
int SEGAAPI_Play(void *hHandle)
|
||||||
@ -280,23 +185,26 @@ int SEGAAPI_Play(void *hHandle)
|
|||||||
dbgPrint("SEGAAPI_Play() 0x%x", hHandle);
|
dbgPrint("SEGAAPI_Play() 0x%x", hHandle);
|
||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
|
|
||||||
if (context == NULL)
|
if (context == NULL)
|
||||||
return SEGA_ERROR_BAD_PARAM;
|
return SEGA_ERROR_BAD_PARAM;
|
||||||
|
|
||||||
// alSourcei(context->alSource, AL_LOOPING, context->loop ? AL_TRUE : AL_FALSE);
|
|
||||||
alSourcei(context->alSource, AL_LOOPING, AL_FALSE);
|
|
||||||
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
|
||||||
alSourcePlay(context->alSource);
|
alSourcePlay(context->alSource);
|
||||||
|
|
||||||
return SEGA_SUCCESS;
|
return SEGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SEGAAPI_Pause(void *hHandle)
|
int SEGAAPI_Pause(void *hHandle)
|
||||||
{
|
{
|
||||||
dbgPrint("SEGAAPI_Pause() 0x%x", hHandle);
|
dbgPrint("SEGAAPI_Pause() 0x%x", hHandle);
|
||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
|
|
||||||
if (context == NULL)
|
if (context == NULL)
|
||||||
return SEGA_ERROR_BAD_PARAM;
|
return SEGA_ERROR_BAD_PARAM;
|
||||||
|
|
||||||
alSourcePause(context->alSource);
|
alSourcePause(context->alSource);
|
||||||
|
|
||||||
return SEGA_SUCCESS;
|
return SEGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,6 +213,7 @@ int SEGAAPI_Stop(void *hHandle)
|
|||||||
dbgPrint("SEGAAPI_Stop() 0x%x", hHandle);
|
dbgPrint("SEGAAPI_Stop() 0x%x", hHandle);
|
||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
|
|
||||||
if (context == NULL)
|
if (context == NULL)
|
||||||
return SEGA_ERROR_BAD_PARAM;
|
return SEGA_ERROR_BAD_PARAM;
|
||||||
|
|
||||||
@ -316,12 +225,14 @@ int SEGAAPI_Stop(void *hHandle)
|
|||||||
int SEGAAPI_PlayWithSetup(void *hHandle)
|
int SEGAAPI_PlayWithSetup(void *hHandle)
|
||||||
{
|
{
|
||||||
dbgPrint("SEGAAPI_PlayWithSetup() 0x%x", hHandle);
|
dbgPrint("SEGAAPI_PlayWithSetup() 0x%x", hHandle);
|
||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
|
|
||||||
if (context == NULL)
|
if (context == NULL)
|
||||||
return SEGA_ERROR_BAD_PARAM;
|
return SEGA_ERROR_BAD_PARAM;
|
||||||
alSourcei(context->alSource, AL_LOOPING, context->loop ? AL_TRUE : AL_FALSE);
|
|
||||||
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
|
||||||
alSourcePlay(context->alSource);
|
alSourcePlay(context->alSource);
|
||||||
|
|
||||||
return SEGA_ERROR_UNSUPPORTED;
|
return SEGA_ERROR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,6 +254,7 @@ PlaybackStatus SEGAAPI_GetPlaybackStatus(void *hHandle)
|
|||||||
case AL_PAUSED:
|
case AL_PAUSED:
|
||||||
return PLAYBACK_STATUS_PAUSE;
|
return PLAYBACK_STATUS_PAUSE;
|
||||||
case AL_INITIAL:
|
case AL_INITIAL:
|
||||||
|
return PLAYBACK_STATUS_ACTIVE;
|
||||||
case AL_STOPPED:
|
case AL_STOPPED:
|
||||||
return PLAYBACK_STATUS_STOP;
|
return PLAYBACK_STATUS_STOP;
|
||||||
default:
|
default:
|
||||||
@ -373,7 +285,9 @@ int SEGAAPI_SetSampleRate(void *hHandle, unsigned int dwSampleRate)
|
|||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
context->sampleRate = dwSampleRate;
|
context->sampleRate = dwSampleRate;
|
||||||
|
|
||||||
updateBufferData(context, -1, -1);
|
updateBufferData(context, -1, -1);
|
||||||
|
|
||||||
return SEGA_SUCCESS;
|
return SEGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +298,7 @@ unsigned int SEGAAPI_GetSampleRate(void *hHandle)
|
|||||||
return SEGA_ERROR_BAD_HANDLE;
|
return SEGA_ERROR_BAD_HANDLE;
|
||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
|
|
||||||
return context->sampleRate;
|
return context->sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,7 +356,7 @@ int SEGAAPI_SetSendLevel(void *hHandle, unsigned int dwChannel, unsigned int dwS
|
|||||||
unsigned int SEGAAPI_GetSendLevel(void *hHandle, unsigned int dwChannel, unsigned int dwSend)
|
unsigned int SEGAAPI_GetSendLevel(void *hHandle, unsigned int dwChannel, unsigned int dwSend)
|
||||||
{
|
{
|
||||||
dbgPrint("SEGAAPI_GetSendLevel() 0x%x 0x%x 0x%x", hHandle, dwChannel, dwSend);
|
dbgPrint("SEGAAPI_GetSendLevel() 0x%x 0x%x 0x%x", hHandle, dwChannel, dwSend);
|
||||||
return 0;
|
return SEGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SEGAAPI_SetChannelVolume(void *hHandle, unsigned int dwChannel, unsigned int dwVolume)
|
int SEGAAPI_SetChannelVolume(void *hHandle, unsigned int dwChannel, unsigned int dwVolume)
|
||||||
@ -510,7 +425,6 @@ int SEGAAPI_SetStartLoopOffset(void *hHandle, unsigned int dwOffset)
|
|||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
|
|
||||||
context->startLoop = dwOffset;
|
context->startLoop = dwOffset;
|
||||||
updateBufferLoop(context);
|
|
||||||
|
|
||||||
return SEGA_SUCCESS;
|
return SEGA_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -534,7 +448,6 @@ int SEGAAPI_SetEndLoopOffset(void *hHandle, unsigned int dwOffset)
|
|||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
context->endLoop = dwOffset;
|
context->endLoop = dwOffset;
|
||||||
updateBufferLoop(context);
|
|
||||||
|
|
||||||
return SEGA_SUCCESS;
|
return SEGA_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -580,8 +493,9 @@ int SEGAAPI_SetLoopState(void *hHandle, int loop)
|
|||||||
return SEGA_ERROR_BAD_HANDLE;
|
return SEGA_ERROR_BAD_HANDLE;
|
||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
|
|
||||||
context->loop = loop;
|
context->loop = loop;
|
||||||
alSourcei(context->alSource, AL_LOOPING, context->loop ? AL_TRUE : AL_FALSE);
|
|
||||||
return SEGA_SUCCESS;
|
return SEGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,6 +596,7 @@ int SEGAAPI_SetReleaseState(void *hHandle, int enterReleasePhase)
|
|||||||
|
|
||||||
SEGAContext *context = hHandle;
|
SEGAContext *context = hHandle;
|
||||||
|
|
||||||
|
|
||||||
if (!enterReleasePhase)
|
if (!enterReleasePhase)
|
||||||
return SEGA_SUCCESS;
|
return SEGA_SUCCESS;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user