Example #1
0
int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
{
	libmixer->Warning("cellSurMixerCreate(config_addr=0x%x)", config.addr());

	surMixer = *config;

	AudioPortConfig& port = m_config.m_ports[SUR_PORT];

	if (port.m_is_audio_port_opened)
	{
		return CELL_LIBMIXER_ERROR_FULL;
	}

	port.channel = 8;
	port.block = 16;
	port.attr = 0;
	port.level = 1.0f;

	libmixer->Warning("*** audio port opened(default)");

	port.m_is_audio_port_opened = true;
	port.tag = 0;
	m_config.m_port_in_use++;

	libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)",
		(u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8);

	mixcount = 0;
	surMixerCb = 0;

	thread t("Surmixer Thread", []()
	{
		AudioPortConfig& port = m_config.m_ports[SUR_PORT];

		CPUThread* mixerCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU);

		mixerCb->SetName("Surmixer Callback");

		while (port.m_is_audio_port_opened)
		{
			if (Emu.IsStopped())
			{
				libmixer->Warning("Surmixer aborted");
				break;
			}

			if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack)
			{
				std::this_thread::sleep_for(std::chrono::milliseconds(1));
				continue;
			}

			if (port.m_is_audio_port_started)
			{
				//u64 stamp0 = get_system_time();

				memset(mixdata, 0, sizeof(mixdata));
				if (surMixerCb) mixerCb->ExecAsCallback(surMixerCb, true, surMixerCbArg, mixcount, 256);

				//u64 stamp1 = get_system_time();

				{
					std::lock_guard<std::mutex> lock(mixer_mutex);

					for (auto& p : ssp) if (p.m_active && p.m_created)
					{
						auto v = vm::lptrl<s16>::make(p.m_addr); // 16-bit LE audio data
						float left = 0.0f;
						float right = 0.0f;
						float speed = fabs(p.m_speed);
						float fpos = 0.0f;
						for (int i = 0; i < 256; i++) if (p.m_active)
						{
							u32 pos = p.m_position;
							int pos_inc = 0;
							if (p.m_speed > 0.0f) // select direction
							{
								pos_inc = 1;
							}
							else if (p.m_speed < 0.0f)
							{
								pos_inc = -1;
							}
							int shift = i - (int)fpos; // change playback speed (simple and rough)
							if (shift > 0)
							{
								// slow playback
								pos_inc = 0; // duplicate one sample at this time
								fpos += 1.0f;
								fpos += speed;
							}
							else if (shift < 0)
							{
								// fast playback
								i--; // mix two sample into one at this time
								fpos -= 1.0f;
							}
							else
							{
								fpos += speed;
							}
							p.m_position += (u32)pos_inc;
							if (p.m_channels == 1) // get mono data
							{
								left = right = (float)v[pos] / 0x8000 * p.m_level;
							}
							else if (p.m_channels == 2) // get stereo data
							{
								left = (float)v[pos * 2 + 0] / 0x8000 * p.m_level;
								right = (float)v[pos * 2 + 1] / 0x8000 * p.m_level;
							}
							if (p.m_connected) // mix
							{
								// TODO: m_x, m_y, m_z ignored
								mixdata[i * 8 + 0] += left;
								mixdata[i * 8 + 1] += right;
							}
							if ((p.m_position == p.m_samples && p.m_speed > 0.0f) ||
								(p.m_position == ~0 && p.m_speed < 0.0f)) // loop or stop
							{
								if (p.m_loop_mode == CELL_SSPLAYER_LOOP_ON)
								{
									p.m_position = p.m_loop_start;
								}
								else if (p.m_loop_mode == CELL_SSPLAYER_ONESHOT_CONT)
								{
									p.m_position -= (u32)pos_inc; // restore position
								}
								else // oneshot
								{
									p.m_active = false;
									p.m_position = p.m_loop_start; // TODO: check value
								}
							}
						}
					}
				}

				//u64 stamp2 = get_system_time();

				auto buf = vm::get_ptr<be_t<float>>(m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float));

				for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++)
				{
					// reverse byte order
					buf[i] = mixdata[i];
				}

				//u64 stamp3 = get_system_time();

				//ConLog.Write("Libmixer perf: start=%lld (cb=%lld, ssp=%lld, finalize=%lld)", stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2);
			}

			mixcount++;
		}

		{
			std::lock_guard<std::mutex> lock(mixer_mutex);
			ssp.clear();
		}
		
		Emu.GetCPU().RemoveThread(mixerCb->GetId());
	});
	t.detach();

	return CELL_OK;
}