Initial work on cellMic

This commit is contained in:
Zion Nimchuk 2018-03-14 13:27:56 -07:00 committed by kd-11
parent b5dbd44087
commit f9cab3270f
3 changed files with 392 additions and 91 deletions

View File

@ -38,6 +38,17 @@ s32 cellVideoOutSetupDisplay()
s32 cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<CellAudioInDeviceInfo> info)
{
cellAvconfExt.todo("cellAudioInGetDeviceInfo(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
info->portType = CELL_AUDIO_IN_PORT_USB;
info->availableModeCount = 1;
info->state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
info->deviceNumber = 0;
// Some games check if deviceId and type are the same.
info->deviceId = 0xDEADBEEF;
info->type = 0xBEEFDEAD;
info->availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
info->availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE;
info->availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
strcpy(info->name, "USB Camera");
return CELL_OK;
}
@ -65,7 +76,18 @@ s32 cellVideoOutGetGamma(u32 videoOut, vm::ptr<f32> gamma)
s32 cellAudioInGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioInDeviceInfo> info)
{
cellAvconfExt.todo("cellAudioInGetAvailableDeviceInfo(count=0x%x, info=*0x%x)", count, info);
return 0; // number of available devices
info->portType = CELL_AUDIO_IN_PORT_USB;
info->availableModeCount = 1;
info->state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
info->deviceNumber = 0;
// Some games check if deviceId and type are the same.
info->deviceId = 0xDEADBEEF;
info->type = 0xBEEFDEAD;
info->availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
info->availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE;
info->availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
strcpy(info->name, "USB Camera");
return 1; // number of available devices
}
s32 cellAudioOutGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioOutDeviceInfo2> info)

View File

