{"action":"created","comment":{"url":"https://api.github.com/repos/mamedev/mame/pulls/comments/209824305","pull_request_review_id":145909317,"id":209824305,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwOTgyNDMwNQ==","diff_hunk":"@@ -180,70 +212,429 @@ WRITE8_MEMBER(qsound_hle_device::qsound_w)\n \n READ8_MEMBER(qsound_hle_device::qsound_r)\n {\n-\t/* Port ready bit (0x80 if ready) */\n-\treturn 0x80;\n+\t// ready bit (0x00 = busy, 0x80 == ready)\n+\tm_stream->update();\n+\treturn m_ready_flag;\n }\n \n \n void qsound_hle_device::write_data(u8 address, u16 data)\n {\n-\tint ch = 0, reg;\n+\tuint16_t *destination = register_map[address];\n+\tif(destination)\n+\t\t*destination = data;\n+\tm_ready_flag = 0;\n+}\n \n-\tif (address < 0x80)\n+void qsound_hle_device::init_register_map()\n+{\n+\t// unused registers\n+\tfor(int i=0;i<256;i++)\n+\t\tregister_map[i] = NULL;\n+\n+\t// PCM registers\n+\tfor(int i=0;i<16;i++) // PCM voices\n \t{\n-\t\tch = address >> 3;\n-\t\treg = address & 7;\n+\t\tregister_map[(i<<3)+0] = (uint16_t*)&m_voice[(i+1)%16].bank; // Bank applies to the next channel\n+\t\tregister_map[(i<<3)+1] = (uint16_t*)&m_voice[i].addr; // Current sample position and start position.\n+\t\tregister_map[(i<<3)+2] = (uint16_t*)&m_voice[i].rate; // 4.12 fixed point decimal.\n+\t\tregister_map[(i<<3)+3] = (uint16_t*)&m_voice[i].phase;\n+\t\tregister_map[(i<<3)+4] = (uint16_t*)&m_voice[i].loop_len;\n+\t\tregister_map[(i<<3)+5] = (uint16_t*)&m_voice[i].end_addr;\n+\t\tregister_map[(i<<3)+6] = (uint16_t*)&m_voice[i].volume;\n+\t\tregister_map[(i<<3)+7] = NULL;\t// unused\n+\t\tregister_map[i+0x80] = (uint16_t*)&m_voice_pan[i];\n+\t\tregister_map[i+0xba] = (uint16_t*)&m_voice[i].echo;\n \t}\n-\telse if (address < 0x90)\n+\n+\t// ADPCM registers\n+\tfor(int i=0;i<3;i++) // ADPCM voices\n \t{\n-\t\tch = address & 0xf;\n-\t\treg = 8;\n+\t\t// ADPCM sample rate is fixed to 8khz. (one channel is updated every third sample)\n+\t\tregister_map[(i<<2)+0xca] = (uint16_t*)&m_adpcm[i].start_addr;\n+\t\tregister_map[(i<<2)+0xcb] = (uint16_t*)&m_adpcm[i].end_addr;\n+\t\tregister_map[(i<<2)+0xcc] = (uint16_t*)&m_adpcm[i].bank;\n+\t\tregister_map[(i<<2)+0xcd] = (uint16_t*)&m_adpcm[i].volume;\n+\t\tregister_map[i+0xd6] = (uint16_t*)&m_adpcm[i].flag; // non-zero to start ADPCM playback\n+\t\tregister_map[i+0x90] = (uint16_t*)&m_voice_pan[16+i];\n \t}\n-\telse if (address >= 0xba && address < 0xca)\n+\n+\t// QSound registers\n+\tregister_map[0x93] = (uint16_t*)&m_echo.feedback;\n+\tregister_map[0xd9] = (uint16_t*)&m_echo.end_pos;\n+\tregister_map[0xe2] = (uint16_t*)&m_delay_update; // non-zero to update delays\n+\tregister_map[0xe3] = (uint16_t*)&m_next_state;\n+\tfor(int i=0;i<2;i++)  // left, right\n \t{\n-\t\tch = address - 0xba;\n-\t\treg = 9;\n+\t\t// Wet\n+\t\tregister_map[(i<<1)+0xda] = (uint16_t*)&m_filter[i].table_pos;\n+\t\tregister_map[(i<<1)+0xde] = (uint16_t*)&m_wet[i].delay;\n+\t\tregister_map[(i<<1)+0xe4] = (uint16_t*)&m_wet[i].volume;\n+\t\t// Dry\n+\t\tregister_map[(i<<1)+0xdb] = (uint16_t*)&m_alt_filter[i].table_pos;\n+\t\tregister_map[(i<<1)+0xdf] = (uint16_t*)&m_dry[i].delay;\n+\t\tregister_map[(i<<1)+0xe5] = (uint16_t*)&m_dry[i].volume;\n+\t}\n+}\n+\n+int16_t qsound_hle_device::get_sample(uint16_t bank,uint16_t address)\n+{\n+\tuint32_t rom_addr;\n+\tuint8_t sample_data;\n+\n+\tbank &= 0x7FFF;\n+\trom_addr = (bank << 16) | (address << 0);\n+\n+\tsample_data = read_byte(rom_addr);\n+\n+\treturn (int16_t)(sample_data << 8);\t// bit0-7 is tied to ground\n+}\n+\n+/********************************************************************/\n+\n+// updates one DSP sample\n+void qsound_hle_device::update_sample()\n+{\n+\tswitch(m_state)\n+\t{\n+\t\tdefault:\n+\t\tcase STATE_INIT1:\n+\t\tcase STATE_INIT2:\n+\t\t\treturn state_init();\n+\t\tcase STATE_REFRESH1:\n+\t\t\treturn state_refresh_filter_1();\n+\t\tcase STATE_REFRESH2:\n+\t\t\treturn state_refresh_filter_2();\n+\t\tcase STATE_NORMAL1:\n+\t\tcase STATE_NORMAL2:\n+\t\t\treturn state_normal_update();\n+\t}\n+}\n+\n+// Initialization routine\n+void qsound_hle_device::state_init()\n+{\n+\tint mode = (m_state == STATE_INIT2) ? 1 : 0;\n+\n+\t// we're busy for 4 samples, including the filter refresh.\n+\tif(m_state_counter >= 2)\n+\t{\n+\t\tm_state_counter = 0;\n+\t\tm_state = m_next_state;\n+\t\treturn;\n+\t}\n+\telse if(m_state_counter == 1)\n+\t{\n+\t\tm_state_counter++;\n+\t\treturn;\n+\t}\n+\n+\tqsound_voice temp = {};\t\tstd::fill(std::begin(m_voice),std::end(m_voice),temp);\n+\tqsound_adpcm temp2 = {};\tstd::fill(std::begin(m_adpcm),std::end(m_adpcm),temp2);\n+\tqsound_fir temp3 = {};\t\tstd::fill(std::begin(m_filter),std::end(m_filter),temp3);\n+\t\t\t\t\t\t\t\tstd::fill(std::begin(m_alt_filter),std::end(m_alt_filter),temp3);\n+\tqsound_delay temp4 = {};\tstd::fill(std::begin(m_wet),std::end(m_wet),temp4);\n+\t\t\t\t\t\t\t\tstd::fill(std::begin(m_dry),std::end(m_dry),temp4);\n+\tqsound_echo temp5 = {};\t\tm_echo = temp5;\n+\n+\tfor(int i=0;i<19;i++)\n+\t{\n+\t\tm_voice_pan[i] = DATA_PAN_TAB + 0x10;\n+\t\tm_voice_output[i] = 0;\n+\t}\n+\n+\tfor(int i=0;i<16;i++)\n+\t\tm_voice[i].bank = 0x8000;\n+\tfor(int i=0;i<3;i++)\n+\t\tm_adpcm[i].bank = 0x8000;\n+\n+\tif(mode == 0)\n+\t{\n+\t\t// mode 1\n+\t\tm_wet[0].delay = 0;\n+\t\tm_dry[0].delay = 46;\n+\t\tm_wet[1].delay = 0;\n+\t\tm_dry[1].delay = 48;\n+\t\tm_filter[0].table_pos = DATA_FILTER_TAB + (FILTER_ENTRY_SIZE*1);\n+\t\tm_filter[1].table_pos = DATA_FILTER_TAB + (FILTER_ENTRY_SIZE*2);\n+\t\tm_echo.end_pos = DELAY_BASE_OFFSET + 6;\n+\t\tm_next_state = STATE_REFRESH1;\n \t}\n \telse\n \t{\n-\t\t// unknown\n-\t\treg = address;\n+\t\t// mode 2\n+\t\tm_wet[0].delay = 1;\n+\t\tm_dry[0].delay = 0;\n+\t\tm_wet[1].delay = 0;\n+\t\tm_dry[1].delay = 0;\n+\t\tm_filter[0].table_pos = 0xf73;\n+\t\tm_filter[1].table_pos = 0xfa4;\n+\t\tm_alt_filter[0].table_pos = 0xf73;\n+\t\tm_alt_filter[1].table_pos = 0xfa4;\n+\t\tm_echo.end_pos = DELAY_BASE_OFFSET2 + 6;\n+\t\tm_next_state = STATE_REFRESH2;\n \t}\n \n-\tswitch (reg)\n+\tm_wet[0].volume = 0x3fff;\n+\tm_dry[0].volume = 0x3fff;\n+\tm_wet[1].volume = 0x3fff;\n+\tm_dry[1].volume = 0x3fff;\n+\n+\tm_delay_update = 1;\n+\tm_ready_flag = 0;\n+\tm_state_counter = 1;\n+}\n+\n+// Updates filter parameters for mode 1\n+void qsound_hle_device::state_refresh_filter_1()\n+{\n+\tfor(int ch=0; ch<2; ch++)\n \t{\n-\tcase 0: // bank\n-\tcase 1: // current sample\n-\tcase 2: // playback rate\n-\tcase 3: // sample interval counter\n-\tcase 4: // loop offset\n-\tcase 5: // end sample\n-\tcase 6: // channel volume\n-\tcase 7: // unused\n-\t\tm_channel[ch].reg[reg] = data;\n-\t\tbreak;\n+\t\tm_filter[ch].delay_pos = 0;\n+\t\tm_filter[ch].tap_count = 95;\n+\n+\t\tfor(int i=0; i<95; i++)\n+\t\t\tm_filter[ch].taps[i] = read_dsp_rom(m_filter[ch].table_pos + i);\n+\t}\n+\n+\tm_state = m_next_state = STATE_NORMAL1;\n+}\n \n-\tcase 8:\n+// Updates filter parameters for mode 2\n+void qsound_hle_device::state_refresh_filter_2()\n+{\n+\tfor(int ch=0; ch<2; ch++)\n \t{\n-\t\t// panning (left=0x0110, centre=0x0120, right=0x0130)\n-\t\t// looks like it doesn't write other values than that\n-\t\tint pan = (data & 0x3f) - 0x10;\n-\t\tif (pan > 0x20)\n-\t\t\tpan = 0x20;\n-\t\tif (pan < 0)\n-\t\t\tpan = 0;\n+\t\tm_filter[ch].delay_pos = 0;\n+\t\tm_filter[ch].tap_count = 45;\n+\n+\t\tfor(int i=0; i<45; i++)\n+\t\t\tm_filter[ch].taps[i] = (int16_t) read_dsp_rom(m_filter[ch].table_pos + i);\n \n-\t\tm_channel[ch].rvol = m_pan_table[pan];\n-\t\tm_channel[ch].lvol = m_pan_table[0x20 - pan];\n-\t\tbreak;\n+\t\tm_alt_filter[ch].delay_pos = 0;\n+\t\tm_alt_filter[ch].tap_count = 44;\n+\n+\t\tfor(int i=0; i<44; i++)\n+\t\t\tm_alt_filter[ch].taps[i] = (int16_t) read_dsp_rom(m_filter[ch].table_pos + i);\n \t}\n \n-\tcase 9:\n-\t\t// unknown\n-\t\tbreak;\n+\tm_state = m_next_state = STATE_NORMAL2;\n+}\n \n-\tdefault:\n-\t\t//logerror(\"%s: write_data %02x = %04x\\n\", machine().describe_context(), address, data);\n-\t\tbreak;\n+// Updates a PCM voice. There are 16 voices, each are updated every sample\n+// with full rate and volume control.\n+int16_t qsound_hle_device::pcm_update(struct qsound_voice *v, int32_t *echo_out)\n+{\n+\t// Read sample from rom and apply volume\n+\tint16_t output = (v->volume * get_sample(v->bank, v->addr))>>14;\n+\n+\t*echo_out += (output * v->echo)<<2;\n+\n+\t// Add delta to the phase and loop back if required\n+\tint32_t new_phase = v->rate + ((v->addr<<12) | (v->phase>>4));\n+\n+\tif((new_phase>>12) >= v->end_addr)\n+\t\tnew_phase -= (v->loop_len<<12);\n+\n+\tnew_phase = CLAMP(new_phase, -0x8000000, 0x7FFFFFF);\n+\tv->addr = new_phase>>12;\n+\tv->phase = (new_phase<<4)&0xffff;\n+\n+\treturn output;\n+}\n+\n+// Updates an ADPCM voice. There are 3 voices, one is updated every sample\n+// (effectively making the ADPCM rate 1/3 of the master sample rate), and\n+// volume is set when starting samples only.\n+// The ADPCM algorithm is supposedly similar to Yamaha ADPCM. It also seems\n+// like Capcom never used it, so this was not emulated in the earlier QSound\n+// emulators.\n+void qsound_hle_device::adpcm_update(int voice_no, int nibble)\n+{\n+\tstruct qsound_adpcm *v = &m_adpcm[voice_no];\n+\n+\tint32_t delta;\n+\tint8_t step;\n+\n+\tif(!nibble)\n+\t{\n+\t\t// Mute voice when it reaches the end address.\n+\t\tif(v->cur_addr == v->end_addr)\n+\t\t\tv->cur_vol = 0;\n+\n+\t\t// Playback start flag\n+\t\tif(v->flag)\n+\t\t{\n+\t\t\tm_voice_output[16+voice_no] = 0;\n+\t\t\tv->flag = 0;\n+\t\t\tv->step_size = 10;\n+\t\t\tv->cur_vol = v->volume;\n+\t\t\tv->cur_addr = v->start_addr;\n+\t\t}\n+\n+\t\t// get top nibble\n+\t\tstep = get_sample(v->bank, v->cur_addr) >> 8;\n+\t}\n+\telse\n+\t{\n+\t\t// get bottom nibble\n+\t\tstep = get_sample(v->bank, v->cur_addr++) >> 4;\n+\t}\n+\n+\t// shift with sign extend\n+\tstep >>= 4;\n+\n+\t// delta = (0.5 + abs(v->step)) * v->step_size\n+\tdelta = ((1+abs(step<<1)) * v->step_size)>>1;\n+\tif(step <= 0)\n+\t\tdelta = -delta;\n+\tdelta += m_voice_output[16+voice_no];\n+\tdelta = CLAMP(delta,-32768,32767);\n+\n+\tm_voice_output[16+voice_no] = (delta * v->cur_vol)>>16;\n+\n+\tv->step_size = (read_dsp_rom(DATA_ADPCM_TAB + 8 + step) * v->step_size) >> 6;\n+\tv->step_size = CLAMP(v->step_size, 1, 2000);\n+}\n+\n+// The echo effect is pretty simple. A moving average filter is used on\n+// the output from the delay line to smooth samples over time.\n+int16_t qsound_hle_device::echo(struct qsound_echo *r,int32_t input)\n+{\n+\t// get average of last 2 samples from the delay line\n+\tint32_t old_sample = r->delay_line[r->delay_pos];\n+\tint32_t last_sample = r->last_sample;\n+\tr->last_sample = old_sample;\n+\told_sample = (old_sample+last_sample) >> 1;\n+\n+\t// add current sample to the delay line\n+\tint32_t new_sample = input + ((old_sample * r->feedback)<<2);\n+\tr->delay_line[r->delay_pos++] = new_sample>>16;\n+\n+\tif(r->delay_pos >= r->length)\n+\t\tr->delay_pos = 0;\n+\n+\treturn old_sample;\n+}\n+\n+// Process a sample update\n+void qsound_hle_device::state_normal_update()\n+{\n+\tm_ready_flag = 0x80;\n+\tint32_t echo_input = 0;\n+\tint16_t echo_output;\n+\n+\t// recalculate echo length\n+\tif(m_state == STATE_NORMAL2)\n+\t\tm_echo.length = m_echo.end_pos - DELAY_BASE_OFFSET2;\n+\telse\n+\t\tm_echo.length = m_echo.end_pos - DELAY_BASE_OFFSET;\n+\n+\tm_echo.length = CLAMP(m_echo.length, 0, 1024);\n+\n+\t// update PCM voices\n+\tfor(int i=0; i<16; i++)\n+\t\tm_voice_output[i] = pcm_update(&m_voice[i], &echo_input);\n+\n+\t// update ADPCM voices (one every third sample)\n+\tadpcm_update(m_state_counter % 3, m_state_counter / 3);\n+\n+\techo_output = echo(&m_echo,echo_input);\n+\n+\t// now, we do the magic stuff\n+\tfor(int ch=0; ch<2; ch++)\n+\t{\n+\t\t// Echo is output on the unfiltered component of the left channel and\n+\t\t// the filtered component of the right channel.\n+\t\tint32_t wet = (ch == 1) ? echo_output<<16 : 0;\n+\t\tint32_t dry = (ch == 0) ? echo_output<<16 : 0;\n+\t\tint32_t output = 0;\n+\n+\t\tfor(int i=0; i<19; i++)\n+\t\t{\n+\t\t\tuint16_t pan_index = m_voice_pan[i] + (ch * PAN_TABLE_CH_OFFSET);\n+\n+\t\t\t// Apply different volume tables on the dry and wet inputs.\n+\t\t\tdry -= (m_voice_output[i] * (int16_t) read_dsp_rom(pan_index + PAN_TABLE_DRY))<<2;\n+\t\t\twet -= (m_voice_output[i] * (int16_t) read_dsp_rom(pan_index + PAN_TABLE_WET))<<2;\n+\t\t}\n+\n+\t\t// Apply FIR filter on 'wet' input\n+\t\twet = fir(&m_filter[ch], wet >> 16);\n+\n+\t\t// in mode 2, we do this on the 'dry' input too\n+\t\tif(m_state == STATE_NORMAL2)\n+\t\t\tdry = fir(&m_alt_filter[ch], dry >> 16);\n+\n+\t\t// output goes through a delay line and attenuation\n+\t\toutput = (delay(&m_wet[ch], wet) + delay(&m_dry[ch], dry))<<2;\n+\n+\t\t// DSP round function\n+\t\toutput = (output + 0x8000) & ~0xffff;\n+\t\tm_out[ch] = output >> 16;\n+\n+\t\tif(m_delay_update)\n+\t\t{\n+\t\t\tdelay_update(&m_wet[ch]);\n+\t\t\tdelay_update(&m_dry[ch]);\n+\t\t}\n+\t}\n+\n+\tm_delay_update = 0;\n+\n+\t// after 6 samples, the next state is executed.\n+\tm_state_counter++;\n+\tif(m_state_counter > 5)\n+\t{\n+\t\tm_state_counter = 0;\n+\t\tm_state = m_next_state;\n+\t}\n+}\n+\n+// Apply the FIR filter used as the Q1 transfer function\n+int32_t qsound_hle_device::fir(struct qsound_fir *f, int16_t input)\n+{\n+\tint32_t output = 0, tap = 0;\n+\n+\tfor(; tap < (f->tap_count-1); tap++)\n+\t{\n+\t\toutput -= (f->taps[tap] * f->delay_line[f->delay_pos++])<<2;\n+\n+\t\tif(f->delay_pos >= f->tap_count-1)\n+\t\t\tf->delay_pos = 0;\n \t}\n+\n+\toutput -= (f->taps[tap] * input)<<2;\n+\n+\tf->delay_line[f->delay_pos++] = input;\n+\tif(f->delay_pos >= f->tap_count-1)\n+\t\tf->delay_pos = 0;\n+\n+\treturn output;\n+}\n+\n+// Apply delay line and component volume\n+int32_t qsound_hle_device::delay(struct qsound_delay *d, int32_t input)\n+{\n+\tint32_t output;\n+\n+\td->delay_line[d->write_pos++] = input>>16;\n+\tif(d->write_pos >= 51)\n+\t\td->write_pos = 0;\n+\n+\toutput = d->delay_line[d->read_pos++]*d->volume;\n+\tif(d->read_pos >= 51)\n+\t\td->read_pos = 0;\n+\n+\treturn output;\n+}\n+\n+// Update the delay read position to match new delay length\n+void qsound_hle_device::delay_update(struct qsound_delay *d)","path":"src/devices/sound/qsoundhle.cpp","position":728,"original_position":728,"commit_id":"7d9b0e407b2b7c9279fac91535c2d91e51c3e530","original_commit_id":"7d9b0e407b2b7c9279fac91535c2d91e51c3e530","user":{"login":"cuavas","id":9678431,"node_id":"MDQ6VXNlcjk2Nzg0MzE=","avatar_url":"https://avatars0.githubusercontent.com/u/9678431?v=4","gravatar_id":"","url":"https://api.github.com/users/cuavas","html_url":"https://github.com/cuavas","followers_url":"https://api.github.com/users/cuavas/followers","following_url":"https://api.github.com/users/cuavas/following{/other_user}","gists_url":"https://api.github.com/users/cuavas/gists{/gist_id}","starred_url":"https://api.github.com/users/cuavas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cuavas/subscriptions","organizations_url":"https://api.github.com/users/cuavas/orgs","repos_url":"https://api.github.com/users/cuavas/repos","events_url":"https://api.github.com/users/cuavas/events{/privacy}","received_events_url":"https://api.github.com/users/cuavas/received_events","type":"User","site_admin":false},"body":"Things that operate entirely on an inner structure/class like this should be members of the inner structure/class, otherwise you're passing a useless `this` pointer for the outer class and need an explicit parameter for the inner structure/class.","created_at":"2018-08-14T04:17:40Z","updated_at":"2018-08-14T04:28:41Z","html_url":"https://github.com/mamedev/mame/pull/3819#discussion_r209824305","pull_request_url":"https://api.github.com/repos/mamedev/mame/pulls/3819","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/mamedev/mame/pulls/comments/209824305"},"html":{"href":"https://github.com/mamedev/mame/pull/3819#discussion_r209824305"},"pull_request":{"href":"https://api.github.com/repos/mamedev/mame/pulls/3819"}}},"pull_request":{"url":"https://api.github.com/repos/mamedev/mame/pulls/3819","id":205874084,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA1ODc0MDg0","html_url":"https://github.com/mamedev/mame/pull/3819","diff_url":"https://github.com/mamedev/mame/pull/3819.diff","patch_url":"https://github.com/mamedev/mame/pull/3819.patch","issue_url":"https://api.github.com/repos/mamedev/mame/issues/3819","number":3819,"state":"open","locked":false,"title":"Add improved qsound_hle core","user":{"login":"Lord-Nightmare","id":2099814,"node_id":"MDQ6VXNlcjIwOTk4MTQ=","avatar_url":"https://avatars0.githubusercontent.com/u/2099814?v=4","gravatar_id":"","url":"https://api.github.com/users/Lord-Nightmare","html_url":"https://github.com/Lord-Nightmare","followers_url":"https://api.github.com/users/Lord-Nightmare/followers","following_url":"https://api.github.com/users/Lord-Nightmare/following{/other_user}","gists_url":"https://api.github.com/users/Lord-Nightmare/gists{/gist_id}","starred_url":"https://api.github.com/users/Lord-Nightmare/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Lord-Nightmare/subscriptions","organizations_url":"https://api.github.com/users/Lord-Nightmare/orgs","repos_url":"https://api.github.com/users/Lord-Nightmare/repos","events_url":"https://api.github.com/users/Lord-Nightmare/events{/privacy}","received_events_url":"https://api.github.com/users/Lord-Nightmare/received_events","type":"User","site_admin":false},"body":"This adds the rewritten QSound HLE by ValleyBell and superctr with full spatialization, among other accuracy improvements","created_at":"2018-08-02T22:03:02Z","updated_at":"2018-08-14T04:28:41Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cbd7960a243672b75632f6ac7af48bb1dae171f2","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/mamedev/mame/pulls/3819/commits","review_comments_url":"https://api.github.com/repos/mamedev/mame/pulls/3819/comments","review_comment_url":"https://api.github.com/repos/mamedev/mame/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mamedev/mame/issues/3819/comments","statuses_url":"https://api.github.com/repos/mamedev/mame/statuses/7d9b0e407b2b7c9279fac91535c2d91e51c3e530","head":{"label":"superctr:qsound_hle_mame200","ref":"qsound_hle_mame200","sha":"7d9b0e407b2b7c9279fac91535c2d91e51c3e530","user":{"login":"superctr","id":1159409,"node_id":"MDQ6VXNlcjExNTk0MDk=","avatar_url":"https://avatars3.githubusercontent.com/u/1159409?v=4","gravatar_id":"","url":"https://api.github.com/users/superctr","html_url":"https://github.com/superctr","followers_url":"https://api.github.com/users/superctr/followers","following_url":"https://api.github.com/users/superctr/following{/other_user}","gists_url":"https://api.github.com/users/superctr/gists{/gist_id}","starred_url":"https://api.github.com/users/superctr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/superctr/subscriptions","organizations_url":"https://api.github.com/users/superctr/orgs","repos_url":"https://api.github.com/users/superctr/repos","events_url":"https://api.github.com/users/superctr/events{/privacy}","received_events_url":"https://api.github.com/users/superctr/received_events","type":"User","site_admin":false},"repo":{"id":33266402,"node_id":"MDEwOlJlcG9zaXRvcnkzMzI2NjQwMg==","name":"mame","full_name":"superctr/mame","owner":{"login":"superctr","id":1159409,"node_id":"MDQ6VXNlcjExNTk0MDk=","avatar_url":"https://avatars3.githubusercontent.com/u/1159409?v=4","gravatar_id":"","url":"https://api.github.com/users/superctr","html_url":"https://github.com/superctr","followers_url":"https://api.github.com/users/superctr/followers","following_url":"https://api.github.com/users/superctr/following{/other_user}","gists_url":"https://api.github.com/users/superctr/gists{/gist_id}","starred_url":"https://api.github.com/users/superctr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/superctr/subscriptions","organizations_url":"https://api.github.com/users/superctr/orgs","repos_url":"https://api.github.com/users/superctr/repos","events_url":"https://api.github.com/users/superctr/events{/privacy}","received_events_url":"https://api.github.com/users/superctr/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/superctr/mame","description":"MAME - Multiple Arcade Machine Emulator","fork":true,"url":"https://api.github.com/repos/superctr/mame","forks_url":"https://api.github.com/repos/superctr/mame/forks","keys_url":"https://api.github.com/repos/superctr/mame/keys{/key_id}","collaborators_url":"https://api.github.com/repos/superctr/mame/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/superctr/mame/teams","hooks_url":"https://api.github.com/repos/superctr/mame/hooks","issue_events_url":"https://api.github.com/repos/superctr/mame/issues/events{/number}","events_url":"https://api.github.com/repos/superctr/mame/events","assignees_url":"https://api.github.com/repos/superctr/mame/assignees{/user}","branches_url":"https://api.github.com/repos/superctr/mame/branches{/branch}","tags_url":"https://api.github.com/repos/superctr/mame/tags","blobs_url":"https://api.github.com/repos/superctr/mame/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/superctr/mame/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/superctr/mame/git/refs{/sha}","trees_url":"https://api.github.com/repos/superctr/mame/git/trees{/sha}","statuses_url":"https://api.github.com/repos/superctr/mame/statuses/{sha}","languages_url":"https://api.github.com/repos/superctr/mame/languages","stargazers_url":"https://api.github.com/repos/superctr/mame/stargazers","contributors_url":"https://api.github.com/repos/superctr/mame/contributors","subscribers_url":"https://api.github.com/repos/superctr/mame/subscribers","subscription_url":"https://api.github.com/repos/superctr/mame/subscription","commits_url":"https://api.github.com/repos/superctr/mame/commits{/sha}","git_commits_url":"https://api.github.com/repos/superctr/mame/git/commits{/sha}","comments_url":"https://api.github.com/repos/superctr/mame/comments{/number}","issue_comment_url":"https://api.github.com/repos/superctr/mame/issues/comments{/number}","contents_url":"https://api.github.com/repos/superctr/mame/contents/{+path}","compare_url":"https://api.github.com/repos/superctr/mame/compare/{base}...{head}","merges_url":"https://api.github.com/repos/superctr/mame/merges","archive_url":"https://api.github.com/repos/superctr/mame/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/superctr/mame/downloads","issues_url":"https://api.github.com/repos/superctr/mame/issues{/number}","pulls_url":"https://api.github.com/repos/superctr/mame/pulls{/number}","milestones_url":"https://api.github.com/repos/superctr/mame/milestones{/number}","notifications_url":"https://api.github.com/repos/superctr/mame/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/superctr/mame/labels{/name}","releases_url":"https://api.github.com/repos/superctr/mame/releases{/id}","deployments_url":"https://api.github.com/repos/superctr/mame/deployments","created_at":"2015-04-01T18:54:40Z","updated_at":"2016-08-17T03:45:06Z","pushed_at":"2018-08-12T15:29:52Z","git_url":"git://github.com/superctr/mame.git","ssh_url":"git@github.com:superctr/mame.git","clone_url":"https://github.com/superctr/mame.git","svn_url":"https://github.com/superctr/mame","homepage":null,"size":748207,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"mamedev:master","ref":"master","sha":"781f17725a8fd4f411ddbb7eb763283166179a25","user":{"login":"mamedev","id":9024458,"node_id":"MDEyOk9yZ2FuaXphdGlvbjkwMjQ0NTg=","avatar_url":"https://avatars3.githubusercontent.com/u/9024458?v=4","gravatar_id":"","url":"https://api.github.com/users/mamedev","html_url":"https://github.com/mamedev","followers_url":"https://api.github.com/users/mamedev/followers","following_url":"https://api.github.com/users/mamedev/following{/other_user}","gists_url":"https://api.github.com/users/mamedev/gists{/gist_id}","starred_url":"https://api.github.com/users/mamedev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mamedev/subscriptions","organizations_url":"https://api.github.com/users/mamedev/orgs","repos_url":"https://api.github.com/users/mamedev/repos","events_url":"https://api.github.com/users/mamedev/events{/privacy}","received_events_url":"https://api.github.com/users/mamedev/received_events","type":"Organization","site_admin":false},"repo":{"id":14303048,"node_id":"MDEwOlJlcG9zaXRvcnkxNDMwMzA0OA==","name":"mame","full_name":"mamedev/mame","owner":{"login":"mamedev","id":9024458,"node_id":"MDEyOk9yZ2FuaXphdGlvbjkwMjQ0NTg=","avatar_url":"https://avatars3.githubusercontent.com/u/9024458?v=4","gravatar_id":"","url":"https://api.github.com/users/mamedev","html_url":"https://github.com/mamedev","followers_url":"https://api.github.com/users/mamedev/followers","following_url":"https://api.github.com/users/mamedev/following{/other_user}","gists_url":"https://api.github.com/users/mamedev/gists{/gist_id}","starred_url":"https://api.github.com/users/mamedev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mamedev/subscriptions","organizations_url":"https://api.github.com/users/mamedev/orgs","repos_url":"https://api.github.com/users/mamedev/repos","events_url":"https://api.github.com/users/mamedev/events{/privacy}","received_events_url":"https://api.github.com/users/mamedev/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mamedev/mame","description":"MAME","fork":false,"url":"https://api.github.com/repos/mamedev/mame","forks_url":"https://api.github.com/repos/mamedev/mame/forks","keys_url":"https://api.github.com/repos/mamedev/mame/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mamedev/mame/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mamedev/mame/teams","hooks_url":"https://api.github.com/repos/mamedev/mame/hooks","issue_events_url":"https://api.github.com/repos/mamedev/mame/issues/events{/number}","events_url":"https://api.github.com/repos/mamedev/mame/events","assignees_url":"https://api.github.com/repos/mamedev/mame/assignees{/user}","branches_url":"https://api.github.com/repos/mamedev/mame/branches{/branch}","tags_url":"https://api.github.com/repos/mamedev/mame/tags","blobs_url":"https://api.github.com/repos/mamedev/mame/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mamedev/mame/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mamedev/mame/git/refs{/sha}","trees_url":"https://api.github.com/repos/mamedev/mame/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mamedev/mame/statuses/{sha}","languages_url":"https://api.github.com/repos/mamedev/mame/languages","stargazers_url":"https://api.github.com/repos/mamedev/mame/stargazers","contributors_url":"https://api.github.com/repos/mamedev/mame/contributors","subscribers_url":"https://api.github.com/repos/mamedev/mame/subscribers","subscription_url":"https://api.github.com/repos/mamedev/mame/subscription","commits_url":"https://api.github.com/repos/mamedev/mame/commits{/sha}","git_commits_url":"https://api.github.com/repos/mamedev/mame/git/commits{/sha}","comments_url":"https://api.github.com/repos/mamedev/mame/comments{/number}","issue_comment_url":"https://api.github.com/repos/mamedev/mame/issues/comments{/number}","contents_url":"https://api.github.com/repos/mamedev/mame/contents/{+path}","compare_url":"https://api.github.com/repos/mamedev/mame/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mamedev/mame/merges","archive_url":"https://api.github.com/repos/mamedev/mame/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mamedev/mame/downloads","issues_url":"https://api.github.com/repos/mamedev/mame/issues{/number}","pulls_url":"https://api.github.com/repos/mamedev/mame/pulls{/number}","milestones_url":"https://api.github.com/repos/mamedev/mame/milestones{/number}","notifications_url":"https://api.github.com/repos/mamedev/mame/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mamedev/mame/labels{/name}","releases_url":"https://api.github.com/repos/mamedev/mame/releases{/id}","deployments_url":"https://api.github.com/repos/mamedev/mame/deployments","created_at":"2013-11-11T14:32:13Z","updated_at":"2018-08-14T03:50:43Z","pushed_at":"2018-08-14T03:50:30Z","git_url":"git://github.com/mamedev/mame.git","ssh_url":"git@github.com:mamedev/mame.git","clone_url":"https://github.com/mamedev/mame.git","svn_url":"https://github.com/mamedev/mame","homepage":"","size":772080,"stargazers_count":3040,"watchers_count":3040,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":755,"mirror_url":null,"archived":false,"open_issues_count":230,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":755,"open_issues":230,"watchers":3040,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mamedev/mame/pulls/3819"},"html":{"href":"https://github.com/mamedev/mame/pull/3819"},"issue":{"href":"https://api.github.com/repos/mamedev/mame/issues/3819"},"comments":{"href":"https://api.github.com/repos/mamedev/mame/issues/3819/comments"},"review_comments":{"href":"https://api.github.com/repos/mamedev/mame/pulls/3819/comments"},"review_comment":{"href":"https://api.github.com/repos/mamedev/mame/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mamedev/mame/pulls/3819/commits"},"statuses":{"href":"https://api.github.com/repos/mamedev/mame/statuses/7d9b0e407b2b7c9279fac91535c2d91e51c3e530"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"cuavas"}}