trunk/src/emu/sound/ymz770.c
| r26454 | r26455 | |
| 24 | 24 | { |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | |
| 27 | 28 | //------------------------------------------------- |
| 28 | 29 | // device_start - device-specific startup |
| 29 | 30 | //------------------------------------------------- |
| 31 | |
| 30 | 32 | void ymz770_device::device_start() |
| 31 | 33 | { |
| 32 | 34 | // create the stream |
| 33 | 35 | m_stream = machine().sound().stream_alloc(*this, 0, 2, 16000, this); |
| 34 | | rom_base = device().machine().root_device().memregion(":ymz770")->base(); |
| 35 | | rom_size = device().machine().root_device().memregion(":ymz770")->bytes() * 8; |
| 36 | m_rom_base = device().machine().root_device().memregion(":ymz770")->base(); |
| 37 | m_rom_size = device().machine().root_device().memregion(":ymz770")->bytes() * 8; |
| 36 | 38 | |
| 37 | 39 | for (int i = 0; i < 8; i++) |
| 38 | 40 | { |
| 39 | | channels[i].is_playing = false; |
| 40 | | channels[i].is_seq_playing = false; |
| 41 | | channels[i].decoder = new mpeg_audio(rom_base, mpeg_audio::AMM, false, 0); |
| 41 | m_channels[i].is_playing = false; |
| 42 | m_channels[i].is_seq_playing = false; |
| 43 | m_channels[i].decoder = new mpeg_audio(m_rom_base, mpeg_audio::AMM, false, 0); |
| 42 | 44 | } |
| 43 | 45 | |
| 44 | 46 | // register for save states |
| 45 | 47 | save_item(NAME(m_cur_reg)); |
| 46 | 48 | for (int i = 0; i < 8; i++) |
| 47 | 49 | { |
| 48 | | save_item(NAME(channels[i].phrase), i); |
| 49 | | save_item(NAME(channels[i].pan), i); |
| 50 | | save_item(NAME(channels[i].volume), i); |
| 51 | | save_item(NAME(channels[i].control), i); |
| 52 | | save_item(NAME(channels[i].is_playing), i); |
| 53 | | save_item(NAME(channels[i].last_block), i); |
| 54 | | save_item(NAME(channels[i].output_remaining), i); |
| 55 | | save_item(NAME(channels[i].output_ptr), i); |
| 56 | | save_item(NAME(channels[i].pptr), i); |
| 57 | | save_item(NAME(channels[i].sequence), i); |
| 58 | | save_item(NAME(channels[i].seqcontrol), i); |
| 59 | | save_item(NAME(channels[i].seqdelay), i); |
| 60 | | save_item(NAME(channels[i].is_seq_playing), i); |
| 61 | | save_item(NAME(channels[i].output_data), i); |
| 50 | save_item(NAME(m_channels[i].phrase), i); |
| 51 | save_item(NAME(m_channels[i].pan), i); |
| 52 | save_item(NAME(m_channels[i].volume), i); |
| 53 | save_item(NAME(m_channels[i].control), i); |
| 54 | save_item(NAME(m_channels[i].is_playing), i); |
| 55 | save_item(NAME(m_channels[i].last_block), i); |
| 56 | save_item(NAME(m_channels[i].output_remaining), i); |
| 57 | save_item(NAME(m_channels[i].output_ptr), i); |
| 58 | save_item(NAME(m_channels[i].pptr), i); |
| 59 | save_item(NAME(m_channels[i].sequence), i); |
| 60 | save_item(NAME(m_channels[i].seqcontrol), i); |
| 61 | save_item(NAME(m_channels[i].seqdelay), i); |
| 62 | save_item(NAME(m_channels[i].is_seq_playing), i); |
| 63 | save_item(NAME(m_channels[i].output_data), i); |
| 62 | 64 | } |
| 63 | 65 | } |
| 64 | 66 | |
| r26454 | r26455 | |
| 71 | 73 | { |
| 72 | 74 | for (int i = 0; i < 8; i++) |
| 73 | 75 | { |
| 74 | | channels[i].phrase = 0; |
| 75 | | channels[i].pan = 8; |
| 76 | | channels[i].volume = 0; |
| 77 | | channels[i].control = 0; |
| 78 | | channels[i].sequence = 0; |
| 79 | | channels[i].seqcontrol = 0; |
| 80 | | channels[i].seqdelay = 0; |
| 81 | | channels[i].is_playing = false; |
| 82 | | channels[i].is_seq_playing = false; |
| 76 | m_channels[i].phrase = 0; |
| 77 | m_channels[i].pan = 8; |
| 78 | m_channels[i].volume = 0; |
| 79 | m_channels[i].control = 0; |
| 80 | m_channels[i].sequence = 0; |
| 81 | m_channels[i].seqcontrol = 0; |
| 82 | m_channels[i].seqdelay = 0; |
| 83 | m_channels[i].is_playing = false; |
| 84 | m_channels[i].is_seq_playing = false; |
| 83 | 85 | } |
| 84 | 86 | } |
| 85 | 87 | |
| 88 | |
| 86 | 89 | //------------------------------------------------- |
| 87 | 90 | // sound_stream_update - handle update requests for |
| 88 | 91 | // our sound stream |
| r26454 | r26455 | |
| 104 | 107 | |
| 105 | 108 | for (ch = 0; ch < 8; ch++) |
| 106 | 109 | { |
| 107 | | if (channels[ch].is_seq_playing) |
| 110 | if (m_channels[ch].is_seq_playing) |
| 108 | 111 | { |
| 109 | | if (channels[ch].seqdelay != 0) |
| 112 | if (m_channels[ch].seqdelay != 0) |
| 110 | 113 | { |
| 111 | | channels[ch].seqdelay--; |
| 114 | m_channels[ch].seqdelay--; |
| 112 | 115 | } |
| 113 | 116 | else |
| 114 | 117 | { |
| 115 | | int reg = *channels[ch].seqdata++; |
| 116 | | UINT8 data = *channels[ch].seqdata++; |
| 118 | int reg = *m_channels[ch].seqdata++; |
| 119 | UINT8 data = *m_channels[ch].seqdata++; |
| 117 | 120 | switch (reg) |
| 118 | 121 | { |
| 119 | 122 | case 0x0f: |
| 120 | | if (channels[ch].seqcontrol & 1) |
| 123 | if (m_channels[ch].seqcontrol & 1) |
| 121 | 124 | { |
| 122 | | UINT8 sqn = channels[ch].sequence; |
| 123 | | UINT32 pptr = rom_base[(4*sqn)+1+0x400]<<16 | rom_base[(4*sqn)+2+0x400]<<8 | rom_base[(4*sqn)+3+0x400]; |
| 124 | | channels[ch].seqdata = &rom_base[pptr]; |
| 125 | UINT8 sqn = m_channels[ch].sequence; |
| 126 | UINT32 pptr = m_rom_base[(4*sqn)+1+0x400]<<16 | m_rom_base[(4*sqn)+2+0x400]<<8 | m_rom_base[(4*sqn)+3+0x400]; |
| 127 | m_channels[ch].seqdata = &m_rom_base[pptr]; |
| 125 | 128 | } |
| 126 | 129 | else |
| 127 | 130 | { |
| 128 | | channels[ch].is_seq_playing = false; |
| 131 | m_channels[ch].is_seq_playing = false; |
| 129 | 132 | } |
| 130 | 133 | break; |
| 131 | 134 | case 0x0e: |
| 132 | | channels[ch].seqdelay = 32 - 1; |
| 135 | m_channels[ch].seqdelay = 32 - 1; |
| 133 | 136 | break; |
| 134 | 137 | default: |
| 135 | 138 | internal_reg_write(reg, data); |
| r26454 | r26455 | |
| 137 | 140 | } |
| 138 | 141 | } |
| 139 | 142 | } |
| 140 | | if (channels[ch].is_playing) |
| 143 | if (m_channels[ch].is_playing) |
| 141 | 144 | { |
| 142 | | if (channels[ch].output_remaining > 0) |
| 145 | if (m_channels[ch].output_remaining > 0) |
| 143 | 146 | { |
| 144 | | mix += (channels[ch].output_data[channels[ch].output_ptr++]*2*channels[ch].volume); |
| 145 | | channels[ch].output_remaining--; |
| 147 | mix += (m_channels[ch].output_data[m_channels[ch].output_ptr++]*2*m_channels[ch].volume); |
| 148 | m_channels[ch].output_remaining--; |
| 146 | 149 | } |
| 147 | 150 | else |
| 148 | 151 | { |
| 149 | 152 | retry: |
| 150 | | if (channels[ch].last_block) |
| 153 | if (m_channels[ch].last_block) |
| 151 | 154 | { |
| 152 | | if (channels[ch].control & 1) |
| 155 | if (m_channels[ch].control & 1) |
| 153 | 156 | { |
| 154 | | UINT8 phrase = channels[ch].phrase; |
| 155 | | channels[ch].pptr = 8*(rom_base[(4*phrase)+1]<<16 | rom_base[(4*phrase)+2]<<8 | rom_base[(4*phrase)+3]); |
| 157 | UINT8 phrase = m_channels[ch].phrase; |
| 158 | m_channels[ch].pptr = 8*(m_rom_base[(4*phrase)+1]<<16 | m_rom_base[(4*phrase)+2]<<8 | m_rom_base[(4*phrase)+3]); |
| 156 | 159 | } |
| 157 | 160 | else |
| 158 | 161 | { |
| 159 | | channels[ch].is_playing = false; |
| 162 | m_channels[ch].is_playing = false; |
| 160 | 163 | } |
| 161 | 164 | } |
| 162 | 165 | |
| 163 | | if (channels[ch].is_playing) |
| 166 | if (m_channels[ch].is_playing) |
| 164 | 167 | { |
| 165 | 168 | int sample_rate, channel_count; |
| 166 | | if(!channels[ch].decoder->decode_buffer(channels[ch].pptr, |
| 167 | | rom_size, |
| 168 | | channels[ch].output_data, |
| 169 | | channels[ch].output_remaining, |
| 169 | if(!m_channels[ch].decoder->decode_buffer(m_channels[ch].pptr, |
| 170 | m_rom_size, |
| 171 | m_channels[ch].output_data, |
| 172 | m_channels[ch].output_remaining, |
| 170 | 173 | sample_rate, |
| 171 | 174 | channel_count)) |
| 172 | 175 | { |
| 173 | | channels[ch].last_block = true; |
| 176 | m_channels[ch].last_block = true; |
| 174 | 177 | goto retry; |
| 175 | 178 | } |
| 176 | 179 | |
| 177 | | channels[ch].last_block = channels[ch].output_remaining < 1152; |
| 178 | | channels[ch].output_remaining--; |
| 179 | | channels[ch].output_ptr = 1; |
| 180 | m_channels[ch].last_block = m_channels[ch].output_remaining < 1152; |
| 181 | m_channels[ch].output_remaining--; |
| 182 | m_channels[ch].output_ptr = 1; |
| 180 | 183 | |
| 181 | | mix += (channels[ch].output_data[0]*2*channels[ch].volume); |
| 184 | mix += (m_channels[ch].output_data[0]*2*m_channels[ch].volume); |
| 182 | 185 | } |
| 183 | 186 | } |
| 184 | 187 | } |
| r26454 | r26455 | |
| 188 | 191 | } |
| 189 | 192 | } |
| 190 | 193 | |
| 194 | |
| 191 | 195 | //------------------------------------------------- |
| 192 | | // read - read from the chip's registers |
| 196 | // write - write to the chip's registers |
| 193 | 197 | //------------------------------------------------- |
| 194 | 198 | |
| 195 | | READ8_MEMBER( ymz770_device::read ) |
| 199 | WRITE8_MEMBER( ymz770_device::write ) |
| 196 | 200 | { |
| 197 | | return 0; |
| 201 | if (offset & 1) |
| 202 | { |
| 203 | m_stream->update(); |
| 204 | internal_reg_write(m_cur_reg, data); |
| 205 | } |
| 206 | else |
| 207 | { |
| 208 | m_cur_reg = data; |
| 209 | } |
| 198 | 210 | } |
| 199 | 211 | |
| 212 | |
| 200 | 213 | void ymz770_device::internal_reg_write(UINT8 reg, UINT8 data) |
| 201 | 214 | { |
| 202 | 215 | if (reg >= 0x40 && reg <= 0x5f) |
| r26454 | r26455 | |
| 206 | 219 | switch (reg & 0x03) |
| 207 | 220 | { |
| 208 | 221 | case 0: |
| 209 | | channels[voice].phrase = data; |
| 222 | m_channels[voice].phrase = data; |
| 210 | 223 | break; |
| 211 | 224 | |
| 212 | 225 | case 1: |
| 213 | | channels[voice].volume = data; |
| 226 | m_channels[voice].volume = data; |
| 214 | 227 | break; |
| 215 | 228 | |
| 216 | 229 | case 2: |
| 217 | | channels[voice].pan = data; |
| 230 | m_channels[voice].pan = data; |
| 218 | 231 | break; |
| 219 | 232 | |
| 220 | 233 | case 3: |
| 221 | 234 | if (data & 6) |
| 222 | 235 | { |
| 223 | | UINT8 phrase = channels[voice].phrase; |
| 224 | | channels[voice].pptr = 8*(rom_base[(4*phrase)+1]<<16 | rom_base[(4*phrase)+2]<<8 | rom_base[(4*phrase)+3]); |
| 225 | | channels[voice].output_remaining = 0; |
| 226 | | channels[voice].output_ptr = 0; |
| 227 | | channels[voice].last_block = false; |
| 236 | UINT8 phrase = m_channels[voice].phrase; |
| 237 | m_channels[voice].pptr = 8*(m_rom_base[(4*phrase)+1]<<16 | m_rom_base[(4*phrase)+2]<<8 | m_rom_base[(4*phrase)+3]); |
| 238 | m_channels[voice].output_remaining = 0; |
| 239 | m_channels[voice].output_ptr = 0; |
| 240 | m_channels[voice].last_block = false; |
| 228 | 241 | |
| 229 | | channels[voice].is_playing = true; |
| 242 | m_channels[voice].is_playing = true; |
| 230 | 243 | } |
| 231 | 244 | else |
| 232 | 245 | { |
| 233 | | channels[voice].is_playing = false; |
| 246 | m_channels[voice].is_playing = false; |
| 234 | 247 | } |
| 235 | 248 | |
| 236 | | channels[voice].control = data; |
| 249 | m_channels[voice].control = data; |
| 237 | 250 | break; |
| 238 | 251 | } |
| 239 | 252 | } |
| r26454 | r26455 | |
| 244 | 257 | switch (reg & 0x0f) |
| 245 | 258 | { |
| 246 | 259 | case 0: |
| 247 | | channels[voice].sequence = data; |
| 260 | m_channels[voice].sequence = data; |
| 248 | 261 | break; |
| 249 | 262 | case 1: |
| 250 | 263 | if (data & 6) |
| 251 | 264 | { |
| 252 | | UINT8 sqn = channels[voice].sequence; |
| 253 | | UINT32 pptr = rom_base[(4*sqn)+1+0x400]<<16 | rom_base[(4*sqn)+2+0x400]<<8 | rom_base[(4*sqn)+3+0x400]; |
| 254 | | channels[voice].seqdata = &rom_base[pptr]; |
| 255 | | channels[voice].seqdelay = 0; |
| 256 | | channels[voice].is_seq_playing = true; |
| 265 | UINT8 sqn = m_channels[voice].sequence; |
| 266 | UINT32 pptr = m_rom_base[(4*sqn)+1+0x400]<<16 | m_rom_base[(4*sqn)+2+0x400]<<8 | m_rom_base[(4*sqn)+3+0x400]; |
| 267 | m_channels[voice].seqdata = &m_rom_base[pptr]; |
| 268 | m_channels[voice].seqdelay = 0; |
| 269 | m_channels[voice].is_seq_playing = true; |
| 257 | 270 | } |
| 258 | 271 | else |
| 259 | 272 | { |
| 260 | | channels[voice].is_seq_playing = false; |
| 273 | m_channels[voice].is_seq_playing = false; |
| 261 | 274 | } |
| 262 | 275 | |
| 263 | | channels[voice].seqcontrol = data; |
| 276 | m_channels[voice].seqcontrol = data; |
| 264 | 277 | break; |
| 265 | 278 | |
| 266 | 279 | default: |
| r26454 | r26455 | |
| 268 | 281 | } |
| 269 | 282 | } |
| 270 | 283 | } |
| 271 | | |
| 272 | | //------------------------------------------------- |
| 273 | | // write - write to the chip's registers |
| 274 | | //------------------------------------------------- |
| 275 | | |
| 276 | | WRITE8_MEMBER( ymz770_device::write ) |
| 277 | | { |
| 278 | | if (offset & 1) |
| 279 | | { |
| 280 | | m_stream->update(); |
| 281 | | internal_reg_write(m_cur_reg, data); |
| 282 | | } |
| 283 | | else |
| 284 | | { |
| 285 | | m_cur_reg = data; |
| 286 | | } |
| 287 | | } |