2017-12-20 18:44:32 +00:00
|
|
|
// Copyright 2017 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
#include "audio_core/audio_types.h"
|
|
|
|
#include "audio_core/time_stretch.h"
|
|
|
|
#include "common/common_types.h"
|
2018-09-08 20:07:28 +00:00
|
|
|
#include "common/ring_buffer.h"
|
2017-12-20 18:44:32 +00:00
|
|
|
#include "core/memory.h"
|
|
|
|
|
2018-07-24 19:54:33 +00:00
|
|
|
namespace Service {
|
|
|
|
namespace DSP {
|
|
|
|
class DSP_DSP;
|
|
|
|
} // namespace DSP
|
|
|
|
} // namespace Service
|
|
|
|
|
2017-12-20 18:44:32 +00:00
|
|
|
namespace AudioCore {
|
|
|
|
|
|
|
|
class Sink;
|
|
|
|
|
|
|
|
class DspInterface {
|
|
|
|
public:
|
|
|
|
DspInterface();
|
|
|
|
virtual ~DspInterface();
|
|
|
|
|
|
|
|
DspInterface(const DspInterface&) = delete;
|
|
|
|
DspInterface(DspInterface&&) = delete;
|
|
|
|
DspInterface& operator=(const DspInterface&) = delete;
|
|
|
|
DspInterface& operator=(DspInterface&&) = delete;
|
|
|
|
|
2018-12-06 12:18:26 +00:00
|
|
|
/**
|
|
|
|
* Reads data from one of three DSP registers
|
|
|
|
* @note this function blocks until the data is available
|
|
|
|
* @param register_number the index of the register to read
|
|
|
|
* @returns the value of the register
|
|
|
|
*/
|
|
|
|
virtual u16 RecvData(u32 register_number) = 0;
|
2017-12-20 18:44:32 +00:00
|
|
|
|
2018-12-06 12:28:47 +00:00
|
|
|
/**
|
|
|
|
* Checks whether data is ready in one of three DSP registers
|
|
|
|
* @param register_number the index of the register to check
|
|
|
|
* @returns true if data is ready
|
|
|
|
*/
|
|
|
|
virtual bool RecvDataIsReady(u32 register_number) const = 0;
|
|
|
|
|
2017-12-20 18:44:32 +00:00
|
|
|
/**
|
|
|
|
* Reads `length` bytes from the DSP pipe identified with `pipe_number`.
|
|
|
|
* @note Can read up to the maximum value of a u16 in bytes (65,535).
|
|
|
|
* @note IF an error is encoutered with either an invalid `pipe_number` or `length` value, an
|
|
|
|
* empty vector will be returned.
|
|
|
|
* @note IF `length` is set to 0, an empty vector will be returned.
|
|
|
|
* @note IF `length` is greater than the amount of data available, this function will only read
|
|
|
|
* the available amount.
|
|
|
|
* @param pipe_number a `DspPipe`
|
|
|
|
* @param length the number of bytes to read. The max is 65,535 (max of u16).
|
|
|
|
* @returns a vector of bytes from the specified pipe. On error, will be empty.
|
|
|
|
*/
|
|
|
|
virtual std::vector<u8> PipeRead(DspPipe pipe_number, u32 length) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* How much data is left in pipe
|
|
|
|
* @param pipe_number The Pipe ID
|
|
|
|
* @return The amount of data remaning in the pipe. This is the maximum length PipeRead will
|
|
|
|
* return.
|
|
|
|
*/
|
2018-09-06 20:03:28 +00:00
|
|
|
virtual std::size_t GetPipeReadableSize(DspPipe pipe_number) const = 0;
|
2017-12-20 18:44:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Write to a DSP pipe.
|
|
|
|
* @param pipe_number The Pipe ID
|
|
|
|
* @param buffer The data to write to the pipe.
|
|
|
|
*/
|
|
|
|
virtual void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) = 0;
|
|
|
|
|
|
|
|
/// Returns a reference to the array backing DSP memory
|
|
|
|
virtual std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() = 0;
|
|
|
|
|
2018-07-24 19:54:33 +00:00
|
|
|
/// Sets the dsp class that we trigger interrupts for
|
2018-07-29 18:26:41 +00:00
|
|
|
virtual void SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) = 0;
|
2018-07-24 19:54:33 +00:00
|
|
|
|
2017-12-20 18:44:32 +00:00
|
|
|
/// Select the sink to use based on sink id.
|
2018-07-02 13:03:14 +00:00
|
|
|
void SetSink(const std::string& sink_id, const std::string& audio_device);
|
2017-12-20 18:44:32 +00:00
|
|
|
/// Get the current sink
|
|
|
|
Sink& GetSink();
|
|
|
|
/// Enable/Disable audio stretching.
|
|
|
|
void EnableStretching(bool enable);
|
|
|
|
|
|
|
|
protected:
|
2018-06-30 12:26:38 +00:00
|
|
|
void OutputFrame(StereoFrame16& frame);
|
2017-12-20 18:44:32 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
void FlushResidualStretcherAudio();
|
2018-09-08 20:07:28 +00:00
|
|
|
void OutputCallback(s16* buffer, std::size_t num_frames);
|
2017-12-20 18:44:32 +00:00
|
|
|
|
|
|
|
std::unique_ptr<Sink> sink;
|
2018-09-08 20:28:19 +00:00
|
|
|
std::atomic<bool> perform_time_stretching = false;
|
|
|
|
std::atomic<bool> flushing_time_stretcher = false;
|
2018-09-08 20:07:28 +00:00
|
|
|
Common::RingBuffer<s16, 0x2000, 2> fifo;
|
|
|
|
std::array<s16, 2> last_frame{};
|
2017-12-20 18:44:32 +00:00
|
|
|
TimeStretcher time_stretcher;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace AudioCore
|