mirror of
				https://github.com/cookiengineer/audacity
				synced 2025-10-31 14:13:50 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			184 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // allegrowr.cpp -- write sequence to an Allegro file (text)
 | |
| 
 | |
| #include "assert.h"
 | |
| #include "stdlib.h"
 | |
| #include <iostream>
 | |
| #include <fstream>
 | |
| #include <iomanip>
 | |
| #include <errno.h>
 | |
| #include <string>
 | |
| #include "memory.h"
 | |
| using namespace std;
 | |
| #include "strparse.h"
 | |
| #include "allegro.h"
 | |
| 
 | |
| // Note about precision: %g prints 6 significant digits. For 1ms precision, 
 | |
| // the maximum magnitude is 999.999, i.e. 1000s < 17minutes. For anything
 | |
| // over 1000s, time in seconds will be printed with 10ms precision, which
 | |
| // is not good. Therefore, times and durations are printed as %.4d, which 
 | |
| // gives 100us precision.
 | |
| // The following define allows you to change this decision:
 | |
| /* #define TIMFMT "%.4d" */
 | |
| #define TIMPREC 4
 | |
| #define TIMFMT fixed << setprecision(TIMPREC)
 | |
| #define GFMT resetiosflags(ios::floatfield) << setprecision(6)
 | |
| 
 | |
| void parameter_print(ostream &file, Alg_parameter_ptr p)
 | |
| {
 | |
|     file << " -" << p->attr_name() << ":";
 | |
|     switch (p->attr_type()) {
 | |
|     case 'a':
 | |
|         file << "'" << alg_attr_name(p->a) << "'";
 | |
|         break;
 | |
|     case 'i':
 | |
|         file << p->i;
 | |
|         break;
 | |
|     case 'l':
 | |
|         file << (p->l ? "true" : "false");
 | |
|         break;
 | |
|     case 'r':
 | |
|         file << p->r;
 | |
|         break;
 | |
|     case 's': {
 | |
|         string str;
 | |
|         string_escape(str, p->s, "\"");
 | |
|         file << str;
 | |
|         break;
 | |
|     }
 | |
|     }
 | |
| }
 | |
| 
 | |
| Alg_event_ptr Alg_seq::write_track_name(ostream &file, int n, 
 | |
|                                         Alg_events &events)
 | |
| // write #track <n> <trackname-or-sequencename>
 | |
| // if we write the name on the "#track" line, then we do *not* want
 | |
| // to write again as an update: "-seqnames:"Jordu", so if we do
 | |
| // find a name and write it, return a pointer to it so the track
 | |
| // writer knows what update (if any) to skip
 | |
