home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / sound.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  11.0 KB  |  524 lines

  1.  
  2. /*
  3.     SOUND.C
  4.     =======
  5.  
  6.     Sound chip and cassette routines.
  7. */
  8.  
  9. #include <malloc.h>
  10. #include "v9t9_common.h"
  11. #include "timer.h"
  12. #include "sound.h"
  13. #include "demo.h"
  14. #include "command.h"
  15.  
  16. #define _L     LOG_SOUND | LOG_INFO
  17.  
  18. /* I've read from ti99sim that this is really logarithmic */
  19. static u8 attenuation_to_volume[16] =
  20. {
  21.     0xff, 0xee, 0xdd, 0xcc,
  22.     0xbb, 0xaa, 0x99, 0x88,
  23.     0x77, 0x66, 0x55, 0x44,
  24.     0x33, 0x22, 0x11, 0x00
  25. };
  26.  
  27. voiceinfo sound_voices[4];
  28.  
  29. /*    
  30.     The current voice (selected by writing OPERATION_FREQUENCY_LO byte).  
  31.     May be useful for arpeggiation. 
  32. */
  33. static u8   cvoice;
  34.  
  35. int         sndplayhz = 44100;    /* playback rate */
  36. int         sndplaybits = 8;    /* word size for sound */
  37.  
  38. /*************************************/
  39.  
  40. static u16  noise_period[4] = 
  41. {
  42.     16, 
  43.     32, 
  44.     64, 
  45.     0                         /* determined by VOICE_TONE_2 */
  46. };
  47.  
  48.  
  49. /*
  50.     Update cached fields
  51. */
  52. static void 
  53. voice_cache_values(voiceinfo *v)
  54. {
  55.     if (v != &sound_voices[VOICE_NOISE]) {
  56.         v->volume = OPERATION_TO_VOLUME(v);
  57.         v->period = OPERATION_TO_PERIOD(v);
  58.         v->hertz = PERIOD_TO_HERTZ(v->period);
  59.     } else {
  60.         int period = OPERATION_TO_NOISE_PERIOD(v);
  61.         int type = OPERATION_TO_NOISE_TYPE(v);
  62.  
  63.         if (period != NOISE_PERIOD_VARIABLE) {
  64.             v->period = noise_period[period];
  65.             v->hertz = PERIOD_TO_HERTZ(v->period);
  66.         } else {
  67.             v->period = sound_voices[VOICE_TONE_2].period;
  68.             v->hertz = sound_voices[VOICE_TONE_2].hertz;
  69.         }
  70.     }
  71.  
  72.     logger(_L|L_3, "voice_cache_values: lo=>%02x, hi=>%02x, period=>%04x, hertz=%d, volume=%d\n",
  73.            v->operation[OPERATION_FREQUENCY_LO], 
  74.            v->operation[OPERATION_FREQUENCY_HI],
  75.            v->period,
  76.            v->hertz,
  77.            v->volume);
  78. }
  79.  
  80. /*
  81.  *    Update the noise channel when a noise operation occurs
  82.  *    or VOICE_TONE_2 changes and the noise control is NOISE_PERIOD_VARIABLE.
  83.  */
  84. static void
  85. sound_update_noise(void)
  86. {
  87.     voiceinfo *v = &sound_voices[VOICE_NOISE];
  88.     int period = OPERATION_TO_NOISE_PERIOD(v);
  89.  
  90.     if ((cvoice == VOICE_TONE_2 && period == NOISE_PERIOD_VARIABLE)
  91.          || cvoice == VOICE_NOISE)
  92.     {
  93.         SOUNDUPDATE(vms_Tn);
  94.     }
  95. }
  96.  
  97. void
  98. sound_mmio_write(u8 val)
  99. {
  100.     voiceinfo *v;
  101.     int vn;
  102.  
  103.     if (stateflag & ST_DEMOING) {
  104.         demo_record_event(demo_type_sound, val);
  105.     }
  106.  
  107.     /*  handle command byte */
  108.     if (val & 0x80) {
  109.         vn = OPERATION_TO_VOICE(val);
  110.         cvoice = vn;
  111.         v = &sound_voices[vn];
  112.         switch ((val & 0x70) >> 4) 
  113.         {
  114.         case 0:                /* T1 FRQ */
  115.         case 2:                /* T2 FRQ */
  116.         case 4:                /* T3 FRQ */
  117.             v->operation[OPERATION_FREQUENCY_LO] = val;
  118.             voice_cache_values(v);
  119.             sound_update_noise();
  120.             SOUNDUPDATE(vms_Tv0 << vn);
  121.             break;
  122.         case 1:                /* T1 ATT */
  123.         case 3:                /* T2 ATT */
  124.         case 5:                /* T3 ATT */
  125.             v->operation[OPERATION_ATTENUATION] = val;
  126.             voice_cache_values(v);
  127.             SOUNDUPDATE(vms_Vv0 << vn);
  128.             break;
  129.         case 6:                /* noise ctl */
  130.             v->operation[OPERATION_CONTROL] = val;
  131.             sound_update_noise();
  132.             break;
  133.         case 7:                /* noise vol */
  134.             v->operation[OPERATION_ATTENUATION] = val;
  135.             voice_cache_values(v);
  136.             SOUNDUPDATE(vms_Vn);
  137.             break;
  138.         }
  139.     }
  140.     /*  second frequency byte */
  141.     else if (!(val & 0xc0)) {
  142.         v = &sound_voices[cvoice];
  143.         v->operation[OPERATION_FREQUENCY_HI] = val;
  144.         voice_cache_values(v);
  145.         sound_update_noise();
  146.         SOUNDUPDATE(vms_Tv0 << cvoice);
  147.     }
  148. }
  149.  
  150. /********************************************/
  151.  
  152. /*    Cassette routines  */
  153.  
  154. static vmModule *cs[2];
  155. static u8   cs_open[2];
  156. static u16  cs_clock;
  157. static u8   cs_motor[2];
  158. static u32  cs_lasttime;        // last clock when data was read (3.0/64 mhz)
  159. static u8   cs_latch,            // last data read
  160.             cs_min, cs_max;        // midrange of incoming data
  161.  
  162. static void
  163. cassette_open(int csx)
  164. {
  165.     vmModule   *ptr;
  166.  
  167.     if (csx < 0 || csx >= 2)
  168.         return;
  169.  
  170.     if (cs_open[csx])
  171.         return;
  172.  
  173.     /*  Select where to filter cassette info;
  174.        for now, just use sound module */
  175.  
  176.     for (ptr = vmSound; ptr; ptr = ptr->next) {
  177.         // cs2 [csx=1] can only write, methinks (try "OLD CS2")
  178.         if (ptr->m.sound->play && (csx != 1 || ptr->m.sound->read)
  179.             && !(ptr->runtimeflags & vmRTUnselected)) {
  180.             break;
  181.         }
  182.     }
  183.     if (ptr)
  184.         logger(_L | 0, "Cassette %d is %p (%s)\n\n", csx, ptr, ptr->name);
  185.     cs[csx] = ptr;
  186.     cs_open[csx] = (ptr != NULL);
  187. }
  188.  
  189. void
  190. cassette_set_timer(u16 hz)
  191. {
  192.     cs_clock = hz;
  193. }
  194.  
  195. void
  196. cassette_set_motor(int csx, u8 onoff)
  197. {
  198.     if (csx < 0 || csx >= 2)
  199.         return;
  200.  
  201.     cs_motor[csx] = onoff;
  202.     cs_lasttime = 0;
  203.  
  204.     cs_min = 0xff;
  205.     cs_max = 0;
  206.     cs_latch = 0x80;
  207.     if (onoff)
  208.         cassette_open(csx);
  209. }
  210.  
  211. void
  212. cassette_write(u8 onoff, u32 timepassed)
  213. {
  214.     // we should not write to the sound module because
  215.     // the mix server is usually owning it.
  216.  
  217. /*
  218.     u8 *data = (u8 *)alloca(4096);
  219.     memset(data, onoff ? 0x7f : 0x00, 4096);
  220.     while (timepassed) {
  221.         u32 quant = (timepassed >= 4096 ? 4096 : timepassed);
  222.         #warning can we write to both at once?
  223.         if (cs_motor[0])
  224.             cs[0]->m.sound->play(vms_CS, data, quant, 
  225.                 cs_clock ? cs_clock : baseclockhz / 64);
  226.         if (cs_motor[1])
  227.             cs[1]->m.sound->play(vms_CS, data, quant, 
  228.                 cs_clock ? cs_clock : baseclockhz / 64);
  229.         timepassed -= quant;
  230.     }
  231. */
  232. }
  233.  
  234. u8
  235. cassette_read(void)
  236. {
  237.     u32         timepassed;
  238.     u8         *data;
  239.     u32         average;
  240.  
  241.     if (currenttime >= cs_lasttime)
  242.         timepassed = currenttime - cs_lasttime;
  243.     else
  244.         timepassed = 64;
  245.  
  246.     if (cs_clock)
  247.         timepassed = (timepassed + cs_clock - 1) *
  248.             (cs_clock) / (baseclockhz / 64);
  249.     else
  250.         timepassed = timepassed / 64;
  251.  
  252.     data = (u8 *) alloca(timepassed + 1);
  253.     average = 0;
  254.  
  255.     if (timepassed && cs_open[0]) {
  256.         cs_lasttime = currenttime;
  257.  
  258.         //  read at most as much data as represented by cs_clock
  259.         if (cs[0]->m.sound->read)
  260.             cs[0]->m.sound->read(vms_AGr, data, timepassed,
  261.                                  cs_clock ? cs_clock : baseclockhz / 64);
  262.  
  263.         while (timepassed--)
  264.             average = (average + data[timepassed]) / 2;
  265.  
  266.         cs_latch = average;
  267.  
  268.         if (cs_latch < cs_min)
  269.             cs_min = cs_latch;
  270.         else if (cs_min < 0x60 / 2)
  271.             cs_min++;
  272.         if (cs_latch > cs_max)
  273.             cs_max = cs_latch;
  274.         else if (cs_max > 0xa0 / 2)
  275.             cs_max--;
  276.  
  277.     }                            // else, use last cs_latch
  278.  
  279.  
  280.  
  281.     logger(_L | L_2, "cs = %d/%d/%d = \n", cs_min, cs_latch, cs_max);
  282.     if (cs_latch > cs_min + (cs_max - cs_min) / 2) {
  283.         logger(_L | L_2, "1\n");
  284.         return 1;
  285.     } else {
  286.         logger(_L | L_2, "0\n\n");
  287.         return 0;
  288.     }
  289. }
  290.  
  291.  
  292. /********************************************/
  293.  
  294. static
  295. DECL_SYMBOL_ACTION(sound_playsound_toggle)
  296. {
  297.     if (features & FE_PLAYSOUND) {
  298.         DOSOUNDUPDATE(vms_Tv0 | vms_Tv1 | vms_Tv2 | vms_Tn | 
  299.                       vms_Vv0 | vms_Vv1 | vms_Vv2 | vms_Vn);
  300.     } else {
  301.         DOSOUNDFLUSH();
  302.     }
  303.     return 1;
  304. }
  305.  
  306. static
  307. DECL_SYMBOL_ACTION(sound_enablesound_toggle)
  308. {
  309.     if (features & FE_SOUND) {
  310.         sound_enable();
  311.         sound_restart();
  312.     } else {
  313.         sound_restop();
  314.         sound_disable();
  315.     }
  316.     return 1;
  317. }
  318.  
  319. static
  320. DECL_SYMBOL_ACTION(sound_module_restart)
  321. {
  322.     if (sndplaybits <= 8)
  323.         sndplaybits = 8;
  324.     else
  325.         sndplaybits = 16;
  326.     sound_restop();
  327.     sound_restart();
  328.     return 1;
  329. }
  330.  
  331. static
  332. DECL_SYMBOL_ACTION(sound_config_state)
  333. {
  334.     struct voiceinfo *v;
  335.     int val;
  336.  
  337.     if (task == csa_READ) {
  338.         if (iter >= 4)
  339.             return 0;
  340.         v = &sound_voices[iter];
  341.         command_arg_set_num(SYM_ARG_1st, iter);
  342.         command_arg_set_num(SYM_ARG_2nd, v->operation[OPERATION_FREQUENCY_LO]);
  343.         command_arg_set_num(SYM_ARG_3rd, v->operation[OPERATION_FREQUENCY_HI]);
  344.         command_arg_set_num(SYM_ARG_4th, v->operation[OPERATION_ATTENUATION]);
  345.         return 1;
  346.     }
  347.  
  348.     command_arg_get_num(SYM_ARG_1st, &val);
  349.     if (val < 0 || val >= 4) {
  350.         logger(_L | LOG_USER | LOG_ERROR, "Invalid sound channel specified (%d)\n", val);
  351.         return 0;
  352.     }
  353.  
  354.     iter = val;
  355.     v = &sound_voices[iter];
  356.  
  357.     command_arg_get_num(SYM_ARG_2nd, &val);    
  358.     v->operation[OPERATION_FREQUENCY_LO] = val;
  359.  
  360.     command_arg_get_num(SYM_ARG_3rd, &val);
  361.     v->operation[OPERATION_FREQUENCY_HI] = val;
  362.  
  363.     command_arg_get_num(SYM_ARG_4th, &val);
  364.     v->operation[OPERATION_ATTENUATION] = val;
  365.  
  366.     voice_cache_values(v);
  367.     sound_update_noise();
  368.     SOUNDUPDATE((vms_Tv0|vms_Vv0) << iter);
  369.  
  370.     return 1;
  371. }
  372.  
  373.  
  374. void
  375. sound_init(void)
  376. {
  377.     command_symbol_table *soundcommands =
  378.         command_symbol_table_new("Sound Options",
  379.                                  "These are generic commands for controlling sound emulation",
  380.  
  381.     command_symbol_new("PlaySound",
  382.                             "Control whether music/noise sound is played.\n"
  383.                        "(Note: to turn off all sound, "
  384.                "disable the sound module or use \"EnableSound off\".)",
  385.                             c_STATIC,
  386.                             sound_playsound_toggle,
  387.                             RET_FIRST_ARG,
  388.                             command_arg_new_toggle
  389.                             ("on|off",
  390.                              "toggle sound on or off",
  391.                              NULL /* action */ ,
  392.                              ARG_NUM(features),
  393.                              FE_PLAYSOUND,
  394.                              NULL /* next */ )
  395.                             ,
  396.  
  397.     command_symbol_new("EnableSound",
  398.                        "Control whether any sound is emitted.",
  399.                             c_STATIC,
  400.                             sound_enablesound_toggle,
  401.                             RET_FIRST_ARG,
  402.                             command_arg_new_toggle
  403.                             ("on|off",
  404.                              "toggle sound on or off",
  405.                              NULL /* action */ ,
  406.                              ARG_NUM(features),
  407.                              FE_SOUND,
  408.                              NULL /* next */ )
  409.                             ,
  410.  
  411.     command_symbol_new("DigitalSoundHertz",
  412.                        "Set playback rate for digitized sound; "
  413.                        "interpretation is dependent on sound module in effect",
  414.                        c_STATIC,
  415.                        sound_module_restart,
  416.                        RET_FIRST_ARG,
  417.                        command_arg_new_num("Hz",
  418.                                            "set rate for playback",
  419.                                            NULL  /* action */,
  420.                                            ARG_NUM(sndplayhz),
  421.                                            NULL
  422.                                            /* next */),
  423.     command_symbol_new("DigitalSoundBits",
  424.                        "Set word size for digitized sound; "
  425.                        "interpretation is dependent on sound module in effect",
  426.                        c_STATIC,
  427.                        sound_module_restart,
  428.                        RET_FIRST_ARG,
  429.                        command_arg_new_num("8|16",
  430.                                            "set word size for playback",
  431.                                            NULL /* action */ ,
  432.                                            ARG_NUM(sndplaybits),
  433.                                            NULL /* next */ )
  434.                        ,
  435.  
  436.     command_symbol_new("SoundChannelState",
  437.                        NULL /* help */,
  438.                        c_DYNAMIC|c_SESSION_ONLY,
  439.                        sound_config_state,
  440.                        NULL /* ret */,
  441.                        command_arg_new_num("channel",
  442.                                            "channel number, 0-3",
  443.                                            NULL /* action */,
  444.                                            NEW_ARG_NUM(u8),
  445.                        command_arg_new_num("period",
  446.                                            "period of channel",
  447.                                            NULL /* action */,
  448.                                            NEW_ARG_NUM(u16),
  449.                        command_arg_new_num("volume",
  450.                                            "volume 0-15, 15=off",
  451.                                            NULL /* action */,
  452.                                            NEW_ARG_NUM(u8),
  453.                        command_arg_new_num("type",
  454.                                            "type of noise, or 0 for tone",
  455.                                            NULL /* action */,
  456.                                            NEW_ARG_NUM(u8),
  457.                        NULL)))),
  458.  
  459.     NULL /* next */ ))))),
  460.  
  461.     NULL /* sub */ ,
  462.  
  463.     NULL    /* next */
  464.     );
  465.     int v;
  466.  
  467.     command_symbol_table_add_subtable(universe, soundcommands);
  468.  
  469.     features |= FE_PLAYSOUND | FE_PLAYSPEECH;
  470.     for (v=0; v<4; v++) {
  471.         sound_voices[v].operation[OPERATION_ATTENUATION] = 0xf;
  472.         voice_cache_values(&sound_voices[v]);
  473.     }
  474.     cvoice = 0;
  475. }
  476.  
  477. int
  478. sound_restart(void)
  479. {
  480.     if (features & FE_PLAYSOUND) {
  481.         DOSOUNDUPDATE(vms_Tv0 | vms_Tv1 | vms_Tv2 | vms_Tn | vms_Vv0 | vms_Vv1 |
  482.                       vms_Vv2 | vms_Vn);
  483.     }
  484.     if (features & FE_PLAYSPEECH) {
  485.         DOSOUNDPLAY(vms_Speech, NULL, 0, 0);
  486.     }
  487.     return 1;
  488. }
  489.  
  490. void
  491. sound_restop(void)
  492. {
  493.     SOUNDFLUSH();
  494. }
  495.  
  496. int
  497. sound_enable(void)
  498. {
  499.     vmModule *ptr = vmSound;
  500.     while (ptr) {
  501.         if (ptr->runtimeflags & vmRTInUse)
  502.         {
  503.             if (vmEnableModule(ptr) != vmOk)
  504.                 return 0;
  505.         }
  506.         ptr = ptr->next;
  507.     }
  508.  
  509.     return 1;
  510. }
  511.  
  512. void
  513. sound_disable(void)
  514. {
  515.     vmModule *ptr = vmSound;
  516.     while (ptr) {
  517.         if (ptr->runtimeflags & vmRTInUse)
  518.         {
  519.             vmDisableModule(ptr);
  520.         }
  521.         ptr = ptr->next;
  522.     }
  523. }
  524.