static void initialize_tls() { // allocate if not initialized if (!g_tls_net_data) { g_tls_net_data.set(vm::alloc(sizeof(decltype(g_tls_net_data)::type), vm::main)); thread_ctrl::at_exit([addr = g_tls_net_data.addr()] { vm::dealloc_verbose_nothrow(addr, vm::main); }); } }
static never_inline void initialize_tls() { // allocate if not initialized if (!g_tls_net_data) { g_tls_net_data.set(vm::alloc(sizeof(decltype(g_tls_net_data)::type), vm::main)); // Initial values g_tls_net_data->_errno = SYS_NET_EBUSY; thread_ctrl::atexit([addr = g_tls_net_data.addr()] { vm::dealloc_verbose_nothrow(addr, vm::main); }); } }
s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config) { libmixer.Warning("cellSurMixerCreate(config=*0x%x)", config); g_surmx.audio_port = g_audio.open_port(); if (!~g_surmx.audio_port) { return CELL_LIBMIXER_ERROR_FULL; } g_surmx.priority = config->priority; g_surmx.ch_strips_1 = config->chStrips1; g_surmx.ch_strips_2 = config->chStrips2; g_surmx.ch_strips_6 = config->chStrips6; g_surmx.ch_strips_8 = config->chStrips8; AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; port.channel = 8; port.block = 16; port.attr = 0; port.addr = g_audio.buffer + AUDIO_PORT_OFFSET * g_surmx.audio_port; port.read_index_addr = g_audio.indexes + sizeof(u64) * g_surmx.audio_port; port.size = port.channel * port.block * AUDIO_SAMPLES * sizeof(float); port.tag = 0; port.level = 1.0f; port.level_set.data = { 1.0f, 0.0f }; libmixer.Warning("*** audio port opened (port=%d)", g_surmx.audio_port); mixcount = 0; surMixerCb.set(0); libmixer.Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); auto ppu = Emu.GetIdManager().make_ptr<PPUThread>("Surmixer Thread"); ppu->prio = 1001; ppu->stack_size = 0x10000; ppu->custom_task = [](PPUThread& CPU) { AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; while (port.state.load() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped()) { if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } if (port.state.load() == AUDIO_PORT_STATE_STARTED) { //u64 stamp0 = get_system_time(); memset(mixdata, 0, sizeof(mixdata)); if (surMixerCb) { surMixerCb(CPU, surMixerCbArg, (u32)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::ptrl<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 (s32 i = 0; i < 256; i++) if (p.m_active) { u32 pos = p.m_position; s32 pos_inc = 0; if (p.m_speed > 0.0f) // select direction { pos_inc = 1; } else if (p.m_speed < 0.0f) { pos_inc = -1; } s32 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>>(port.addr + (mixcount % port.block) * port.channel * AUDIO_SAMPLES * 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(); } surMixerCb.set(0); const u32 id = CPU.GetId(); CallAfter([id]() { Emu.GetIdManager().remove<PPUThread>(id); }); }; return CELL_OK; }