U0 PsmNoteDel(PsmNote *tmpn) { Free(tmpn->word); Free(tmpn); } PsmNote *PsmNoteCopy(PsmNote *tmpn) { PsmNote *tmpn1 = MAllocIdent(tmpn); if (tmpn->word) tmpn1->word = StrNew(tmpn->word); else tmpn1->word = NULL; return tmpn1; } U0 PsmSongDel(PsmNote *head) { PsmNote *tmpn, *tmpn1; tmpn = head->next; while (tmpn != head) { tmpn1 = tmpn->next; PsmNoteDel(tmpn); tmpn = tmpn1; } QueueInit(head); } U0 PsmCutToClip() { PsmNote *tmpn, *tmpn1; PsmSongDel(&psm.clip); tmpn = psm.head.next; while (tmpn != &psm.head) { tmpn1 = tmpn->next; if (tmpn->flags & PSMF_SEL) { if (psm.cur_note == tmpn) psm.cur_note = tmpn->next; QueueRemove(tmpn); tmpn->flags &= ~PSMF_SEL; QueueInsert(tmpn, psm.clip.last); } tmpn = tmpn1; } } U0 PsmPasteClip() { PsmNote *tmpn, *tmpn1; tmpn = psm.clip.next; while (tmpn != &psm.clip) { tmpn1 = PsmNoteCopy(tmpn); QueueInsert(tmpn1, psm.cur_note->last); tmpn = tmpn->next; } } U0 PsmCopyToClip() { PsmNote *tmpn, *tmpn1; PsmSongDel(&psm.clip); tmpn = psm.head.next; while (tmpn != &psm.head) { if (tmpn->flags & PSMF_SEL) { tmpn->flags &= ~PSMF_SEL; tmpn1 = PsmNoteCopy(tmpn); QueueInsert(tmpn1, psm.clip.last); } tmpn = tmpn->next; } } PsmNote *PsmFindNote(I64 x, I64) { PsmNote *tmpn=psm.head.next; PsmRecalcNoteXY; x += PSM_NOTE_SPACING / 2; while (x > tmpn->next->x && tmpn != &psm.head) tmpn = tmpn->next; return tmpn; } U8 *PsmMusicSetOctave(U8 *st, I64 *psm_octave) { while ('0' <= *st <= '9') *psm_octave = *st++ - '0'; return st; } U8 *PsmMusicSetNoteLen(U8 *st, F64 *psm_duration) { Bool cont = TRUE; do { switch (*st++) { case 'w': *psm_duration = 4.0; break; case 'h': *psm_duration = 2.0; break; case 'q': *psm_duration = 1.0; break; case 'e': *psm_duration = 0.5; break; case 's': *psm_duration = 0.25; break; case 't': *psm_duration = 2.0 * *psm_duration / 3.0; break; case '.': *psm_duration = 1.5 * *psm_duration; break; default: st--; cont = FALSE; } } while (cont); return st; } U0 PsmLoadSongStr(U8 *st, I64 *psm_octave, F64 *psm_duration) { PsmNote *tmpn, *tmpn1; I64 note, i = 0; while (*st) { tmpn = CAlloc(sizeof(PsmNote)); while (*st && !('A' <= *st <= 'G') && *st != 'R') { if (*st == 'M') { tmpn1 = CAlloc(sizeof(PsmNote)); tmpn1->type = PSMT_METER; st++; if ('1' <= *st <= '9') tmpn1->meter_top = *st++ - '0'; else tmpn1->meter_top = 4; if (*st == '/') st++; if ('1' <= *st <= '9') tmpn1->meter_bottom = *st++ - '0'; else tmpn1->meter_bottom = 4; PsmSetWidth(tmpn1); QueueInsert(tmpn1, psm.head.last); } while (*st == '(') { Bts(&tmpn->flags, PSMf_TIE); st++; } st = PsmMusicSetOctave(st, psm_octave); st = PsmMusicSetNoteLen(st, psm_duration); } if (!*st) { PsmNoteDel(tmpn); break; } note = *st++ - 'A'; if (note < 7) { note = music.note_map[note]; if (*st == 'b') { Bts(&tmpn->flags, PSMf_FLAT); note--; st++; if (note < 0) //Ab note = 11; else if (note == 2) //Cb *psm_octave -= 1; } else if (*st == '#') { Bts(&tmpn->flags, PSMf_SHARP); note++; st++; if (note > 11) //G# note = 0; else if (note == 3) //B# *psm_octave += 1; } tmpn->ona = Note2Ona(note, *psm_octave); } else tmpn->ona = 0; if (*psm_duration <= 2*.25 / 3) i = 0; else if (*psm_duration <= .25) i = 1; else if (*psm_duration <= 2 * .5 / 3) i = 2; else if (*psm_duration <= .5) i = 3; else if (*psm_duration <= 2.0 / 3) i = 4; else if (*psm_duration <= .5 * 1.5) i = 5; else if (*psm_duration <= 1.0) i = 6; else if (*psm_duration <= 1.5) i = 7; else if (*psm_duration <= 2.0) i = 8; else if (*psm_duration <= 3.0) i = 9; else if (*psm_duration <= 4.0) i = 10; else i = 11; tmpn->duration = i; tmpn->type = PSMT_NOTE; PsmSetWidth(tmpn); QueueInsert(tmpn, psm.cur_note->last); } } U0 PsmLoadSong(U8 *filename, I64 *psm_octave, F64 *psm_duration) { U8 *st; PsmNote *tmpn; CCompCtrl *cc = CompCtrlNew(MStrPrint("#include \"%s\"", filename)); if (FileOcc("incomplete", filename, "")) psm.incomplete_entry->checked = TRUE; else psm.incomplete_entry->checked = FALSE; while (Lex(cc)) { if (cc->token == TK_IDENT) if (!StrCompare(cc->cur_str, "Play")) { if (Lex(cc) == '(') if (Lex(cc) == TK_STR) { tmpn = psm.head.last; st = LexExtStr(cc); PsmLoadSongStr(st, psm_octave, psm_duration); if (cc->token == ',') { if (Lex(cc) == TK_STR) { st = LexExtStr(cc); do { do tmpn = tmpn->next; while (tmpn != &psm.head && tmpn->type == PSMT_METER); if (tmpn != &psm.head) tmpn->word = StrNew(st); st += StrLen(st) + 1; } while (*st); } } } } else if (!StrCompare(cc->cur_str, "music") && Lex(cc) == '.' && Lex(cc) == TK_IDENT) { if (!StrCompare(cc->cur_str, "tempo")) { if (Lex(cc) == '=' && Lex(cc) == TK_F64) { music.tempo = cc->cur_f64 - 0.0005; tempo_state.tempo = Round(TEMPO_RANGE * (music.tempo - 0.5) / 4.4); } } else if (!StrCompare(cc->cur_str, "stacatto_factor")) { if (Lex(cc) == '=' && Lex(cc) == TK_F64) { music.stacatto_factor = cc->cur_f64 - 0.0005; tempo_state.stacatto = Round(TEMPO_RANGE * (music.stacatto_factor - 0.12) / 0.88); } } } } CompCtrlDel(cc); } U8 *PsmConvertSong() { PsmNote *tmpn; U8 *st, *src, *dst; I64 i, ona, note, octave, last_octave, last_duration; i = 0; tmpn = psm.head.next; last_octave = I64_MIN; last_duration = -1; while (tmpn != &psm.head) { dst = &tmpn->ascii; if (tmpn->type == PSMT_METER) { *dst++ = 'M'; *dst++ = tmpn->meter_top + '0'; *dst++ = '/'; *dst++ = tmpn->meter_bottom + '0'; } else { if (tmpn->ona) { ona = tmpn->ona; if (Bt(&tmpn->flags, PSMf_SHARP)) ona--; if (Bt(&tmpn->flags, PSMf_FLAT)) ona++; octave = Ona2Octave(ona); note = Ona2Note (ona); note = music.note_map[*ListSub(note, psm_note_list) - 'A']; } if (Bt(&tmpn->flags, PSMf_TIE)) *dst++ = '('; if (octave != last_octave && tmpn->ona) { *dst++ = octave + '0'; last_octave = octave; } if (tmpn->duration != last_duration) { src = ListSub(tmpn->duration, psm_duration_list); *dst++ = src[0]; if (src[1]) *dst++ = src[1]; last_duration = tmpn->duration; } if (tmpn->ona) { src = ListSub(note, psm_note_list); *dst++ = src[0]; if (src[1]) *dst++ = src[1]; else if (Bt(&tmpn->flags, PSMf_FLAT)) *dst++ = 'b'; else if (Bt(&tmpn->flags, PSMf_SHARP)) *dst++ = '#'; } else *dst++ = 'R'; } *dst++ = 0; i += StrLen(tmpn->ascii); tmpn = tmpn->next; } st = MAlloc(i + 1); dst = st; tmpn = psm.head.next; while (tmpn != &psm.head) { StrCopy(dst, tmpn->ascii); dst += StrLen(tmpn->ascii); tmpn = tmpn->next; } *dst++ = 0; return st; } U8 *PsmSaveSong(U8 *dirname, U8 *full_filename) { CDoc *doc = DocNew(full_filename); Bool has_words; PsmNote *tmpn, *tmpn1; F64 measure_len = 4, two_measure_left = 2 * measure_len; I64 ch; U8 *ptr; Free(PsmConvertSong); //set tmpn->ascii; music.tempo = 4.4 * tempo_state.tempo / TEMPO_RANGE + 0.5; music.stacatto_factor = 0.88 * tempo_state.stacatto / TEMPO_RANGE + 0.12; has_words = FALSE; tmpn = psm.head.next; while (tmpn != &psm.head) { if (PsmHasWords(tmpn->word)) has_words = TRUE; tmpn = tmpn->next; } if (psm.incomplete_entry->checked) DocPrint(doc, "//0 incomplete\n"); else if (has_words) DocPrint(doc, "//0 has words\n"); else DocPrint(doc, "//0 no nothing\n"); DocPrint(doc, "U0 Song()\n" "{\n" "\tFs->task_end_cb=&SoundTaskEndCB;\n" "\tMusicSettingsReset;\n" "\tmusic.tempo=%6.3f;\n" "\tmusic.stacatto_factor=%6.3f;\n" "\ttry {\n" "\t\twhile (!KeyScan) {\n" "\t\t\tPlay(\"", music.tempo + 0.0005, music.stacatto_factor + 0.0005); tmpn = psm.head.next; tmpn1 = tmpn; has_words = FALSE; while (tmpn != &psm.head) { DocPrint(doc, "%s", tmpn->ascii); if (PsmHasWords(tmpn->word)) has_words = TRUE; if (tmpn->type == PSMT_METER) { measure_len = tmpn->meter_top * 4.0 / tmpn->meter_bottom; two_measure_left = 0; } else two_measure_left -= psm_durations[tmpn->duration]; tmpn = tmpn->next; if (two_measure_left < 0.001 && tmpn != &psm.head) { if (has_words) { DocPrint(doc, "\",\n\t\t\""); while (tmpn1 != tmpn) { if (tmpn1->type != PSMT_METER) { if (ptr=tmpn1->word) { while (ch = *ptr) ptr++; DocPrint(doc, "%Q\\0", tmpn1->word); } else DocPrint(doc, " \\0"); } tmpn1 = tmpn1->next; } } DocPrint(doc, "\");\n" "\tPlay(\""); two_measure_left = 2 * measure_len; tmpn1 = tmpn; has_words = FALSE; } } if (has_words) { DocPrint(doc, "\",\n\t\t\""); while (tmpn1 != tmpn) { if (tmpn1->type != PSMT_METER) { if (ptr = tmpn1->word) { while (ch = *ptr) ptr++; DocPrint(doc, "%Q\\0", tmpn1->word); } else DocPrint(doc, " \\0"); } tmpn1 = tmpn1->next; } } DocPrint(doc, "\");\n" "\t\t}\n" "\t} catch\n" "\t\tPutExcept;\n" "\tSound;\n" "}\n" "\n" "Song;\n"); DocRecalc(doc); if (full_filename) Free(full_filename); else StrPrint(doc->filename.name, "%s/Tmp.ZC", dirname); DocWrite(doc, TRUE); full_filename = StrNew(doc->filename.name); DocDel(doc); return full_filename; }