home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / mac / speech / wlcm132s.hqx / Welcome.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-13  |  15.5 KB  |  599 lines

  1. /*    Welcome!
  2.  
  3.     Welcome is an recreation of the Welcome2 application using the new Speech Manager.
  4. I have no connection with the original author, except fond memories. :-)
  5.  
  6. Copyright 1993 by Garrett Fitzgerald
  7. A product of donnael Software
  8.  
  9. v1.3.2    -    Adds Halloween (ARGH!) and fixes bug in selection of day-of-week holidays - 12/12/93
  10.             Also fixed Munger bug--brought back from v2.0d (to appear later...)
  11. v1.3.1    -    Added FlushEvents call, but it didn't help. The Speech Manager doesn't
  12.             seem too happy with Male Voice and only 4M RAM....
  13. v1.3    -    Menu selection of future default voice works!     -    8/25/93
  14. v1.2    -    Show speaking voice        -    8/22/93
  15.             Error alerts
  16.             Gestalt now works, with inclusion of <GestaltEqu.h>
  17.             Lists voices
  18.             Added about box
  19.             Defaults to "Female Voice", if available
  20. v1.1.1    -    Increased app partition to permit more complicated voices    -    8/16/93
  21.             Changed to StopSpeechAt end of word
  22.             Added commas after weekday
  23.             Re-did Finder icon
  24. v1.1    -    Added WaitNextEvent to allow quitting    -    8/16/93
  25. v1.0    -    initial release    -    8/15/93
  26. */
  27.  
  28. #include "Welcome.h"
  29. short vol_refnum,
  30.       prefs_file_refnum;
  31.  
  32. /*    toolbox_init()
  33.     
  34.     Initializes the full toolbox--things here seem to depend on it.
  35. */
  36.  
  37. toolbox_init()
  38. {
  39.  
  40.     InitGraf(&thePort);    
  41.     InitFonts();
  42.     InitWindows();
  43.     InitMenus();
  44.     TEInit();
  45.     InitDialogs(nil);
  46.     InitCursor();
  47. }
  48.  
  49. /*    prefs_init()
  50.     
  51.     Finds the Welcome! preferences file, or creates a new one. Returns true if file
  52. exists, false if the prefs folder can't be found or the file can't be opened.
  53. */
  54.  
  55. Boolean
  56. prefs_init()
  57.  
  58. {
  59.     OSErr err;
  60.     StringHandle vol_name;
  61.     long prefs_dir;
  62.     FSSpec prefs_spec;
  63.     Handle voice_res;
  64.     VoiceSpec init_voice_res;
  65.     extern short prefs_file_refnum,
  66.                  vol_refnum;
  67.     
  68.     vol_name = NewString("\p");
  69.     err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
  70.                      &vol_refnum, &prefs_dir);
  71.     if (err != noErr)
  72.         return false;
  73.     
  74.     err = FSMakeFSSpec(vol_refnum, prefs_dir, PREFS_FILE_NAME, &prefs_spec);
  75.     
  76.     if (err == fnfErr) {
  77.         FSpCreateResFile(&prefs_spec, 'GSFC', 'pref', smSystemScript);
  78.         err = ResError();
  79.         if (err != noErr) {
  80.             FSpDelete(&prefs_spec);
  81.             return false;
  82.         }
  83.         prefs_file_refnum = FSpOpenResFile(&prefs_spec, fsRdWrPerm);
  84.         err = ResError();
  85.         if (err != noErr) {
  86.             FSpDelete(&prefs_spec);
  87.             return false;
  88.         }
  89.         
  90.         init_voice_res.creator = '????';
  91.         init_voice_res.id = '????';
  92.         PtrToHand((Ptr)&init_voice_res, &voice_res, sizeof(VoiceSpec));
  93.         AddResource(voice_res, VOICE_RES_TYPE, VOICE_RES_NUMB, "\pPreferred voice");
  94.         WriteResource(voice_res);
  95.         FlushVol(*vol_name, vol_refnum);
  96.     }
  97.     else {
  98.         prefs_file_refnum = FSpOpenResFile(&prefs_spec, fsRdWrPerm);
  99.         err = ResError();
  100.         if (err != noErr) {
  101.             return false;
  102.         }
  103.     }
  104. }
  105.  
  106. /*    date_to_text()
  107.  
  108.     Converts the numbers returned in Secs2Date to more readable months, days, time, and
  109. days of the week.
  110. */
  111.  
  112. void
  113. date_to_text(StringHandle *month, StringHandle *day, StringHandle *weekday, 
  114.              StringHandle *time, StringHandle *greeting)
  115. {
  116.     long secs,
  117.          mil_time;
  118.     Str255 hmin;
  119.     DateTimeRec now;
  120.          
  121.     GetDateTime(&secs);
  122.     IUTimeString(secs, false, hmin);    /* 4:22 AM */
  123.     *(hmin+*hmin+1) = '%';                /* Stick in a % for Munger to find later */
  124.     *hmin += 1;                            /* and fix the length byte... */
  125.     *time = NewString(hmin);
  126.     mil_time = Munger(*time, 5, "M", 1, ".M.", 3);    /* If this is 12 hour time, change */
  127.     if (mil_time >= 0)                                /* AM/PM to A.M./P.M. */
  128.         ***time += 2;                    /* Length byte again... */
  129.     
  130.     Secs2Date(secs, &now);                /* Turn the seconds since 1904 into a date/time record */
  131.     switch (now.dayOfWeek) {            /* Change the day of week, month, and date into words */
  132.         case 1:
  133.             *weekday = NewString("\pSunday, %");    /* and stick in a % for Munger to find later... */
  134.             break;
  135.         case 2:
  136.             *weekday = NewString("\pMonday, %");
  137.             break;
  138.         case 3:
  139.             *weekday = NewString("\pTuesday, %");
  140.             break;
  141.         case 4:
  142.             *weekday = NewString("\pWednesday, %");
  143.             break;
  144.         case 5:
  145.             *weekday = NewString("\pThursday, %");
  146.             break;
  147.         case 6:
  148.             *weekday = NewString("\pFriday, %");
  149.             break;
  150.         case 7:
  151.             *weekday = NewString("\pSaturday, %");
  152.             break;
  153.     }
  154.     switch (now.month) {
  155.         case 1:
  156.             *month = NewString("\pJanuary %");
  157.             break;
  158.         case 2:
  159.             *month = NewString("\pFebruary %");
  160.             break;
  161.         case 3:
  162.             *month = NewString("\pMarch %");
  163.             break;
  164.         case 4:
  165.             *month = NewString("\pApril %");
  166.             break;
  167.         case 5:
  168.             *month = NewString("\pMay %");
  169.             break;
  170.         case 6:
  171.             *month = NewString("\pJune %");
  172.             break;
  173.         case 7:
  174.             *month = NewString("\pJuly %");
  175.             break;
  176.         case 8:
  177.             *month = NewString("\pAugust %");
  178.             break;
  179.         case 9:
  180.             *month = NewString("\pSeptember %");
  181.             break;
  182.         case 10:
  183.             *month = NewString("\pOctober %");
  184.             break;
  185.         case 11:
  186.             *month = NewString("\pNovember %");
  187.             break;
  188.         case 12:
  189.             *month = NewString("\pDecember %");
  190.             break;
  191.     }
  192.     switch (now.day) {
  193.         case 1:
  194.             *day = NewString("\pfirst %");
  195.             break;
  196.         case 2:
  197.             *day = NewString("\psecond %");
  198.             break;
  199.         case 3:
  200.             *day = NewString("\pthird %");
  201.             break;
  202.         case 4:
  203.             *day = NewString("\pfourth %");
  204.             break;
  205.         case 5:
  206.             *day = NewString("\pfifth %");
  207.             break;
  208.         case 6:
  209.             *day = NewString("\psixth %");
  210.             break;
  211.         case 7:
  212.             *day = NewString("\pseventh %");
  213.             break;
  214.         case 8:
  215.             *day = NewString("\peighth %");
  216.             break;
  217.         case 9:
  218.             *day = NewString("\pnineth %");
  219.             break;
  220.         case 10:
  221.             *day = NewString("\ptenth %");
  222.             break;
  223.         case 11:
  224.             *day = NewString("\peleventh %");
  225.             break;
  226.         case 12:
  227.             *day = NewString("\ptwelveth %");
  228.             break;
  229.         case 13:
  230.             *day = NewString("\pthirteenth %");
  231.             break;
  232.         case 14:
  233.             *day = NewString("\pfourteenth %");
  234.             break;
  235.         case 15:
  236.             *day = NewString("\pfifteenth %");
  237.             break;
  238.         case 16:
  239.             *day = NewString("\psixteenth %");
  240.             break;
  241.         case 17:
  242.             *day = NewString("\pseventeenth %");
  243.             break;
  244.         case 18:
  245.             *day = NewString("\peighteenth %");
  246.             break;
  247.         case 19:
  248.             *day = NewString("\pnineteenth %");
  249.             break;
  250.         case 20:
  251.             *day = NewString("\ptwentieth %");
  252.             break;
  253.         case 21:
  254.             *day = NewString("\ptwenty-first %");
  255.             break;
  256.         case 22:
  257.             *day = NewString("\ptwenty-second %");
  258.             break;
  259.         case 23:
  260.             *day = NewString("\ptwenty-third %");
  261.             break;
  262.         case 24:
  263.             *day = NewString("\ptwenty-fourth %");
  264.             break;
  265.         case 25:
  266.             *day = NewString("\ptwenty-fifth %");
  267.             break;
  268.         case 26:
  269.             *day = NewString("\ptwenty-sixth %");
  270.             break;
  271.         case 27:
  272.             *day = NewString("\ptwenty-seventh %");
  273.             break;
  274.         case 28:
  275.             *day = NewString("\ptwenty-eighth %");
  276.             break;
  277.         case 29:
  278.             *day = NewString("\ptwenty-ninth %");
  279.             break;
  280.         case 30:
  281.             *day = NewString("\pthirtieth %");
  282.             break;
  283.         case 31:
  284.             *day = NewString("\pthirty-first %");
  285.             break;
  286.     }
  287.     
  288.     /* Go though and look for holidays -- specific date */
  289.     if ((now.month == 1) & (now.day == 1))
  290.         *greeting = NewString("\pHappy New Year! %");
  291.     else if ((now.month == 2) & (now.day == 14))
  292.         *greeting = NewString("\pHappy Valentine's Day! %");
  293.     else if ((now.month == 3) & (now.day == 17))
  294.         *greeting = NewString("\pHappy Saint Patrick's Day! %");
  295.     else if ((now.month == 3) & (now.day == 19))
  296.         *greeting = NewString("\pHappy Saint Joseph's Day! %");    /* I want a zeppola! */
  297.     else if ((now.month == 6) & (now.day == 14))
  298.         *greeting = NewString("\pHappy Flag Day! %");
  299.     else if ((now.month == 7) & (now.day == 4))
  300.         *greeting = NewString("\pHappy Independence Day! %");
  301.     else if ((now.month == 10) & (now.day == 12))
  302.         *greeting = NewString("\pHappy Columbus Day! %");
  303.     else if ((now.month == 10) & (now.day == 31))
  304.         *greeting = NewString("\pHappy Halloween! %");
  305.     else if ((now.month == 11) & (now.day == 11))
  306.         *greeting = NewString("\pHappy Veterans Day! %");
  307.     else if ((now.month == 12) & (now.day == 25))
  308.         *greeting = NewString("\pMerry Chrismas! %");
  309.     
  310.     /* Now find 2nd Monday, 4th Thursday, etc. */
  311.     else if ((now.month == 2) & (now.day >= 9) & (now.day <= 15) & (now.dayOfWeek == 2))
  312.         *greeting = NewString("\pHappy Presidents' Day! %");
  313.     else if ((now.month == 5) & (now.day >= 8) & (now.day <= 14) & (now.dayOfWeek == 1))
  314.         *greeting = NewString("\pHappy Mother's Day! %");
  315.     else if ((now.month == 6) & (now.day >= 15) & (now.day <= 21) & (now.dayOfWeek ==1))
  316.         *greeting = NewString("\pHappy Father's Day! %");
  317.     else if ((now.month == 9) & (now.day >= 1) & (now.day <= 7) & (now.dayOfWeek == 2))
  318.         *greeting = NewString("\pHappy Labor Day! %");
  319.     else if ((now.month == 11) & (now.day >= 22) & (now.day <= 28) & (now.dayOfWeek == 5))
  320.         *greeting = NewString("\pHappy Thanksgiving! %");
  321.     
  322.     /* Evening before holidays... */
  323.     else if ((now.month == 12) & (now.day == 31) & (now.hour >= 18))
  324.         *greeting = NewString("\pit's New Year's Eve! %");
  325.     else if ((now.month == 12) & (now.day == 25) & (now.hour >= 18))
  326.         *greeting = NewString("\pit's Chrismas Eve! %");
  327.     
  328.     /* If it's not a holiday, then... */
  329.     else if ((now.hour >= 0) & (now.hour <= 4))
  330.         *greeting = NewString("\pyou should be in bed! %");
  331.     else if ((now.hour >= 5) & (now.hour <= 11))
  332.         *greeting = NewString("\pgood morning. %");
  333.     else if ((now.hour >= 12) & (now.hour <= 17))
  334.         *greeting = NewString("\pgood afternoon. %");
  335.     else if ((now.hour >= 18) & (now.hour <= 23))
  336.         *greeting = NewString("\pgood evening. %");
  337. }
  338.  
  339. Boolean
  340. handle_menus(long menu_choice, Boolean prefs)
  341. {    
  342.     static int checked_voice = 0;
  343.     short menu,
  344.           choice;
  345.     Str255 da_name;
  346.     MenuHandle voice_menu;
  347.     VoiceSpec voice;
  348.     Handle voice_res,
  349.            voice_hand;
  350.     OSErr err;
  351.     
  352.     menu = HiWord(menu_choice);
  353.     choice = LoWord(menu_choice);
  354.     
  355.     switch (menu) {
  356.         case MENU_APPLE:
  357.             switch (choice) {
  358.                 case 1:                /* About Branagh */
  359.                     Alert(ALRT_ABOUT, nil);
  360.                     break;
  361.                 default:            /* DAs */
  362.                     GetItem(GetMHandle(MENU_APPLE), choice, da_name);
  363.                     OpenDeskAcc(da_name);
  364.                     break;
  365.             }
  366.             break;
  367.         case MENU_FILE:
  368.             if (choice == FILE_QUIT) 
  369.                 return true;
  370.             break;
  371.         case MENU_VOICES:
  372.             if ((prefs = true) && (choice != 0)) {
  373.                 voice_menu = GetMHandle(MENU_VOICES);
  374.                 if (checked_voice != 0)
  375.                     CheckItem(voice_menu, checked_voice, false);
  376.                 CheckItem(voice_menu, choice, true);
  377.                 GetIndVoice(choice, &voice);
  378.                 voice_res = GetResource(VOICE_RES_TYPE, VOICE_RES_NUMB);
  379.                 PtrToXHand((Ptr)&voice, voice_res, sizeof(VoiceSpec));
  380.                 ChangedResource(voice_res);
  381.                 err = ResError();
  382.                 if (err != noErr)
  383.                     SysBeep(20);
  384.             }
  385.             break;
  386.     }
  387.     return false;
  388. }
  389.  
  390. stop_speech(SpeechChannel channel)
  391. {
  392.     OSErr err;
  393.     
  394.     err = StopSpeechAt(channel, kEndOfWord);
  395.     if (err != noErr)
  396.         SysBeep(20);
  397.     while (SpeechBusy() > 0);
  398. }
  399.  
  400. main()
  401. {
  402.     long info,
  403.          ticks,
  404.          menu_choice;
  405.     int i;
  406.     Boolean done = false,
  407.             prefs;
  408.     EventRecord choice;
  409.     short index;
  410.     StringHandle month,
  411.                  day,
  412.                  weekday,
  413.                  time,
  414.                  greeting,
  415.                  text;
  416.     OSErr err;
  417.     VoiceSpec voice;
  418.     VoiceDescription voice_info;
  419.     SpeechChannel channel;
  420.     DialogPtr voice_dlog;
  421.     Handle menu_bar,
  422.            default_voice;
  423.     MenuHandle menu,
  424.                voice_menu;
  425.     Point where;
  426.     WindowPtr which_window;
  427.     Boolean galatea = false;
  428.     extern short prefs_file_refnum,
  429.                  vol_refnum;
  430.     
  431.     toolbox_init();
  432.     FlushEvents(everyEvent, 0);
  433.     prefs = prefs_init();
  434.     
  435.     menu_bar = GetNewMBar(MENU_BAR);            /* Set up menus... */
  436.     if (menu_bar == nil) {
  437.         SysBeep(20);
  438.         return;
  439.     }
  440.     else 
  441.         SetMenuBar(menu_bar);
  442.         
  443.     menu = GetMHandle(MENU_APPLE);
  444.     AddResMenu(menu, 'DRVR');
  445.     
  446.     err = Gestalt(gestaltSpeechAttr, &info);
  447.     if (err == gestaltUndefSelectorErr) {
  448.         ParamText("\pWelcome! requires that the Speech Manager be installed. Sorry.", "\p", "\p", "\p");
  449.         StopAlert(ALRT_ERR, nil);
  450.         SysBeep(20);
  451.         return;
  452.     }
  453.     else if (err != noErr) {
  454.         ParamText("\pProblem calling Gestalt: exiting.", "\p", "\p", "\p");
  455.         StopAlert(ALRT_ERR, nil);
  456.         SysBeep(20);
  457.         return;
  458.     }
  459.     
  460.     if (!(info && (1L << gestaltSpeechMgrPresent))) {
  461.         ParamText("\pWelcome! requires that the Speech Manager be installed. Sorry.", "\p", "\p", "\p");
  462.         StopAlert(ALRT_ERR, nil);
  463.         SysBeep(20);
  464.         return;
  465.     }
  466.  
  467.     err = CountVoices(&index);            /* How many voices do we have? */
  468.     if (err != noErr) {
  469.         ParamText("\pI really don't think there should have been an error here...", "\p", "\p", "\p");
  470.         StopAlert(ALRT_ERR, nil);
  471.         SysBeep(20);
  472.         return;
  473.     }
  474.  
  475.     voice_menu = GetMHandle(MENU_VOICES);
  476.     for (i = 1; i <= index; i++) {
  477.         err = GetIndVoice(i, &voice);
  478.         if (err != noErr) {
  479.             ParamText("\pCouldn't find indicated voice. Exiting.", "\p", "\p", "\p");
  480.             StopAlert(ALRT_ERR, nil);
  481.             SysBeep(20);
  482.             return;
  483.         }
  484.         GetVoiceDescription(&voice, &voice_info, sizeof(VoiceDescription));
  485.         AppendMenu(voice_menu, voice_info.name);
  486.         if ((voice.creator == 'gala') && (voice.id == 12))    /* If "Female voice" is available,*/
  487.             galatea = true;                                    /* use it, unless overruled */
  488.     }
  489.     
  490.     DrawMenuBar();
  491.     
  492.     default_voice = GetResource(VOICE_RES_TYPE, VOICE_RES_NUMB);
  493.     HLock(default_voice);
  494.     if (((VoiceSpec *)*default_voice)->creator != '????') {
  495.         voice.creator = ((VoiceSpec *)*default_voice)->creator;
  496.         voice.id = ((VoiceSpec *)*default_voice)->id;
  497.         GetVoiceDescription(&voice, &voice_info, sizeof(VoiceDescription));
  498.         galatea = false;
  499.     }
  500.     HUnlock(default_voice);
  501.     
  502.     if (galatea) {
  503.         voice.creator = 'gala';
  504.         voice.id = (long)12;
  505.         GetVoiceDescription(&voice, &voice_info, sizeof(VoiceDescription));
  506.     }
  507.     
  508.     err = NewSpeechChannel(&voice, &channel);    /* Open a SpeechChannel */
  509.     if (err == synthOpenFailed) {
  510.         ParamText("\pCould not open SpeechChannel: Try increasing the memory partition.", "\p", "\p", "\p");
  511.         StopAlert(ALRT_ERR, nil);
  512.         return;
  513.     }
  514.     else if (err != noErr) {
  515.         ParamText("\pCould not open SpeechChannel: exiting.", "\p", "\p", "\p");
  516.         StopAlert(ALRT_ERR, nil);
  517.         SysBeep(20);
  518.         return;
  519.     }
  520.     
  521.     ParamText(voice_info.name, "\p", "\p", "\p");
  522.     voice_dlog = GetNewDialog(DLOG_VOICE, nil, WINDOW_IN_FRONT);
  523.     if (voice_dlog == nil) {
  524.         ParamText("\pCan't show current voice...", "\p", "\p", "\p");
  525.         StopAlert(ALRT_ERR, nil);
  526.     }
  527.     ShowWindow(voice_dlog);
  528.     DrawDialog(voice_dlog);
  529.     
  530.     date_to_text(&month, &day, &weekday, &time, &greeting);
  531.     
  532.     /* Plug everything into one long string... */
  533.     text = NewString("\pWelcome to Mackintosh, and %");
  534.     SetHandleSize(text, sizeof(Str255));
  535.     Munger(text, 1, "%", 1, *greeting+1, **greeting);     /* Find the %, and replace it with */
  536.     **text = **text + **greeting - 1;                    /* the next part of the string... */
  537.     Munger(text, 1, "%", 1, "It's %", 6);
  538.     **text = **text + 5;                                /* Fix the length byte, ignoring the */
  539.     Munger(text, 1, "%", 1, *weekday+1, **weekday);        /* length byte from the replacement string*/
  540.     **text = **text + **weekday - 1;                    /* (it got cut out, *weekday+1, anyway) */
  541.     Munger(text, 1, "%", 1, *month+1, **month);
  542.     **text = **text + **month - 1;
  543.     Munger(text, 1, "%", 1, *day+1, **day);
  544.     **text = **text + **day - 1;
  545.     Munger(text, 1, "%", 1, "at %", 4);
  546.     **text = **text + 3;
  547.     Munger(text, 1, "%", 1, *time + 1, **time);
  548.     **text = **text + **time - 1;
  549.     Munger(text, 1, "%", 1, ". Let's go!", 11);
  550.     **text = **text + 10;
  551.     
  552.     MoveHHi(text);
  553.     HLock(text);
  554.     SpeakText(channel, (Ptr)(*text + 1), **text);        /* Then speak the text through the channel */
  555.                                                         /* we got up top... */
  556.     while(!done) {
  557.         WaitNextEvent((mDownMask | keyDownMask), &choice, 15, nil);
  558.         switch (choice.what) {
  559.             case mouseDown:
  560.                 where = choice.where;
  561.                 switch (FindWindow(where, &which_window)) {
  562.                     case inMenuBar:
  563.                         menu_choice = MenuSelect(where);
  564.                         if (HiWord(menu_choice) != 0) {
  565.                             done = handle_menus(menu_choice, prefs);
  566.                             if (done == true)
  567.                                 stop_speech(channel);
  568.                         }
  569.                         HiliteMenu(0);
  570.                         break;
  571.                     default:
  572.                         stop_speech(channel);
  573.                         done = true;
  574.                         break;
  575.                 }
  576.                 break;
  577.             case keyDown:
  578.                 stop_speech(channel);
  579.                 done = true;
  580.                 break;
  581.         }
  582.         if (SpeechBusy() == 0)
  583.             done = true;
  584.     }
  585.     
  586.     HUnlock(text);    
  587.     
  588.     DisposeSpeechChannel(channel);                        /* And clean up. */
  589.     DisposeDialog(voice_dlog);
  590.     DisposeHandle(month);
  591.     DisposeHandle(day);
  592.     DisposeHandle(weekday);
  593.     DisposeHandle(greeting);
  594.     DisposeHandle(text);
  595.     DisposeHandle(time);
  596.     CloseResFile(prefs_file_refnum);
  597.     FlushVol(NewString("\p"), vol_refnum);
  598. }
  599.