changeset 0:0ea1ec2da443

*: initial commit
author Paper <mrpapersonic@gmail.com>
date Tue, 04 Jul 2023 22:44:41 -0400
parents
children db8b7e45ee55
files README.md include/edl.h src/main.c
diffstat 3 files changed, 275 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /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
--- /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 <stdbool.h>
+
+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
--- /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 <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#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);
+	}
+}