mirror of
				https://github.com/cookiengineer/audacity
				synced 2025-11-04 08:04:06 +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;
 | 
						|
}
 |