| {
 | |
|     Alg_event_ptr e = NULL; // e is the result, default is NULL
 | |
|     file << "#track " << n;
 | |
|     const char *attr = symbol_table.insert_string(
 | |
|                                n == 0 ? "seqnames" : "tracknames");
 | |
|     // search for name in events with timestamp of 0
 | |
|     for (int i = 0; i < events.length(); i++) {
 | |
|         Alg_event_ptr ue = events[i];
 | |
|         if (ue->time > 0) break;
 | |
|         if (ue->is_update()) {
 | |
|             Alg_update_ptr u = (Alg_update_ptr) ue;
 | |
|             if (u->parameter.attr == attr) {
 | |
|                 file << " " << u->parameter.s;
 | |
|                 e = ue; // return the update event we found
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     file << endl; // end of line containing #track [<name>]
 | |
|     return e; // return parameter event with name if one was found
 | |
| }
 | |
| 
 | |
| 
 | |
| void Alg_seq::write(ostream &file, bool in_secs, double offset)
 | |
| {
 | |
|     int i, j;
 | |
|     if (in_secs) convert_to_seconds();
 | |
|     else convert_to_beats();
 | |
|     file << "#offset " << offset << endl;
 | |
|     Alg_event_ptr update_to_skip = write_track_name(file, 0, track_list[0]);
 | |
|     Alg_beats &beats = time_map->beats;
 | |
|     for (i = 0; i < beats.len - 1; i++) {
 | |
|         Alg_beat_ptr b = &(beats[i]);
 | |
|         if (in_secs) {
 | |
|             file << "T" << TIMFMT << b->time;
 | |
|         } else {
 | |
|             file << "TW" << TIMFMT << b->beat / 4;
 | |
|         }
 | |
|         double tempo = (beats[i + 1].beat - b->beat) /
 | |
|                        (beats[i + 1].time - beats[i].time);
 | |
|         file << " -tempor:" << GFMT << tempo * 60 << "\n";
 | |
|     }
 | |
|     if (time_map->last_tempo_flag) { // we have final tempo:
 | |
|         Alg_beat_ptr b = &(beats[beats.len - 1]);
 | |
|         if (in_secs) {
 | |
|             file << "T" << TIMFMT << b->time;
 | |
|         } else {
 | |
|             file << "TW" << TIMFMT << b->beat / 4;
 | |
|         }
 | |
|         file << " -tempor:" << GFMT << time_map->last_tempo * 60.0 << "\n";
 | |
|     }
 | |
| 
 | |
|     // write the time signatures
 | |
|     for (i = 0; i < time_sig.length(); i++) {
 | |
|         Alg_time_sig &ts = time_sig[i];
 | |
|         double time = ts.beat;
 | |
|         if (in_secs) {
 | |
|             file << "T" << TIMFMT << time << " V- -timesig_numr:" << 
 | |
|                     GFMT << ts.num << "\n";
 | |
|             file << "T" << TIMFMT << time << " V- -timesig_denr:" << 
 | |
|                     GFMT << ts.den << "\n";
 | |
|         } else {
 | |
|             double wholes = ts.beat / 4;
 | |
|             file << "TW" << TIMFMT << wholes << " V- -timesig_numr:" <<
 | |
|                     GFMT << ts.num << "\n";
 | |
|             file << "TW" << TIMFMT << wholes << " V- -timesig_denr:" <<
 | |
|                     GFMT << ts.den << "\n";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     for (j = 0; j < track_list.length(); j++) {
 | |
|         Alg_events ¬es = track_list[j];
 | |
|         if (j != 0) update_to_skip = write_track_name(file, j, notes);
 | |
|         // now write the notes at beat positions
 | |
|         for (i = 0; i < notes.length(); i++) {
 | |
|             Alg_event_ptr e = notes[i];
 | |
|             // if we already wrote this event as a track or sequence name,
 | |
|             // do not write it again
 | |
|             if (e == update_to_skip) continue;
 | |
|             double start = e->time;
 | |
|             if (in_secs) {
 | |
|                 file << "T" << TIMFMT << start;
 | |
|             } else {
 | |
|                 file << "TW" << TIMFMT << start / 4;
 | |
|             }
 | |
|             // write the channel as Vn or V-
 | |
|             if (e->chan == -1) file << " V-";
 | |
|             else file << " V" << e->chan;
 | |
|             // write the note or update data
 | |
|             if (e->is_note()) {
 | |
|                 Alg_note_ptr n = (Alg_note_ptr) e;
 | |
|                 double dur = n->dur;
 | |
|                 file << " K" << n->get_identifier() << 
 | |
|                         " P" << GFMT << n->pitch;
 | |
|                 if (in_secs) {
 | |
|                     file << " U" << TIMFMT << dur;
 | |
|                 } else {
 | |
|                     file << " Q" << TIMFMT << dur;
 | |
|                 }
 | |
|                 file << " L" << GFMT << n->loud; 
 | |
|                 Alg_parameters_ptr p = n->parameters;
 | |
|                 while (p) {
 | |
|                     parameter_print(file, &(p->parm));
 | |
|                     p = p->next;
 | |
|                 }
 | |
|             } else { // an update
 | |
|                 assert(e->is_update());
 | |
|                 Alg_update_ptr u = (Alg_update_ptr) e;
 | |
|                 if (u->get_identifier() != -1) {
 | |
|                     file << " K" << u->get_identifier();
 | |
|                 }
 | |
|                 parameter_print(file, &(u->parameter));
 | |
|             }
 | |
|             file << "\n";
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool Alg_seq::write(const char *filename, double offset)
 | |
| {
 | |
|     ofstream file(filename);
 | |
|     if (file.fail()) return false;
 | |
|     write(file, units_are_seconds, offset);
 | |
|     file.close();
 | |
|     return true;
 | |
| }
 |