Accidentals are coming!
I had a few bugs. See the sources, see "git log", blabla. (Three commits on day 010.)
Here is a screenshot with accidentals. (Wrong colors, did that in gimp for better compression.)
As you see, it's wrong. I need a reference point in glyphs to align things horizontally.
As you see too, the note heads are not vertically aligned (here they should). This requires some clean thinking. Not extremely hard but has to be done correctly.
And that's it for today. It was a productive day. I worked way more than one hour though.
Here comes the git log.
day 009 - introducing glyphs Things started to get too messy with plotting. I introduced glyphs. Only plot.c. I should rewrite do_note in size.c. Bah, next time. Tired. I had a bug today. In plot_note, after adaptation for the new glyph thing, I had: pt = (XPoint *)&glyphs[p].p; Instead of: pt = (XPoint *)glyphs[p].p; I had a crash much later on, in the function "plot", the for loop that calls XDrawPoints. The pointer changed. It took some printfs here and there to find. I even tried gdb and its "awatch" command. But I messed up. And if I didn't I couldn't interpret the results anyway. Even by using "disas /m". It was useless. printfs saved me. Just look at what the malloc returns and print the pointer here and there (where it is used) and see where it changes. And realize you had a "&" where it shouldn't. How come I still have such stupid bugs after all those years? Well, the thing is I didn't want to put XPoint in defs.h, so I put void instead. But then when I access the pointer as an XPoint I need to cast. The cast was wrong. The thing is I almost never do such things. I should have checked that more carefully... Spent too much time digging the wrong grave. Not happy today.
No screenshot today. It's the same as day 007. And yes, I checked it to see that it was the same. It had to!
Stupid bug... stupid me...
Nothing much today. Not much time. Just drawing alterations with gimp. See notes.png.
And here come stems and note heads' display!
A funny screenshot today. (The rectangles will move away, don't worry.)
Heights of lines are not correct, as you can see (the first note is not fully visible).
Notes' heads are a bit small, but I won't fix that before a while.
I have a lot of hardcoded values everywhere in the code, it's getting messy. Today I know what this 3 or this 2 means, but in one week?
Whatever will be will be...
It was a nice day! I need to add alterations (at least "diese" and "bemol") (go translate by yourself). Then handle dots. And I'll have a first reasonnable version.
Then I need to handle clefs and "armatures" (translate by thyself).
Then I'll take a break with plotting. I'll do audio playback. Or the cursor. When both are done I'll start to use the program to do my tonal music exercises. Or maybe I'll add text support before that. I have funky ideas for text.
Then the polishing will begin. Down stems. Then linked stems. Then bars. Then linked notes, you know when a note at bar n is linked to the same at bar n+1 to show it continues.
Undo/redo I don't know. There again I have a funky idea but I suppose laziness has its point too.
Then the fun will really start with the main idea of "free placement/dimensions". You select an object and you say "it's smaller" or "it's upper" and the algorithms change the aspect of things. Try the "l" command in gcomposer for a basic version. I don't know how I'll do that but it's the most important thing in there. Resize everything. Repositions everything. ("Resize" means the size of the box around the object in the screenshot above, not bigger/smaller lines/note heads/stems.) (Hum... That could be fun too...)
It's late. Time to sleep.
I just had my first bug!
Here comes the log of the commit.
starting "real drawing". That part will change a lot in the future I think. cairo is there somewhere whispering to my ear. But let's start easy with XDrawPoints. It's not optimized at all. One would use a pixmap and plot by using XCopyArea or something. Bah, let's make something that works. We'll optimize later. See this: XDrawPoints(disp, xp, gc, dots[i].p, dots[0].n, CoordModePrevious); See this 0 that should be an i? For the first time of my life I used this CoordModePrevious thing. But because of this 0 it didn't plot stuff the right way (try it, change the code, see by yourself). I thought the function "init_dots" was wrong, so I digged in there for way too long (let's say 15 minutes or something) (which is a lot in a one hour coding session). Then I modified the definition of the variable "black_head" and I realized that the plotting was correct only for the height of it. I did something like: static char *black_head[] = { ". .", ". .", ". .", ". .", NULL }; Adding lines (here you see 4 of them) to see what would change. If the plotting is correct only for the height of the first symbol, what does it mean? It means I pass this height for every plot. I then looked at how I call "XDrawPoints" and saw this 0. Which comes for a bad evolution of code. At first I plotted only the first symbol, was satisfied, and wanted to see them all, thus the loop. But I forgot this 0. This happens all the time. To every programmer on Earth... Programming is a dirty job. And truth is it's not the height but the number of dots. My debugging thinking was wrong. But the result is correct. Dirty...
And a screenshot.
After the thinking of yesterday, I started the plotting of notes, that is: poking around in plot.c and size.c.
The order of things will be what it has to. If width is to be computed after y which must be done after height, so be it. If notes are to be done after lines, so be it. Whatever.
Maybe it'll be hard to read and modify at some point in the future... Bah, the code will be small. Convoluted at some very specific places, should not be too hard to understand.
Whatever will be will be.
A small screenshot today. Black boxes are supposed to be note's heads. Well, not exactly. These are more "bouding boxes", and they take into account the duration of the note. Notes' heads would just be plotted on the left. It's taking shape!
I really should work earlier in the day...
Today I was on to add notes. I wrote the functions to add
them in the document. I started to think about sizes' computation
and everything messed up in my brain. Chords are spread on several
sublines. What is the bounding box of a chord? In the code I have
line_size
calling subline_size
. But in
reality I can't compute the size of a subline independantly of
other sublines. Maybe the height, but not the width. Width is
dictated by items' widths. So I need to break things up there.
Then come the x, y, rx and ry things.
It's getting messy... Well, not messy. But weird. I expected to compute everything in one place. There I see width and height need a seperate treatment.
Well, current code already computes some stuff in one function
and other stuff in another (x and y of a subline are done in
line_size
and width, height, rx and ry in
subline_size
). So I should not be too surprised.
Anyway, it's late. Too much thinking to do. My brain isn't on for that.
And a strong feeling of total uselesness caught my brain today. I write this primarily to do exercises of Gradus ad Parnassum tonal music study. But what I really need is just paper and a pencil and roll on. So why continue, huh? It smokes a lot of time and I am very slow. Hum... Just to see if I can go to the end? How many lines of code will be there in the end? What functionalities? How long it will have taken?
Bah, let's keep going, for the sake of it. In the end I'll be happy to have done it. That's all what matters.
Nothing much.
Some structuring in there (plot.c and size.c are there!).
I added the "pointer" definition (the place where insertion/deletion takes place in the graphical window). Have a look:
typedef enum { FULL_POINTER, SUB_POINTER } pointer_type; typedef struct { pointer_type t; int line; int subline; int item; int subchord; } pointer;
The pointer will exist in two states, as in gcomposer. Except this time we have to deal with multi-lines' staves, thus the "subline". "line" is the current line where the pointer is. "item" is where we are horizontally on the subline. "subchord" (the name may change) is to edit a particular note of a chord when the pointer is in SUB_POINTER mode. All this is preliminary and may change a lot. Just some thoughts, really.
The "dimensions" thing has changed with the introduction of a reference point. Plotting lines needed this thing.
The pixmap is also there. Drawing takes place in this and when X says we must redraw the window (or part of it, but we do it full all the time after "compressing" the "Expose" events, see the code) we just copy stuff from the pixmap to the window. Double buffering basic thing.
I will modify the X thread so that it can receive a "replot" command. I could replot in another thread but I want to let the X thread do the plot. It removes some funky synchronization's problems. It introduces some more (if you don't take care the X thread accesses data modified by some other thread). We'll see how that thing evolves. But my brain got used to have an X thread with a pipe and throwing stuff in that pipe to tell the X thread do this and that.
Maybe the plot function will turn out to be veeerrryyy slow, in which case the program might become unresponsive and then I'll rethink this choice. But the X window is small, there is nothing much to plot (in the hundreds of X function calls at worst I think), so I think it should be fine. We'll see. No need to solve problems that don't exist, right?
And that's it.
Nothing much, really.
I wanted to do more, but you know... laziness...
A little screenshot? Okay, let's go.
See? Multi-lines' staff in there (lines 2 and 3). The visual aspect of things may change. Or not. It doesn't look too bad. The multi-lines' indication is small and non-intrusive. We'll see.
By the way, I don't cheat for the screenshots, it's the program that does the rendering. I just created "manually" the document with the three lines. See main.c. The code is:
new_line(&d, 2, 0); new_line(&d, 1, 0); new_line(&d, 1, 2);
Enough noise. It's getting late...
Two important functions popped up: size
and
plot
. That will be it. Only those two to compute
size of everything and plot stuff in a pixmap.
Then you see command
, and an example of call
(to quit) by ctrl+q in x.c. There will be another function,
parse(char *)
to process user input from the terminal.
I added some preliminary dimension handling. That thing may move in the future. I don't really know what semantics attach to (x,y). Is it top-left of the object? Imagine a line with some very low or very high notes. How can I draw the staff lines if (x,y) is top-left. I won't know where the staff lines are unless I examine the content. I want to be able to plot stuff by using (x,y) only. So I need (x,y) to be a specific point, useful for drawing. But then the semantics differs for each object. That complicates things a bit.
We'll see how it evolves.
In doc.c we have creation/destruction of elements (line,
note, ...). We also have size computation. Maybe I'll split
things in two files. size
and plot
are really the two important functions in there. They probably
each deserve a file on their own.
I put new_thread
into main.c. I generally like
to keep main.c small with just the main and the command line
arguments processing. This time I think I'll also put utility
functions in there, to minimize number of files.
In that end I also have only one .h file. I think it's enough. In my previous projects, with many .h files, it didn't feel "good". Don't ask me why. It's, I don't know, esthetical.
A long long time ago I also abandoned headers at top of source file. That's useless. It might look "professional" but it's just noise.
What else...
A little screenshot? As you see it's not fullscreen. I will leave the option for window mode. And it was easier for a start. Anyway, there it comes.
Yes, things will change. It may end up bigger. I don't know how to deal with zooming. The problem is that you need straight lines with identical spacing between all of them. So you can't have "free zoom", it would look ugly, at least at small sizes. And we want small sizes.
Anyway, we'll see.
Ah, one last note. See? There is one doc in main
.
That'll be it. No multiple editing. If you want more than one
open document, just run the program more than once. With window
managers featuring "virtual desktops" like the famous fvwm that
should work fine. Why bother with unnecessary complexity?
This is the first "version". I just created the basic document's structure (line, staff, chord, clef, and so on).
A lot of thinking has been done before that release though.
Keyword: simplicity. I wrote gcomposer a few years ago. It was nice. I use it sometimes. The biggest problem: only one staff line. I thought it was enough for classical guitar. Recently I discovered this: zillions of videos in french by a guy who knows what he's talking about. His work: online lessons about classic tonal music. There are exercises. And to do them you need several staves (two). I thought about improving gcomposer. Too much work. Gcomposer is way too bloated. So, there we go. A simpler version, with more in it.
I want a fullscreen "white board" with only staves, a few keyboard commands and a command line to do complex editing. Fully graphical interfaces are interesting but too hard to write. Mixing graphical/text is a good alternative.
And that's it. Just a white fullscreen window.
Then everything in there will have to be customizable. What does that mean? It means to position stuff wherever you want, mostly through basic properties. Everything in there is graphically represented. An "object" has a position and a size. Let's have the ability to move the object relatively to its basic position. Same thing for its width and height.
Not clear huh? You'll see when I'll do it. If I do...
Enough noise for today.
Contact: sed@free.fr
Created:
Mon, 01 Jun 2015 22:45:59 +0200
Last update:
Fri, 03 Jul 2015 19:10:31 +0200