trunk/src/emu/sound/tms5110.c
| r249013 | r249014 | |
| 350 | 350 | int i, bitout; |
| 351 | 351 | INT32 this_sample; |
| 352 | 352 | |
| 353 | | /* if we're not speaking, fill with nothingness */ |
| 354 | | if (!m_TALKD) |
| 355 | | goto empty; |
| 356 | | |
| 357 | | render: |
| 358 | 353 | /* loop until the buffer is full or we've stopped speaking */ |
| 359 | | while ((size > 0) && m_TALKD) |
| 354 | while (size > 0) |
| 360 | 355 | { |
| 361 | | |
| 362 | | /* if we're ready for a new frame to be applied, i.e. when IP=0, PC=12, Sub=1 |
| 363 | | * (In reality, the frame was really loaded incrementally during the entire IP=0 |
| 364 | | * PC=x time period, but it doesn't affect anything until IP=0 PC=12 happens) |
| 365 | | */ |
| 366 | | if ((m_IP == 0) && (m_PC == 12) && (m_subcycle == 1)) |
| 356 | if(m_TALKD) // speaking |
| 367 | 357 | { |
| 368 | | // HACK for regression testing, be sure to comment out before release! |
| 369 | | //m_RNG = 0x1234; |
| 370 | | // end HACK |
| 358 | /* if we're ready for a new frame to be applied, i.e. when IP=0, PC=12, Sub=1 |
| 359 | * (In reality, the frame was really loaded incrementally during the entire IP=0 |
| 360 | * PC=x time period, but it doesn't affect anything until IP=0 PC=12 happens) |
| 361 | */ |
| 362 | if ((m_IP == 0) && (m_PC == 12) && (m_subcycle == 1)) |
| 363 | { |
| 364 | // HACK for regression testing, be sure to comment out before release! |
| 365 | //m_RNG = 0x1234; |
| 366 | // end HACK |
| 371 | 367 | |
| 372 | 368 | #ifdef PERFECT_INTERPOLATION_HACK |
| 373 | | /* remember previous frame energy, pitch, and coefficients */ |
| 374 | | m_old_frame_energy_idx = m_new_frame_energy_idx; |
| 375 | | m_old_frame_pitch_idx = m_new_frame_pitch_idx; |
| 376 | | for (i = 0; i < m_coeff->num_k; i++) |
| 377 | | m_old_frame_k_idx[i] = m_new_frame_k_idx[i]; |
| 369 | /* remember previous frame energy, pitch, and coefficients */ |
| 370 | m_old_frame_energy_idx = m_new_frame_energy_idx; |
| 371 | m_old_frame_pitch_idx = m_new_frame_pitch_idx; |
| 372 | for (i = 0; i < m_coeff->num_k; i++) |
| 373 | m_old_frame_k_idx[i] = m_new_frame_k_idx[i]; |
| 378 | 374 | #endif |
| 379 | 375 | |
| 380 | | /* Parse a new frame into the new_target_energy, new_target_pitch and new_target_k[] */ |
| 381 | | parse_frame(); |
| 376 | /* Parse a new frame into the new_target_energy, new_target_pitch and new_target_k[] */ |
| 377 | parse_frame(); |
| 382 | 378 | |
| 383 | | // if the new frame is unvoiced (or silenced via ZPAR), be sure to zero out the k5-k10 parameters |
| 384 | | // NOTE: this is probably the bug the tms5100/tmc0280 has, pre-rev D, I think. |
| 385 | | // GUESS: Pre-rev D versions start zeroing k5-k10 immediately upon new frame load regardless of interpolation inhibit |
| 386 | | // I.e. ZPAR = /TALKD || (PC>5&&P=0) |
| 387 | | // GUESS: D and later versions only start or stop zeroing k5-k10 at the IP7->IP0 transition AFTER the frame |
| 388 | | // I.e. ZPAR = /TALKD || (PC>5&&OLDP) |
| 379 | // if the new frame is unvoiced (or silenced via ZPAR), be sure to zero out the k5-k10 parameters |
| 380 | // NOTE: this is probably the bug the tms5100/tmc0280 has, pre-rev D, I think. |
| 381 | // GUESS: Pre-rev D versions start zeroing k5-k10 immediately upon new frame load regardless of interpolation inhibit |
| 382 | // I.e. ZPAR = /TALKD || (PC>5&&P=0) |
| 383 | // GUESS: D and later versions only start or stop zeroing k5-k10 at the IP7->IP0 transition AFTER the frame |
| 384 | // I.e. ZPAR = /TALKD || (PC>5&&OLDP) |
| 389 | 385 | #ifdef PERFECT_INTERPOLATION_HACK |
| 390 | | m_old_uv_zpar = m_uv_zpar; |
| 391 | | m_old_zpar = m_zpar; // unset old zpar on new frame |
| 386 | m_old_uv_zpar = m_uv_zpar; |
| 387 | m_old_zpar = m_zpar; // unset old zpar on new frame |
| 392 | 388 | #endif |
| 393 | | m_zpar = 0; |
| 394 | | //m_uv_zpar = (OLD_FRAME_UNVOICED_FLAG||m_zpar); // GUESS: fixed version in tmc0280d/tms5100a/cd280x/tms5110 |
| 395 | | m_uv_zpar = (NEW_FRAME_UNVOICED_FLAG||m_zpar); // GUESS: buggy version in tmc0280/tms5100 |
| 389 | m_zpar = 0; |
| 390 | //m_uv_zpar = (OLD_FRAME_UNVOICED_FLAG||m_zpar); // GUESS: fixed version in tmc0280d/tms5100a/cd280x/tms5110 |
| 391 | m_uv_zpar = (NEW_FRAME_UNVOICED_FLAG||m_zpar); // GUESS: buggy version in tmc0280/tms5100 |
| 396 | 392 | |
| 397 | | /* if the new frame is a stop frame, unset both TALK and SPEN (via TCON). TALKD remains active while the energy is ramping to 0. */ |
| 398 | | if (NEW_FRAME_STOP_FLAG == 1) |
| 399 | | { |
| 400 | | m_TALK = m_SPEN = 0; |
| 401 | | } |
| 393 | /* if the new frame is a stop frame, unset both TALK and SPEN (via TCON). TALKD remains active while the energy is ramping to 0. */ |
| 394 | if (NEW_FRAME_STOP_FLAG == 1) |
| 395 | { |
| 396 | m_TALK = m_SPEN = 0; |
| 397 | } |
| 402 | 398 | |
| 403 | | /* in all cases where interpolation would be inhibited, set the inhibit flag; otherwise clear it. |
| 404 | | Interpolation inhibit cases: |
| 405 | | * Old frame was voiced, new is unvoiced |
| 406 | | * Old frame was silence/zero energy, new has nonzero energy |
| 407 | | * Old frame was unvoiced, new is voiced (note this is the case on the patent but may not be correct on the real final chip) |
| 408 | | */ |
| 409 | | if ( ((OLD_FRAME_UNVOICED_FLAG == 0) && (NEW_FRAME_UNVOICED_FLAG == 1)) |
| 410 | | || ((OLD_FRAME_UNVOICED_FLAG == 1) && (NEW_FRAME_UNVOICED_FLAG == 0)) /* this line needs further investigation, starwars tie fighters may sound better without it */ |
| 411 | | || ((OLD_FRAME_SILENCE_FLAG == 1) && (NEW_FRAME_SILENCE_FLAG == 0)) ) |
| 412 | | m_inhibit = 1; |
| 413 | | else // normal frame, normal interpolation |
| 414 | | m_inhibit = 0; |
| 399 | /* in all cases where interpolation would be inhibited, set the inhibit flag; otherwise clear it. |
| 400 | Interpolation inhibit cases: |
| 401 | * Old frame was voiced, new is unvoiced |
| 402 | * Old frame was silence/zero energy, new has nonzero energy |
| 403 | * Old frame was unvoiced, new is voiced (note this is the case on the patent but may not be correct on the real final chip) |
| 404 | */ |
| 405 | if ( ((OLD_FRAME_UNVOICED_FLAG == 0) && (NEW_FRAME_UNVOICED_FLAG == 1)) |
| 406 | || ((OLD_FRAME_UNVOICED_FLAG == 1) && (NEW_FRAME_UNVOICED_FLAG == 0)) /* this line needs further investigation, starwars tie fighters may sound better without it */ |
| 407 | || ((OLD_FRAME_SILENCE_FLAG == 1) && (NEW_FRAME_SILENCE_FLAG == 0)) ) |
| 408 | m_inhibit = 1; |
| 409 | else // normal frame, normal interpolation |
| 410 | m_inhibit = 0; |
| 415 | 411 | |
| 416 | 412 | #ifdef DEBUG_GENERATION |
| 417 | | /* Debug info for current parsed frame */ |
| 418 | | fprintf(stderr, "OLDE: %d; OLDP: %d; ", m_OLDE, m_OLDP); |
| 419 | | fprintf(stderr,"Processing new frame: "); |
| 420 | | if (m_inhibit == 0) |
| 421 | | fprintf(stderr, "Normal Frame\n"); |
| 422 | | else |
| 423 | | fprintf(stderr,"Interpolation Inhibited\n"); |
| 424 | | fprintf(stderr,"*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_current_energy, m_current_pitch, m_current_k[0], m_current_k[1], m_current_k[2], m_current_k[3], m_current_k[4], m_current_k[5], m_current_k[6], m_current_k[7], m_current_k[8], m_current_k[9]); |
| 425 | | fprintf(stderr,"*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n", |
| 426 | | (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)), |
| 427 | | m_new_frame_energy_idx, |
| 428 | | (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)), |
| 429 | | (m_coeff->ktable[0][m_new_frame_k_idx[0]] * (1-m_zpar)), |
| 430 | | (m_coeff->ktable[1][m_new_frame_k_idx[1]] * (1-m_zpar)), |
| 431 | | (m_coeff->ktable[2][m_new_frame_k_idx[2]] * (1-m_zpar)), |
| 432 | | (m_coeff->ktable[3][m_new_frame_k_idx[3]] * (1-m_zpar)), |
| 433 | | (m_coeff->ktable[4][m_new_frame_k_idx[4]] * (1-m_uv_zpar)), |
| 434 | | (m_coeff->ktable[5][m_new_frame_k_idx[5]] * (1-m_uv_zpar)), |
| 435 | | (m_coeff->ktable[6][m_new_frame_k_idx[6]] * (1-m_uv_zpar)), |
| 436 | | (m_coeff->ktable[7][m_new_frame_k_idx[7]] * (1-m_uv_zpar)), |
| 437 | | (m_coeff->ktable[8][m_new_frame_k_idx[8]] * (1-m_uv_zpar)), |
| 438 | | (m_coeff->ktable[9][m_new_frame_k_idx[9]] * (1-m_uv_zpar)) ); |
| 413 | /* Debug info for current parsed frame */ |
| 414 | fprintf(stderr, "OLDE: %d; OLDP: %d; ", m_OLDE, m_OLDP); |
| 415 | fprintf(stderr,"Processing new frame: "); |
| 416 | if (m_inhibit == 0) |
| 417 | fprintf(stderr, "Normal Frame\n"); |
| 418 | else |
| 419 | fprintf(stderr,"Interpolation Inhibited\n"); |
| 420 | fprintf(stderr,"*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_current_energy, m_current_pitch, m_current_k[0], m_current_k[1], m_current_k[2], m_current_k[3], m_current_k[4], m_current_k[5], m_current_k[6], m_current_k[7], m_current_k[8], m_current_k[9]); |
| 421 | fprintf(stderr,"*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n", |
| 422 | (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)), |
| 423 | m_new_frame_energy_idx, |
| 424 | (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)), |
| 425 | (m_coeff->ktable[0][m_new_frame_k_idx[0]] * (1-m_zpar)), |
| 426 | (m_coeff->ktable[1][m_new_frame_k_idx[1]] * (1-m_zpar)), |
| 427 | (m_coeff->ktable[2][m_new_frame_k_idx[2]] * (1-m_zpar)), |
| 428 | (m_coeff->ktable[3][m_new_frame_k_idx[3]] * (1-m_zpar)), |
| 429 | (m_coeff->ktable[4][m_new_frame_k_idx[4]] * (1-m_uv_zpar)), |
| 430 | (m_coeff->ktable[5][m_new_frame_k_idx[5]] * (1-m_uv_zpar)), |
| 431 | (m_coeff->ktable[6][m_new_frame_k_idx[6]] * (1-m_uv_zpar)), |
| 432 | (m_coeff->ktable[7][m_new_frame_k_idx[7]] * (1-m_uv_zpar)), |
| 433 | (m_coeff->ktable[8][m_new_frame_k_idx[8]] * (1-m_uv_zpar)), |
| 434 | (m_coeff->ktable[9][m_new_frame_k_idx[9]] * (1-m_uv_zpar)) ); |
| 439 | 435 | #endif |
| 440 | 436 | |
| 441 | | } |
| 442 | | else // Not a new frame, just interpolate the existing frame. |
| 443 | | { |
| 444 | | int inhibit_state = ((m_inhibit==1)&&(m_IP != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the m_inhibit value |
| 445 | | #ifdef PERFECT_INTERPOLATION_HACK |
| 446 | | int samples_per_frame = m_subc_reload?175:266; // either (13 A cycles + 12 B cycles) * 7 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 7 interps for SPKSLOW |
| 447 | | //int samples_per_frame = m_subc_reload?200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW |
| 448 | | int current_sample = (m_subcycle - m_subc_reload)+(m_PC*(3-m_subc_reload))+((m_subc_reload?25:38)*((m_IP-1)&7)); |
| 449 | | //fprintf(stderr, "CS: %03d", current_sample); |
| 450 | | // reset the current energy, pitch, etc to what it was at frame start |
| 451 | | m_current_energy = (m_coeff->energytable[m_old_frame_energy_idx] * (1-m_old_zpar)); |
| 452 | | m_current_pitch = (m_coeff->pitchtable[m_old_frame_pitch_idx] * (1-m_old_zpar)); |
| 453 | | for (i = 0; i < m_coeff->num_k; i++) |
| 454 | | m_current_k[i] = (m_coeff->ktable[i][m_old_frame_k_idx[i]] * (1-((i<4)?m_old_zpar:m_old_uv_zpar))); |
| 455 | | // now adjust each value to be exactly correct for each of the samples per frame |
| 456 | | if (m_IP != 0) // if we're still interpolating... |
| 457 | | { |
| 458 | | m_current_energy = (m_current_energy + (((m_coeff->energytable[m_new_frame_energy_idx] - m_current_energy)*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-m_zpar); |
| 459 | | m_current_pitch = (m_current_pitch + (((m_coeff->pitchtable[m_new_frame_pitch_idx] - m_current_pitch)*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-m_zpar); |
| 460 | | for (i = 0; i < m_coeff->num_k; i++) |
| 461 | | m_current_k[i] = (m_current_k[i] + (((m_coeff->ktable[i][m_new_frame_k_idx[i]] - m_current_k[i])*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-((i<4)?m_zpar:m_uv_zpar)); |
| 462 | 437 | } |
| 463 | | else // we're done, play this frame for 1/8 frame. |
| 438 | else // Not a new frame, just interpolate the existing frame. |
| 464 | 439 | { |
| 465 | | m_current_energy = (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)); |
| 466 | | m_current_pitch = (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)); |
| 440 | int inhibit_state = ((m_inhibit==1)&&(m_IP != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the m_inhibit value |
| 441 | #ifdef PERFECT_INTERPOLATION_HACK |
| 442 | int samples_per_frame = m_subc_reload?175:266; // either (13 A cycles + 12 B cycles) * 7 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 7 interps for SPKSLOW |
| 443 | //int samples_per_frame = m_subc_reload?200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW |
| 444 | int current_sample = (m_subcycle - m_subc_reload)+(m_PC*(3-m_subc_reload))+((m_subc_reload?25:38)*((m_IP-1)&7)); |
| 445 | //fprintf(stderr, "CS: %03d", current_sample); |
| 446 | // reset the current energy, pitch, etc to what it was at frame start |
| 447 | m_current_energy = (m_coeff->energytable[m_old_frame_energy_idx] * (1-m_old_zpar)); |
| 448 | m_current_pitch = (m_coeff->pitchtable[m_old_frame_pitch_idx] * (1-m_old_zpar)); |
| 467 | 449 | for (i = 0; i < m_coeff->num_k; i++) |
| 468 | | m_current_k[i] = (m_coeff->ktable[i][m_new_frame_k_idx[i]] * (1-((i<4)?m_zpar:m_uv_zpar))); |
| 469 | | } |
| 450 | m_current_k[i] = (m_coeff->ktable[i][m_old_frame_k_idx[i]] * (1-((i<4)?m_old_zpar:m_old_uv_zpar))); |
| 451 | // now adjust each value to be exactly correct for each of the samples per frame |
| 452 | if (m_IP != 0) // if we're still interpolating... |
| 453 | { |
| 454 | m_current_energy = (m_current_energy + (((m_coeff->energytable[m_new_frame_energy_idx] - m_current_energy)*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-m_zpar); |
| 455 | m_current_pitch = (m_current_pitch + (((m_coeff->pitchtable[m_new_frame_pitch_idx] - m_current_pitch)*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-m_zpar); |
| 456 | for (i = 0; i < m_coeff->num_k; i++) |
| 457 | m_current_k[i] = (m_current_k[i] + (((m_coeff->ktable[i][m_new_frame_k_idx[i]] - m_current_k[i])*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-((i<4)?m_zpar:m_uv_zpar)); |
| 458 | } |
| 459 | else // we're done, play this frame for 1/8 frame. |
| 460 | { |
| 461 | m_current_energy = (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)); |
| 462 | m_current_pitch = (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)); |
| 463 | for (i = 0; i < m_coeff->num_k; i++) |
| 464 | m_current_k[i] = (m_coeff->ktable[i][m_new_frame_k_idx[i]] * (1-((i<4)?m_zpar:m_uv_zpar))); |
| 465 | } |
| 470 | 466 | #else |
| 471 | | //Updates to parameters only happen on subcycle '2' (B cycle) of PCs. |
| 472 | | if (m_subcycle == 2) |
| 473 | | { |
| 474 | | switch(m_PC) |
| 467 | //Updates to parameters only happen on subcycle '2' (B cycle) of PCs. |
| 468 | if (m_subcycle == 2) |
| 475 | 469 | { |
| 476 | | case 0: /* PC = 0, B cycle, write updated energy */ |
| 477 | | m_current_energy = (m_current_energy + (((m_coeff->energytable[m_new_frame_energy_idx] - m_current_energy)*(1-inhibit_state)) INTERP_SHIFT))*(1-m_zpar); |
| 478 | | break; |
| 479 | | case 1: /* PC = 1, B cycle, write updated pitch */ |
| 480 | | m_current_pitch = (m_current_pitch + (((m_coeff->pitchtable[m_new_frame_pitch_idx] - m_current_pitch)*(1-inhibit_state)) INTERP_SHIFT))*(1-m_zpar); |
| 481 | | break; |
| 482 | | case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: |
| 483 | | /* PC = 2 through 11, B cycle, write updated K1 through K10 */ |
| 484 | | m_current_k[m_PC-2] = (m_current_k[m_PC-2] + (((m_coeff->ktable[m_PC-2][m_new_frame_k_idx[m_PC-2]] - m_current_k[m_PC-2])*(1-inhibit_state)) INTERP_SHIFT))*(((m_PC-2)>4)?(1-m_uv_zpar):(1-m_zpar)); |
| 485 | | break; |
| 486 | | case 12: /* PC = 12 */ |
| 487 | | /* we should NEVER reach this point, PC=12 doesn't have a subcycle 2 */ |
| 488 | | break; |
| 470 | switch(m_PC) |
| 471 | { |
| 472 | case 0: /* PC = 0, B cycle, write updated energy */ |
| 473 | m_current_energy = (m_current_energy + (((m_coeff->energytable[m_new_frame_energy_idx] - m_current_energy)*(1-inhibit_state)) INTERP_SHIFT))*(1-m_zpar); |
| 474 | break; |
| 475 | case 1: /* PC = 1, B cycle, write updated pitch */ |
| 476 | m_current_pitch = (m_current_pitch + (((m_coeff->pitchtable[m_new_frame_pitch_idx] - m_current_pitch)*(1-inhibit_state)) INTERP_SHIFT))*(1-m_zpar); |
| 477 | break; |
| 478 | case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: |
| 479 | /* PC = 2 through 11, B cycle, write updated K1 through K10 */ |
| 480 | m_current_k[m_PC-2] = (m_current_k[m_PC-2] + (((m_coeff->ktable[m_PC-2][m_new_frame_k_idx[m_PC-2]] - m_current_k[m_PC-2])*(1-inhibit_state)) INTERP_SHIFT))*(((m_PC-2)>4)?(1-m_uv_zpar):(1-m_zpar)); |
| 481 | break; |
| 482 | case 12: /* PC = 12 */ |
| 483 | /* we should NEVER reach this point, PC=12 doesn't have a subcycle 2 */ |
| 484 | break; |
| 485 | } |
| 489 | 486 | } |
| 490 | | } |
| 491 | 487 | #endif |
| 492 | | } |
| 488 | } |
| 493 | 489 | |
| 494 | | // calculate the output |
| 495 | | if (OLD_FRAME_UNVOICED_FLAG == 1) |
| 496 | | { |
| 497 | | // generate unvoiced samples here |
| 498 | | if (m_RNG & 1) |
| 499 | | m_excitation_data = ~0x3F; /* according to the patent it is (either + or -) half of the maximum value in the chirp table, so either 01000000(0x40) or 11000000(0xC0)*/ |
| 500 | | else |
| 501 | | m_excitation_data = 0x40; |
| 502 | | } |
| 503 | | else /* (OLD_FRAME_UNVOICED_FLAG == 0) */ |
| 504 | | { |
| 505 | | // generate voiced samples here |
| 506 | | /* US patent 4331836 Figure 14B shows, and logic would hold, that a pitch based chirp |
| 507 | | * function has a chirp/peak and then a long chain of zeroes. |
| 508 | | * The last entry of the chirp rom is at address 0b110011 (51d), the 52nd sample, |
| 509 | | * and if the address reaches that point the ADDRESS incrementer is |
| 510 | | * disabled, forcing all samples beyond 51d to be == 51d |
| 511 | | */ |
| 512 | | if (m_pitch_count >= 51) |
| 513 | | m_excitation_data = (INT8)m_coeff->chirptable[51]; |
| 514 | | else /*m_pitch_count < 51*/ |
| 515 | | m_excitation_data = (INT8)m_coeff->chirptable[m_pitch_count]; |
| 516 | | } |
| 490 | // calculate the output |
| 491 | if (OLD_FRAME_UNVOICED_FLAG == 1) |
| 492 | { |
| 493 | // generate unvoiced samples here |
| 494 | if (m_RNG & 1) |
| 495 | m_excitation_data = ~0x3F; /* according to the patent it is (either + or -) half of the maximum value in the chirp table, so either 01000000(0x40) or 11000000(0xC0)*/ |
| 496 | else |
| 497 | m_excitation_data = 0x40; |
| 498 | } |
| 499 | else /* (OLD_FRAME_UNVOICED_FLAG == 0) */ |
| 500 | { |
| 501 | // generate voiced samples here |
| 502 | /* US patent 4331836 Figure 14B shows, and logic would hold, that a pitch based chirp |
| 503 | * function has a chirp/peak and then a long chain of zeroes. |
| 504 | * The last entry of the chirp rom is at address 0b110011 (51d), the 52nd sample, |
| 505 | * and if the address reaches that point the ADDRESS incrementer is |
| 506 | * disabled, forcing all samples beyond 51d to be == 51d |
| 507 | */ |
| 508 | if (m_pitch_count >= 51) |
| 509 | m_excitation_data = (INT8)m_coeff->chirptable[51]; |
| 510 | else /*m_pitch_count < 51*/ |
| 511 | m_excitation_data = (INT8)m_coeff->chirptable[m_pitch_count]; |
| 512 | } |
| 517 | 513 | |
| 518 | | // Update LFSR *20* times every sample (once per T cycle), like patent shows |
| 519 | | for (i=0; i<20; i++) |
| 520 | | { |
| 521 | | bitout = ((m_RNG >> 12) & 1) ^ |
| 522 | | ((m_RNG >> 3) & 1) ^ |
| 523 | | ((m_RNG >> 2) & 1) ^ |
| 524 | | ((m_RNG >> 0) & 1); |
| 525 | | m_RNG <<= 1; |
| 526 | | m_RNG |= bitout; |
| 527 | | } |
| 528 | | this_sample = lattice_filter(); /* execute lattice filter */ |
| 514 | // Update LFSR *20* times every sample (once per T cycle), like patent shows |
| 515 | for (i=0; i<20; i++) |
| 516 | { |
| 517 | bitout = ((m_RNG >> 12) & 1) ^ |
| 518 | ((m_RNG >> 3) & 1) ^ |
| 519 | ((m_RNG >> 2) & 1) ^ |
| 520 | ((m_RNG >> 0) & 1); |
| 521 | m_RNG <<= 1; |
| 522 | m_RNG |= bitout; |
| 523 | } |
| 524 | this_sample = lattice_filter(); /* execute lattice filter */ |
| 529 | 525 | #ifdef DEBUG_GENERATION_VERBOSE |
| 530 | | //fprintf(stderr,"C:%01d; ",m_subcycle); |
| 531 | | fprintf(stderr,"IP:%01d PC:%02d X:%04d E:%03d P:%03d Pc:%03d ",m_IP, m_PC, m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); |
| 532 | | //fprintf(stderr,"X:%04d E:%03d P:%03d Pc:%03d ", m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); |
| 533 | | for (i=0; i<10; i++) |
| 534 | | fprintf(stderr,"K%d:%04d ", i+1, m_current_k[i]); |
| 535 | | fprintf(stderr,"Out:%06d ", this_sample); |
| 526 | //fprintf(stderr,"C:%01d; ",m_subcycle); |
| 527 | fprintf(stderr,"IP:%01d PC:%02d X:%04d E:%03d P:%03d Pc:%03d ",m_IP, m_PC, m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); |
| 528 | //fprintf(stderr,"X:%04d E:%03d P:%03d Pc:%03d ", m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); |
| 529 | for (i=0; i<10; i++) |
| 530 | fprintf(stderr,"K%d:%04d ", i+1, m_current_k[i]); |
| 531 | fprintf(stderr,"Out:%06d ", this_sample); |
| 536 | 532 | //#ifdef PERFECT_INTERPOLATION_HACK |
| 537 | | // fprintf(stderr,"%d%d%d%d",m_old_zpar,m_zpar,m_old_uv_zpar,m_uv_zpar); |
| 533 | // fprintf(stderr,"%d%d%d%d",m_old_zpar,m_zpar,m_old_uv_zpar,m_uv_zpar); |
| 538 | 534 | //#else |
| 539 | | // fprintf(stderr,"x%dx%d",m_zpar,m_uv_zpar); |
| 535 | // fprintf(stderr,"x%dx%d",m_zpar,m_uv_zpar); |
| 540 | 536 | //#endif |
| 541 | | fprintf(stderr,"\n"); |
| 537 | fprintf(stderr,"\n"); |
| 542 | 538 | #endif |
| 543 | | /* next, force result to 14 bits (since its possible that the addition at the final (k1) stage of the lattice overflowed) */ |
| 544 | | while (this_sample > 16383) this_sample -= 32768; |
| 545 | | while (this_sample < -16384) this_sample += 32768; |
| 546 | | if (m_digital_select == 0) // analog SPK pin output is only 8 bits, with clipping |
| 547 | | buffer[buf_count] = clip_analog(this_sample); |
| 548 | | else // digital I/O pin output is 12 bits |
| 549 | | { |
| 539 | /* next, force result to 14 bits (since its possible that the addition at the final (k1) stage of the lattice overflowed) */ |
| 540 | while (this_sample > 16383) this_sample -= 32768; |
| 541 | while (this_sample < -16384) this_sample += 32768; |
| 542 | if (m_digital_select == 0) // analog SPK pin output is only 8 bits, with clipping |
| 543 | buffer[buf_count] = clip_analog(this_sample); |
| 544 | else // digital I/O pin output is 12 bits |
| 545 | { |
| 550 | 546 | #ifdef ALLOW_4_LSB |
| 551 | | // input: ssss ssss ssss ssss ssnn nnnn nnnn nnnn |
| 552 | | // N taps: ^ = 0x2000; |
| 553 | | // output: ssss ssss ssss ssss snnn nnnn nnnn nnnN |
| 554 | | buffer[buf_count] = (this_sample<<1)|((this_sample&0x2000)>>13); |
| 547 | // input: ssss ssss ssss ssss ssnn nnnn nnnn nnnn |
| 548 | // N taps: ^ = 0x2000; |
| 549 | // output: ssss ssss ssss ssss snnn nnnn nnnn nnnN |
| 550 | buffer[buf_count] = (this_sample<<1)|((this_sample&0x2000)>>13); |
| 555 | 551 | #else |
| 556 | | this_sample &= ~0xF; |
| 557 | | // input: ssss ssss ssss ssss ssnn nnnn nnnn 0000 |
| 558 | | // N taps: ^^ ^^^ = 0x3E00; |
| 559 | | // output: ssss ssss ssss ssss snnn nnnn nnnN NNNN |
| 560 | | buffer[buf_count] = (this_sample<<1)|((this_sample&0x3E00)>>9); |
| 552 | this_sample &= ~0xF; |
| 553 | // input: ssss ssss ssss ssss ssnn nnnn nnnn 0000 |
| 554 | // N taps: ^^ ^^^ = 0x3E00; |
| 555 | // output: ssss ssss ssss ssss snnn nnnn nnnN NNNN |
| 556 | buffer[buf_count] = (this_sample<<1)|((this_sample&0x3E00)>>9); |
| 561 | 557 | #endif |
| 562 | | } |
| 563 | | // Update all counts |
| 558 | } |
| 559 | // Update all counts |
| 564 | 560 | |
| 565 | | m_subcycle++; |
| 566 | | if ((m_subcycle == 2) && (m_PC == 12)) // RESETF3 |
| 567 | | { |
| 568 | | /* Circuit 412 in the patent acts a reset, resetting the pitch counter to 0 |
| 569 | | * if INHIBIT was true during the most recent frame transition. |
| 570 | | * The exact time this occurs is betwen IP=7, PC=12 sub=0, T=t12 |
| 571 | | * and m_IP = 0, PC=0 sub=0, T=t12, a period of exactly 20 cycles, |
| 572 | | * which overlaps the time OLDE and OLDP are updated at IP=7 PC=12 T17 |
| 573 | | * (and hence INHIBIT itself 2 t-cycles later). We do it here because it is |
| 574 | | * convenient and should make no difference in output. |
| 575 | | */ |
| 576 | | if ((m_IP == 7)&&(m_inhibit==1)) m_pitch_zero = 1; |
| 577 | | if ((m_IP == 0)&&(m_pitch_zero==1)) m_pitch_zero = 0; |
| 578 | | if (m_IP == 7) // RESETL4 |
| 561 | m_subcycle++; |
| 562 | if ((m_subcycle == 2) && (m_PC == 12)) // RESETF3 |
| 579 | 563 | { |
| 580 | | // Latch OLDE and OLDP |
| 581 | | OLD_FRAME_SILENCE_FLAG = NEW_FRAME_SILENCE_FLAG; // m_OLDE |
| 582 | | OLD_FRAME_UNVOICED_FLAG = NEW_FRAME_UNVOICED_FLAG; // m_OLDP |
| 583 | | /* if TALK was clear last frame, halt speech now, since TALKD (latched from TALK on new frame) just went inactive. */ |
| 564 | /* Circuit 412 in the patent acts a reset, resetting the pitch counter to 0 |
| 565 | * if INHIBIT was true during the most recent frame transition. |
| 566 | * The exact time this occurs is betwen IP=7, PC=12 sub=0, T=t12 |
| 567 | * and m_IP = 0, PC=0 sub=0, T=t12, a period of exactly 20 cycles, |
| 568 | * which overlaps the time OLDE and OLDP are updated at IP=7 PC=12 T17 |
| 569 | * (and hence INHIBIT itself 2 t-cycles later). We do it here because it is |
| 570 | * convenient and should make no difference in output. |
| 571 | */ |
| 572 | if ((m_IP == 7)&&(m_inhibit==1)) m_pitch_zero = 1; |
| 573 | if ((m_IP == 0)&&(m_pitch_zero==1)) m_pitch_zero = 0; |
| 574 | if (m_IP == 7) // RESETL4 |
| 575 | { |
| 576 | // Latch OLDE and OLDP |
| 577 | OLD_FRAME_SILENCE_FLAG = NEW_FRAME_SILENCE_FLAG; // m_OLDE |
| 578 | OLD_FRAME_UNVOICED_FLAG = NEW_FRAME_UNVOICED_FLAG; // m_OLDP |
| 579 | /* if TALK was clear last frame, halt speech now, since TALKD (latched from TALK on new frame) just went inactive. */ |
| 584 | 580 | #ifdef DEBUG_GENERATION |
| 585 | | if (m_TALK == 0) |
| 586 | | fprintf(stderr,"tms5110_process: processing frame: TALKD = 0 caused by stop frame or buffer empty, halting speech.\n"); |
| 581 | if (m_TALK == 0) |
| 582 | fprintf(stderr,"tms5110_process: processing frame: TALKD = 0 caused by stop frame or buffer empty, halting speech.\n"); |
| 587 | 583 | #endif |
| 588 | | m_TALKD = m_TALK; // TALKD is latched from TALK |
| 589 | | m_TALK = m_SPEN; // TALK is latched from SPEN |
| 584 | m_TALKD = m_TALK; // TALKD is latched from TALK |
| 585 | m_TALK = m_SPEN; // TALK is latched from SPEN |
| 586 | } |
| 587 | m_subcycle = m_subc_reload; |
| 588 | m_PC = 0; |
| 589 | m_IP++; |
| 590 | m_IP&=0x7; |
| 590 | 591 | } |
| 591 | | m_subcycle = m_subc_reload; |
| 592 | | m_PC = 0; |
| 593 | | m_IP++; |
| 594 | | m_IP&=0x7; |
| 592 | else if (m_subcycle == 3) |
| 593 | { |
| 594 | m_subcycle = m_subc_reload; |
| 595 | m_PC++; |
| 596 | } |
| 597 | m_pitch_count++; |
| 598 | if ((m_pitch_count >= m_current_pitch)||(m_pitch_zero == 1)) m_pitch_count = 0; |
| 599 | m_pitch_count &= 0x1FF; |
| 595 | 600 | } |
| 596 | | else if (m_subcycle == 3) |
| 601 | else // m_TALKD == 0 |
| 597 | 602 | { |
| 598 | | m_subcycle = m_subc_reload; |
| 599 | | m_PC++; |
| 600 | | } |
| 601 | | m_pitch_count++; |
| 602 | | if ((m_pitch_count >= m_current_pitch)||(m_pitch_zero == 1)) m_pitch_count = 0; |
| 603 | | m_pitch_count &= 0x1FF; |
| 604 | | buf_count++; |
| 605 | | size--; |
| 606 | | } |
| 607 | | |
| 608 | | empty: |
| 609 | | |
| 610 | | #ifdef VERBOSE |
| 611 | | fprintf(stderr,"empty called with size of %d; IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", size, m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD); |
| 612 | | #endif |
| 613 | | while (size > 0) |
| 614 | | { |
| 615 | | m_subcycle++; |
| 616 | | if ((m_subcycle == 2) && (m_PC == 12)) // RESETF3 |
| 617 | | { |
| 618 | | if (m_IP == 7) // RESETL4 |
| 603 | m_subcycle++; |
| 604 | if ((m_subcycle == 2) && (m_PC == 12)) // RESETF3 |
| 619 | 605 | { |
| 620 | | m_TALKD = m_TALK; // TALKD is latched from TALK |
| 621 | | m_TALK = m_SPEN; // TALK is latched from SPEN |
| 606 | if (m_IP == 7) // RESETL4 |
| 607 | { |
| 608 | m_TALKD = m_TALK; // TALKD is latched from TALK |
| 609 | m_TALK = m_SPEN; // TALK is latched from SPEN |
| 610 | } |
| 611 | m_subcycle = m_subc_reload; |
| 612 | m_PC = 0; |
| 613 | m_IP++; |
| 614 | m_IP&=0x7; |
| 622 | 615 | } |
| 623 | | m_subcycle = m_subc_reload; |
| 624 | | m_PC = 0; |
| 625 | | m_IP++; |
| 626 | | m_IP&=0x7; |
| 627 | | if (m_TALKD) goto render; |
| 616 | else if (m_subcycle == 3) |
| 617 | { |
| 618 | m_subcycle = m_subc_reload; |
| 619 | m_PC++; |
| 620 | } |
| 621 | buffer[buf_count] = -1; /* should be just -1; actual chip outputs -1 every idle sample; (cf note in data sheet, p 10, table 4) */ |
| 628 | 622 | } |
| 629 | | else if (m_subcycle == 3) |
| 630 | | { |
| 631 | | m_subcycle = m_subc_reload; |
| 632 | | m_PC++; |
| 633 | | } |
| 634 | | buffer[buf_count] = -1; /* should be just -1; actual chip outputs -1 every idle sample; (cf note in data sheet, p 10, table 4) */ |
| 635 | | buf_count++; |
| 636 | | size--; |
| 623 | buf_count++; |
| 624 | size--; |
| 637 | 625 | } |
| 638 | 626 | } |
| 639 | 627 | |