Skip to content

Commit c4f3d43

Browse files
committed
Resource sending
1 parent 780bbd7 commit c4f3d43

2 files changed

Lines changed: 114 additions & 0 deletions

File tree

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ store: patch ## upload and save patch to attached OWL
125125
@echo Sending patch $(PATCHNAME) to $(OWLDEVICE) to store in slot $(SLOT)
126126
@$(FIRMWARESENDER) -q -in $(BUILD)/$(TARGET).bin -out "$(OWLDEVICE)" -store $(SLOT)
127127

128+
resource: $(RESOURCE) ## upload and save resource to attached OWL
129+
@echo Sending resource $(RESOURCE) to $(OWLDEVICE) to store in slot $(SLOT)
130+
@$(FIRMWARESENDER) -q -in $(RESOURCE) -out "$(OWLDEVICE)" -store $(SLOT)
131+
128132
docs: ## generate HTML documentation
129133
@doxygen Doxyfile
130134

Tools/makeresource.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#! /usr/bin/env python3
2+
3+
"""
4+
This script adds resource header and converts byte ordering for binary data.
5+
6+
Input can be obtained from binary file, by parsing WAV files or C sources containing LUTs.
7+
8+
C format parsing tested with Magus LED RGB tables, power and log LUTs.
9+
"""
10+
11+
import argparse
12+
import struct
13+
import sys
14+
import wave
15+
16+
parser = argparse.ArgumentParser(
17+
description='Convert binary data to OpenWare resource')
18+
parser.add_argument(
19+
'-i', '--input', required=True, help='Input file')
20+
parser.add_argument(
21+
'-o', '--output', required=True, help='Output file')
22+
parser.add_argument(
23+
'-p', '--parse', help='Parse LUT from C header file', action='store_true')
24+
parser.add_argument(
25+
'-w', '--wav', help='Convert WAV file to wavetable', action='store_true')
26+
parser.add_argument(
27+
'-f', '--format', help='WAV file sample wavetable (i.e. <H for 16bit unsigned little-endian)', default='<H')
28+
parser.add_argument(
29+
'-d', '--destination_format',
30+
help='Normally this will be retrieved from parsed header. If that fails, use the same format as python\'s "struct" modlue (i.e. <I, <f)')
31+
parser.add_argument('name', help='Resource name')
32+
33+
args = parser.parse_args()
34+
35+
in_file = open(args.input, 'rb')
36+
out_file = open(args.output, 'wb')
37+
38+
data = in_file.read()
39+
40+
formats = {
41+
'float': '<f',
42+
'uint32_t': '<I',
43+
'int32_t': '<i',
44+
'uint16_t': '<H',
45+
'int16_t': '<h',
46+
'uint8_t': '<B',
47+
'int8_t': '<b',
48+
'char': '<c',
49+
'size_t': '<N',
50+
}
51+
52+
if args.parse:
53+
values = data.split(b'{', 1)[1].split(b'}', 1)[0].split(b',')
54+
55+
destination_format = args.destination_format
56+
if not args.destination_format:
57+
last_line = data.split(b'{', 1)[0].splitlines()[-1]
58+
for t in formats:
59+
if f' {t} '.encode('ascii') in last_line:
60+
print(f'Found format: {t} -> {formats[t]}')
61+
destination_format = formats[t]
62+
break
63+
64+
if destination_format is None:
65+
raise ValueError(
66+
'Please specify destination format value with -d parameter. '
67+
'See https://docs.python.org/3/library/struct.html#format-characters')
68+
69+
70+
if 'f' in destination_format or 'F' in destination_format:
71+
values = [float(value.strip()) for value in values if value.strip()]
72+
print('Parsing data as floats')
73+
else:
74+
# Using eval() instead of int() allows us to parse prefixes like 0x or 0b
75+
values = [eval(value.strip()) for value in values if value.strip()]
76+
print('Parsing data as integers')
77+
78+
data = b''.join(struct.pack(destination_format, value) for value in values)
79+
80+
elif args.wav:
81+
w = wave.open(args.input)
82+
n_frames = w.getnframes()
83+
data = w.readframes(w.getnframes())
84+
input_format = args.format[:-1] + str(n_frames) + args.format[-1]
85+
print(f'Parsing file as {input_format}')
86+
values = struct.unpack(input_format, data)
87+
destination_format = args.destination_format or args.format
88+
data = b''.join(struct.pack(destination_format, value) for value in values)
89+
90+
# Magick
91+
out_file.write(0xdadadeed.to_bytes(4, 'little'))
92+
93+
# Data size
94+
size = len(data)
95+
if size % 4:
96+
# Align to 4 bytes
97+
size += 4 - size % 4
98+
print(f'Data size is {size} bytes')
99+
out_file.write(size.to_bytes(4, 'little'))
100+
101+
# Resource name
102+
name = list(struct.pack('24s', args.name.encode('ascii')))
103+
name[-1] = 0 # Force terminate name with zero
104+
name = bytes(name)
105+
for i in range(0, 24, 4):
106+
out_file.write(int.from_bytes(name[i : i + 4], sys.byteorder).to_bytes(4, 'little'))
107+
108+
# Data
109+
for i in range(0, size, 4):
110+
out_file.write(int.from_bytes(data[i : i + 4], sys.byteorder).to_bytes(4, 'little'))

0 commit comments

Comments
 (0)