# HG changeset patch # User Paper # Date 1688525081 14400 # Node ID 0ea1ec2da443ad19d35d67cc0474c265533adf19 *: initial commit diff -r 000000000000 -r 0ea1ec2da443 README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Tue Jul 04 22:44:41 2023 -0400 @@ -0,0 +1,5 @@ +# edl-parser +edl-parser is a parser library for Vegas Pro EDL files and translates them into a usable format for manipulation in C/C++. + +# How do I use this? +Drag it into your C/C++ project and adjust your compiler flags accordingly. Then you can call `parse_EDL` with a `char*` containing the entire contents of any EDL file. \ No newline at end of file diff -r 000000000000 -r 0ea1ec2da443 include/edl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/edl.h Tue Jul 04 22:44:41 2023 -0400 @@ -0,0 +1,45 @@ +#include + +typedef enum { + video, + audio +} MediaType; + +typedef struct { + int id; + int track; + double start_time; + double length; + double play_rate; + bool locked; + bool normalized; + int stretch_method; + bool looped; + bool on_ruler; + MediaType media_type; + char* file_name; + int stream; + double stream_start; + double stream_length; + double fade_time_in; + double fade_time_out; + double sustain_gain; + int curve_in; + double gain_in; + int curve_out; + double gain_out; + int layer; + int color; + int curve_in_r; + int curve_out_r; + double play_pitch; + bool lock_pitch; + int first_channel; + int channels; +} EDL_line; + +typedef struct { + EDL_line* edl; + int size; + int current; +} EDL_file; \ No newline at end of file diff -r 000000000000 -r 0ea1ec2da443 src/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.c Tue Jul 04 22:44:41 2023 -0400 @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#include "edl.h" + +int strings_amt = -1; + +/* CRC32 hash function */ +uint32_t crc32b(unsigned char* restrict message) { + int32_t i, j; + uint32_t byte, crc, mask; + + crc = 0xFFFFFFFF; + for (i = 0; message[i] != 0; i++) { + byte = message[i]; // Get next byte. + crc = crc ^ byte; + for (j = 7; j >= 0; j--) { // Do eight times. + mask = -(crc & 1); + crc = (crc >> 1) ^ (0xEDB88320 & mask); + } + } + return ~crc; +} + +/* This parses the first line of the EDL and + creates an array with CRC32 hashes in + the order of the strings. */ +uint32_t* parse_first_line(char* first_line) { + uint32_t* hashes = calloc(32, sizeof(uint32_t)); + int i = 0; + char* token; + hashes[i++] = crc32b(strtok_r(first_line, ";", &token)); + for (;;i++) { + char* token = strtok_r(NULL, ";", &token); + if (token == NULL) + break; + hashes[i] = crc32b(token); + } + strings_amt = i; + free(first_line); + return hashes; +} + +/* -- Functions to extract different datatypes -- */ + +char* get_int(char* input, int* int_return) { + char* ptr_return; + *int_return = strtol(input, &ptr_return, 10); + return ptr_return + 2; +} + +char* get_double(char* input, double* double_return) { + char* ptr_return; + *double_return = strtod(input, &ptr_return); + return ptr_return + 2; +} + +char* get_bool(char* input, bool* bool_return) { + switch (input[0]) { + case 'T': + *bool_return = true; + return input + 6; + case 'F': + *bool_return = false; + return input + 7; + default: + /* what */ + return NULL; + } +} + +char* get_media_type(char* input, MediaType* media_return) { + switch (input[0]) { + case 'V': + *media_return = video; + return input + 7; + case 'A': + *media_return = audio; + return input + 7; + default: + /* what */ + return NULL; + } +} + +/* lenptr is optional */ +char* cut_string_at_match(char* input, char* match, int* lenptr) { + int length = strcspn(&input[1], match); + char* string = calloc(length+1, sizeof(char)); + memcpy(string, &input[1], length); + string[length] = '\0'; + if (lenptr != NULL) + *lenptr = length; + return string; +} + +char* get_string(char* input, char** string_return) { + /* Windows filenames will *NEVER* include double quotes. + This might break with EDL files created with Reaper on Linux. */ + int length; + char* string = cut_string_at_match(input, "\"", &length); + *string_return = string; + return input + length + 4; +} + +/* The memory manager for EDL_file. */ +void allocate_memory(EDL_file* input) { + if (input->size == 0) input->size = 16; + input->edl = realloc(input->edl, (input->size*2) * sizeof(EDL_line)); + input->size *= 2; +} + +/* This is the important function */ +EDL_file* parse_EDL(char* text) { + EDL_file edl; + memset(&edl, '\0', sizeof(edl)); + allocate_memory(&edl); + uint32_t* order = parse_first_line(strtok_r(text, "\n", NULL)); + char* line = strtok(text, "\n"); + while ((line = strtok(NULL, "\n")) != NULL) { + char* tmp_ptr = line; + for (int i = 0; i < strings_amt; i++) { + switch (order[i]) { + case 0x1541c503: /* ID */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].id); + break; + case 0x4b211812: /* Track */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].track); + break; + case 0xbb46516f: /* StartTime */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].start_time); + break; + case 0xaeac5df7: /* Length */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].length); + break; + case 0x03834606: /* PlayRate */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].play_rate); + break; + case 0x0c2083d3: /* Locked */ + tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].locked); + break; + case 0xe60c8b1d: /* Normalized */ + tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].normalized); + break; + case 0xbe5802c9: /* StretchMethod */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].stretch_method); + break; + case 0x4ec8be4c: /* Looped */ + tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].looped); + break; + case 0xe6cb84d1: /* OnRuler */ + tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].on_ruler); + break; + case 0x035f84c2: /* MediaType */ + tmp_ptr = get_media_type(tmp_ptr, &edl.edl[edl.current].media_type); + break; + case 0x379d32c5: /* FileName */ + tmp_ptr = get_string(tmp_ptr, &edl.edl[edl.current].file_name); + break; + case 0x9f334738: /* Stream */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].stream); + break; + case 0x07b4e0e7: /* StreamStart */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].stream_start); + break; + case 0x8f16c7b8: /* StreamLength */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].stream_length); + break; + case 0xd2edd7e4: /* FadeTimeIn */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].fade_time_in); + break; + case 0x792e8c40: /* FadeTimeOut */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].fade_time_out); + break; + case 0x98374657: /* SustainGain */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].sustain_gain); + break; + case 0x3e998b1f: /* CurveIn */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].curve_in); + break; + case 0x82fb09c4: /* GainIn */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].gain_in); + break; + case 0x53add388: /* CurveOut */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].curve_out); + break; + case 0x4210ba56: /* GainOut */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].gain_out); + break; + case 0x89c4df6c: /* Layer */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].layer); + break; + case 0xadf2f1a3: /* Color */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].color); + break; + case 0xa56b43e1: /* CurveInR */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].curve_in_r); + break; + case 0xcb6d715e: /* CurveOutR */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].curve_out_r); + break; + case 0x9da1b9ed: /* PlayPitch */ + tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].play_pitch); + break; + case 0x2bda6ed4: /* LockPitch */ + tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].lock_pitch); + break; + case 0x3071a4c6: /* FirstChannel */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].first_channel); + break; + case 0x7de1bd40: /* Channels */ + tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].channels); + break; + default: + /* ... what */ + break; + } + } + edl.current++; + if (edl.current >= edl.size) + allocate_memory(&edl); + } +}