@ -3,62 +3,198 @@
#include "Emu/Cell/PPUModule.h"
#include "cellMic.h"
#include <Emu/IdManager.h>
#include <Emu/Cell/lv2/sys_event.h>
#include <thread>
LOG_CHANNEL(cellMic);
void mic_thread::on_init(const std::shared_ptr<void>& _this)
{
named_thread::on_init(_this);
}
void mic_thread::on_task()
{
while (micInited && !Emu.IsStopped())
{
if (Emu.IsPaused())
{
std::this_thread::sleep_for(1ms); // hack from cellAudio
continue;
}
if (!micOpened || !micStarted)
continue;
// If event queue is not set, then we can't send any events
if (eventQueueKey == 0)
continue;
std::this_thread::sleep_for(1s);
// Make sure the mic thread wasn't stopped while we were sleeping
if (!micInited)
break;
auto micQueue = lv2_event_queue::find(eventQueueKey);
micQueue->send(0, CELL_MIC_DATA, 0, 0);
}
}
/// Initialization/Shutdown Functions
s32 cellMicInit()
{
cellMic.warning("cellMicInit()");
cellMic.trace("cellMicInit()");
const auto micThread = fxm::make<mic_thread>();
micInited = true;
if (!micThread)
return CELL_MIC_ERROR_ALREADY_INIT;
return CELL_OK;
}
s32 cellMicEnd()
{
cellMic.warning("cellMicEnd()");
cellMic.trace("cellMicEnd()");
const auto micThread = fxm::withdraw<mic_thread>();
micInited = false;
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
return CELL_OK;
}
s32 cellMicOpen()
/// Open/Close Microphone Functions
s32 cellMicOpen(u32 deviceNumber, u32 sampleRate)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.todo("cellMicOpen(deviceNumber=%um sampleRate=%u)", deviceNumber, sampleRate);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
if (micThread->micOpened)
return CELL_MIC_ERROR_ALREADY_OPEN;
micThread->DspFrequency = sampleRate;
micThread->micOpened = true;
return CELL_OK;
}
s32 cellMicClose()
s32 cellMicOpenRaw(u32 deviceNumber, u32 sampleRate, u32 maxChannels)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.todo("cellMicOpenRaw(deviceNumber=%d, sampleRate=%d, maxChannels=%d)", deviceNumber, sampleRate, maxChannels);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
if (micThread->micOpened)
return CELL_MIC_ERROR_ALREADY_OPEN;
micThread->rawFrequency = sampleRate;
micThread->micOpened = true;
return CELL_OK;
}
s32 cellMicGetDeviceGUID()
s32 cellMicOpenEx(u32 deviceNumber, u32 rawSampleRate, u32 rawChannel, u32 DSPSampleRate, u32 bufferSizeMS, u8 signalType)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.todo("cellMicOpenEx(deviceNumber=%d, rawSampleRate=%d, rawChannel=%d, DSPSampleRate=%d, bufferSizeMS=%d, signalType=0x%x)", deviceNumber, rawSampleRate, rawChannel, DSPSampleRate,
bufferSizeMS, signalType);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
if (micThread->micOpened)
return CELL_MIC_ERROR_ALREADY_OPEN;
micThread->rawFrequency = rawSampleRate;
micThread->DspFrequency = DSPSampleRate;
micThread->micOpened = true;
return CELL_OK;
}
s32 cellMicGetType()
u8 cellMicIsOpen(u32 deviceNumber)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.warning("cellMicIsOpen(deviceNumber=%d)", deviceNumber);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return false;
return micThread->micOpened;
}
s32 cellMicIsAttached(u32 deviceNumber)
{
cellMic.warning("cellMicIsAttached(deviceNumber=%d)", deviceNumber);
return 1;
}
s32 cellMicClose(u32 deviceNumber)
{
cellMic.warning("cellMicClose(deviceNumber=%d)", deviceNumber);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
micThread->micOpened = false;
return CELL_OK;
}
s32 cellMicIsAttached()
/// Starting/Stopping Microphone Functions
s32 cellMicStart(u32 deviceNumber)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.warning("cellMicStart(deviceNumber=%d)", deviceNumber);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
if (!micThread->micOpened)
return CELL_MIC_ERROR_NOT_OPEN;
micThread->micStarted = true;
return CELL_OK;
}
s32 cellMicIsOpen()
s32 cellMicStartEx(u32 deviceNumber, u32 flags)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.todo("cellMicStartEx(deviceNumber=%d, flags=%d)", deviceNumber, flags);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
if (!micThread->micOpened)
return CELL_MIC_ERROR_NOT_OPEN;
micThread->micStarted = true;
return CELL_OK;
}
s32 cellMicGetDeviceAttr()
s32 cellMicStop(u32 deviceNumber)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.todo("cellMicStop(deviceNumber=%d)", deviceNumber);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
if (!micThread->micOpened)
return CELL_MIC_ERROR_NOT_OPEN;
micThread->micStarted = false;
return CELL_OK;
}
/// Microphone Attributes/States Functions
s32 cellMicGetDeviceAttr(u32 deviceNumber, vm::ptr<void> deviceAttributes, vm::ptr<u32> arg1, vm::ptr<u32> arg2)
{
cellMic.todo("cellMicGetDeviceAttr(deviceNumber=%d, deviceAttribute=*0x%x, arg1=*0x%x, arg2=*0x%x)", deviceNumber, deviceAttributes, arg1, arg2);
return CELL_OK;
}
@ -80,94 +216,158 @@ s32 cellMicSetSignalAttr()
return CELL_OK;
}
s32 cellMicGetSignalState()
s32 cellMicGetSignalState(u32 deviceNumber, CellMicSignalState signalState, vm::ptr<void> value)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.todo("cellMicGetSignalState(deviceNumber=%d, signalSate=%d, value=0x%x)", deviceNumber, (int)signalState, value);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
be_t<u32>* ival = (be_t<u32>*)value.get_ptr();
be_t<f32>* fval = (be_t<f32>*)value.get_ptr();
switch (signalState)
{
case CELL_MIC_SIGSTATE_LOCTALK:
*ival = 9; // Someone is probably talking
break;
case CELL_MIC_SIGSTATE_FARTALK:
// TODO
break;
case CELL_MIC_SIGSTATE_NSR:
// TODO
break;
case CELL_MIC_SIGSTATE_AGC:
// TODO
break;
case CELL_MIC_SIGSTATE_MICENG:
*fval = 40.0f; // 40 decibels
break;
case CELL_MIC_SIGSTATE_SPKENG:
// TODO
break;
}
return CELL_OK;
}
s32 cellMicStart()
s32 cellMicGetFormatRaw(u32 deviceNumber, vm::ptr<CellMicInputFormat> format)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.warning("cellMicGetFormatRaw(deviceNumber=%d, format=0x%x)", deviceNumber, format);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
format->channelNum = 4;
format->subframeSize = 2;
format->bitResolution = micThread->bitResolution;
format->dataType = 1;
format->sampleRate = micThread->rawFrequency;
return CELL_OK;
}
s32 cellMicRead()
s32 cellMicGetFormatAux(u32 deviceNumber, vm::ptr<CellMicInputFormat> format)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.warning("cellMicGetFormatAux(deviceNumber=%d, format=0x%x)", deviceNumber, format);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
format->channelNum = 4;
format->subframeSize = 2;
format->bitResolution = micThread->bitResolution;
format->dataType = 1;
format->sampleRate = micThread->AuxFrequency;
return CELL_OK;
}
s32 cellMicStop()
s32 cellMicGetFormatDsp(u32 deviceNumber, vm::ptr<CellMicInputFormat> format)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.warning("cellMicGetFormatDsp(deviceNumber=%d, format=0x%x)", deviceNumber, format);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
format->channelNum = 4;
format->subframeSize = 2;
format->bitResolution = micThread->bitResolution;
format->dataType = 1;
format->sampleRate = micThread->DspFrequency;
return CELL_OK;
}
s32 cellMicReset()
/// Event Queue Functions
s32 cellMicSetNotifyEventQueue(u64 key)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.warning("cellMicSetNotifyEventQueue(key=0x%llx)", key);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
// default mic queue size = 4
auto micQueue = lv2_event_queue::find(key);
micQueue->send(0, CELL_MIC_ATTACH, 0, 0);
micThread->eventQueueKey = key;
return CELL_OK;
}
s32 cellMicSetNotifyEventQueue()
s32 cellMicSetNotifyEventQueue2(u64 key, u64 source)
{
UNIMPLEMENTED_FUNC(cellMic);
// TODO: Actually do things with the source variable
cellMic.todo("cellMicSetNotifyEventQueue2(key=0x%llx, source=0x%llx", key, source);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
// default mic queue size = 4
auto micQueue = lv2_event_queue::find(key);
micQueue->send(0, CELL_MIC_ATTACH, 0, 0);
micThread->eventQueueKey = key;
return CELL_OK;
}
s32 cellMicSetNotifyEventQueue2()
s32 cellMicRemoveNotifyEventQueue(u64 key)
{
UNIMPLEMENTED_FUNC(cellMic);
cellMic.warning("cellMicRemoveNotifyEventQueue(key=0x%llx)", key);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
micThread->eventQueueKey = 0;
return CELL_OK;
}
s32 cellMicRemoveNotifyEventQueue()
/// Reading Functions
s32 cellMicRead(u32 deviceNumber, vm::ptr<void> data, u32 maxBytes)
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
cellMic.warning("cellMicRead(deviceNumber=%d, data=0x%x, maxBytes=0x%x)", deviceNumber, data, maxBytes);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
const s32 size = std::min<s32>(maxBytes, bufferSize);
return size;
}
s32 cellMicOpenEx()
s32 cellMicReadRaw(u32 deviceNumber, vm::ptr<void> data, int maxBytes)
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
cellMic.warning("cellMicReadRaw(deviceNumber=%d, data=0x%x, maxBytes=%d)", deviceNumber, data, maxBytes);
const auto micThread = fxm::get<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
s32 cellMicStartEx()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
const s32 size = std::min<s32>(maxBytes, bufferSize);
s32 cellMicGetFormatRaw()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
s32 cellMicGetFormatAux()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
s32 cellMicGetFormatDsp()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
s32 cellMicOpenRaw()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
s32 cellMicReadRaw()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
return size;
}
s32 cellMicReadAux()
@ -182,6 +382,26 @@ s32 cellMicReadDsp()
return CELL_OK;
}
/// Unimplemented Functions
s32 cellMicReset()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
s32 cellMicGetDeviceGUID()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
s32 cellMicGetType()
{
UNIMPLEMENTED_FUNC(cellMic);
return CELL_OK;
}
s32 cellMicGetStatus()
{
UNIMPLEMENTED_FUNC(cellMic);
@ -259,8 +479,8 @@ s32 cellMicGetDeviceIdentifier()
return CELL_OK;
}
DECLARE(ppu_module_manager::cellMic)("cellMic", []()
{
DECLARE(ppu_module_manager::cellMic)
("cellMic", []() {
REG_FUNC(cellMic, cellMicInit);
REG_FUNC(cellMic, cellMicEnd);
REG_FUNC(cellMic, cellMicOpen);

View File

@ -1,25 +1,84 @@
#pragma once
#include "Utilities/Thread.h"
// Error Codes
enum
{
CELL_MICIN_ERROR_ALREADY_INIT = 0x80140101,
CELL_MICIN_ERROR_SYSTEM = 0x80140102,
CELL_MICIN_ERROR_NOT_INIT = 0x80140103,
CELL_MICIN_ERROR_PARAM = 0x80140104,
CELL_MICIN_ERROR_PORT_FULL = 0x80140105,
CELL_MICIN_ERROR_ALREADY_OPEN = 0x80140106,
CELL_MICIN_ERROR_NOT_OPEN = 0x80140107,
CELL_MICIN_ERROR_NOT_RUN = 0x80140108,
CELL_MICIN_ERROR_TRANS_EVENT = 0x80140109,
CELL_MICIN_ERROR_OPEN = 0x8014010a,
CELL_MICIN_ERROR_SHAREDMEMORY = 0x8014010b,
CELL_MICIN_ERROR_MUTEX = 0x8014010c,
CELL_MICIN_ERROR_EVENT_QUEUE = 0x8014010d,
CELL_MICIN_ERROR_DEVICE_NOT_FOUND = 0x8014010e,
CELL_MICIN_ERROR_SYSTEM_NOT_FOUND = 0x8014010e,
CELL_MICIN_ERROR_FATAL = 0x8014010f,
CELL_MICIN_ERROR_DEVICE_NOT_SUPPORT = 0x80140110,
CELL_MIC_ERROR_ALREADY_INIT = 0x80140101,
CELL_MIC_ERROR_SYSTEM = 0x80140102,
CELL_MIC_ERROR_NOT_INIT = 0x80140103,
CELL_MIC_ERROR_PARAM = 0x80140104,
CELL_MIC_ERROR_PORT_FULL = 0x80140105,
CELL_MIC_ERROR_ALREADY_OPEN = 0x80140106,
CELL_MIC_ERROR_NOT_OPEN = 0x80140107,
CELL_MIC_ERROR_NOT_RUN = 0x80140108,
CELL_MIC_ERROR_TRANS_EVENT = 0x80140109,
CELL_MIC_ERROR_OPEN = 0x8014010a,
CELL_MIC_ERROR_SHAREDMEMORY = 0x8014010b,
CELL_MIC_ERROR_MUTEX = 0x8014010c,
CELL_MIC_ERROR_EVENT_QUEUE = 0x8014010d,
CELL_MIC_ERROR_DEVICE_NOT_FOUND = 0x8014010e,
CELL_MIC_ERROR_SYSTEM_NOT_FOUND = 0x8014010e,
CELL_MIC_ERROR_FATAL = 0x8014010f,
CELL_MIC_ERROR_DEVICE_NOT_SUPPORT = 0x80140110,
};
struct CellMicInputFormat
{
u8 channelNum;
u8 subframeSize;
u8 bitResolution;
u8 dataType;
be_t<u32> sampleRate;
};
enum CellMicSignalState
{
CELL_MIC_SIGSTATE_LOCTALK = 0,
CELL_MIC_SIGSTATE_FARTALK = 1,
CELL_MIC_SIGSTATE_NSR = 3,
CELL_MIC_SIGSTATE_AGC = 4,
CELL_MIC_SIGSTATE_MICENG = 5,
CELL_MIC_SIGSTATE_SPKENG = 6,
};
enum CellMicCommand
{
CELL_MIC_ATTACH = 2,
CELL_MIC_DATA = 5,
};
// TODO: generate this from input from an actual microphone
const u32 bufferSize = 1;
bool micInited = false;
class mic_thread final : public named_thread
{
private:
void on_task() override;
std::string get_name() const override { return "Mic Thread"; }
public:
void on_init(const std::shared_ptr<void>&) override;
// Default value of 48000 for no particular reason
u32 DspFrequency = 48000; // DSP is the default type
u32 rawFrequency = 48000;
u32 AuxFrequency = 48000;
u8 bitResolution = 32;
bool micOpened = false;
bool micStarted = false;
u64 eventQueueKey = 0;
u32 signalStateLocalTalk = 9; // value is in range 0-10. 10 indicates talking, 0 indicating none.
u32 signalStateFarTalk = 0; // value is in range 0-10. 10 indicates talking from far away, 0 indicating none.
f32 signalStateNoiseSupression; // value is in decibels
f32 signalStateGainControl;
f32 signalStateMicSignalLevel; // value is in decibels
f32 signalStateSpeakerSignalLevel; // value is in decibels
mic_thread() = default;
~mic_thread()
{
micInited = false;
}
};