1 // Copyright 2004 "Gilles Degottex"
3 // This file is part of "fmit"
5 // "fmit" is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // "fmit" is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "MicrotonalView.h"
21 static const unsigned char g_icon_ji[] = {
22 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
23 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,
24 0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7a, 0x7a, 0xf4, 0x00, 0x00, 0x05,
25 0xc3, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0xb5, 0x97, 0x4b, 0x6c, 0x24,
26 0xc5, 0x19, 0xc7, 0x7f, 0x55, 0xfd, 0x98, 0x5d, 0x7b, 0x1e, 0x1e, 0xdb,
27 0x0c, 0xb3, 0xbb, 0xf6, 0x78, 0xed, 0xf1, 0xda, 0xe0, 0x85, 0x95, 0x80,
28 0x43, 0x88, 0x90, 0x15, 0xb8, 0x70, 0x88, 0xc0, 0x42, 0xe2, 0x86, 0xc4,
29 0x85, 0xa0, 0x58, 0x4a, 0x4e, 0x44, 0x8a, 0x84, 0x72, 0x8a, 0xb4, 0x70,
30 0x08, 0x91, 0x12, 0x5e, 0x97, 0x91, 0x78, 0x48, 0x51, 0x24, 0x94, 0x70,
31 0xca, 0x04, 0x89, 0x03, 0x52, 0x72, 0x18, 0xe5, 0xc4, 0x29, 0x2c, 0x9b,
32 0x08, 0xd6, 0x6b, 0x0f, 0xcc, 0xcb, 0x5e, 0xcf, 0xf8, 0xbd, 0x9e, 0x99,
33 0x6e, 0x4f, 0x17, 0x87, 0xee, 0x9e, 0x99, 0x6e, 0x8f, 0xd7, 0xcb, 0xeb,
34 0x93, 0x4a, 0xdd, 0x35, 0xea, 0xaf, 0xfe, 0xbf, 0xfa, 0x7f, 0x55, 0xd5,
35 0xd3, 0x82, 0x1f, 0x28, 0x16, 0x97, 0x96, 0x47, 0x80, 0x14, 0x70, 0xaf,
36 0x77, 0xed, 0x6f, 0x6d, 0xe0, 0xdd, 0x42, 0x3e, 0x77, 0x3d, 0x9c, 0x27,
37 0xee, 0x72, 0xf0, 0x33, 0xc0, 0x14, 0x30, 0x3d, 0xa0, 0xa5, 0x81, 0x7b,
38 0x00, 0xf3, 0x94, 0x61, 0x1c, 0x20, 0x5b, 0xc8, 0xe7, 0x8a, 0xfd, 0x3f,
39 0xea, 0x21, 0x21, 0x09, 0xfc, 0x04, 0x78, 0x12, 0xb8, 0x14, 0x12, 0x39,
40 0x06, 0x2b, 0x84, 0x20, 0x16, 0x1d, 0x22, 0x1e, 0x1b, 0x26, 0x11, 0x1b,
41 0x26, 0x1e, 0x8b, 0x32, 0x12, 0x8f, 0x12, 0x8f, 0x0d, 0x13, 0x8f, 0x0f,
42 0x93, 0x88, 0x45, 0x11, 0xc0, 0x87, 0xff, 0xfc, 0x17, 0xc5, 0x52, 0x4d,
43 0x02, 0xbf, 0x04, 0x7e, 0x37, 0x10, 0x60, 0x71, 0x69, 0xf9, 0x37, 0xc0,
44 0xcb, 0xde, 0x6c, 0x10, 0x42, 0x30, 0x79, 0x3e, 0xc5, 0xec, 0xcc, 0x24,
45 0xd9, 0x8b, 0x17, 0x18, 0x1f, 0x1d, 0xe9, 0x8a, 0xc4, 0xa3, 0xc3, 0x98,
46 0x67, 0x86, 0x10, 0x7a, 0x84, 0x96, 0xad, 0x68, 0x5a, 0x0e, 0x6d, 0x5b,
47 0xd1, 0xb6, 0x1d, 0x9a, 0x96, 0x43, 0xcb, 0x76, 0x30, 0x34, 0xc9, 0x50,
48 0x44, 0xf2, 0xe8, 0x5c, 0x94, 0xb6, 0x65, 0xf3, 0xe6, 0x3b, 0x7f, 0x07,
49 0x78, 0x2c, 0x3c, 0x09, 0xdd, 0x13, 0xff, 0x2d, 0xf0, 0x1a, 0xc0, 0xc3,
50 0x0f, 0xce, 0xf3, 0xc2, 0x73, 0x4f, 0x73, 0x69, 0x26, 0x83, 0xe5, 0x68,
51 0x34, 0x2d, 0x87, 0x66, 0xbb, 0x43, 0xd3, 0x52, 0x1c, 0x5a, 0x0e, 0xdb,
52 0x6d, 0x87, 0x6a, 0xbd, 0x83, 0xe3, 0x74, 0xe8, 0xa8, 0x43, 0x94, 0x52,
53 0x38, 0x0a, 0x1c, 0xa5, 0x50, 0x0a, 0x1c, 0xc7, 0xef, 0x77, 0x70, 0x1c,
54 0xc5, 0x23, 0x33, 0xc3, 0x3c, 0x70, 0x5f, 0xd6, 0xd7, 0x5b, 0x18, 0x08,
55 0x00, 0x3c, 0x03, 0xf0, 0xb3, 0x9f, 0x3e, 0xc4, 0xd5, 0x97, 0x97, 0x29,
56 0x37, 0x2c, 0xfe, 0x5f, 0xb5, 0xb1, 0x8f, 0xac, 0x9e, 0x00, 0xa0, 0x3c,
57 0x11, 0x1c, 0x9b, 0x8d, 0x5a, 0x8d, 0x6a, 0xa5, 0x42, 0xb5, 0x5a, 0xa1,
58 0x56, 0xad, 0xf0, 0xf3, 0xa5, 0x67, 0x49, 0x9f, 0x9f, 0x70, 0x41, 0x1c,
59 0x17, 0xc8, 0x51, 0x82, 0xa6, 0xe5, 0x90, 0xb9, 0x70, 0xaf, 0xaf, 0x37,
60 0xbe, 0xb8, 0xb4, 0x9c, 0x2a, 0xe4, 0x73, 0xb7, 0xc2, 0x00, 0xa3, 0x00,
61 0x17, 0x33, 0xe7, 0x59, 0xdf, 0xb1, 0x69, 0xec, 0x1f, 0x21, 0x05, 0x98,
62 0x86, 0xc0, 0x51, 0x82, 0x7a, 0xbd, 0xc1, 0xe7, 0xd7, 0x3e, 0xa7, 0x54,
63 0x29, 0x53, 0x2e, 0x95, 0xd9, 0xdc, 0xdc, 0x44, 0x29, 0x05, 0x80, 0x69,
64 0x98, 0x5c, 0x9c, 0x99, 0x21, 0x62, 0x4a, 0x22, 0xba, 0x40, 0x21, 0xe8,
65 0x38, 0x0a, 0xa5, 0x04, 0x8e, 0x82, 0x96, 0xed, 0x90, 0x4a, 0x9c, 0x61,
66 0x6c, 0x34, 0x41, 0x63, 0x6b, 0x17, 0xe0, 0x32, 0x30, 0x18, 0x20, 0x7d,
67 0xcf, 0x28, 0x07, 0xcd, 0x0e, 0xa6, 0x2e, 0x50, 0x4a, 0xa0, 0x70, 0x67,
68 0xb2, 0xb1, 0x5e, 0xe3, 0x1f, 0xf9, 0x3c, 0xa6, 0x61, 0x60, 0xd9, 0x76,
69 0xc0, 0xc2, 0x5f, 0xbc, 0xf8, 0x22, 0x53, 0xd3, 0xd3, 0xae, 0xfd, 0x9e,
70 0x43, 0x4a, 0x09, 0xb7, 0x14, 0x80, 0x7d, 0xe4, 0x82, 0x4e, 0x5d, 0x48,
71 0xfb, 0x00, 0x0b, 0xc0, 0xbf, 0xfd, 0x7c, 0xe9, 0x5d, 0x93, 0x00, 0xe9,
72 0xd4, 0x18, 0xba, 0x26, 0x30, 0x34, 0x81, 0xa1, 0xbb, 0x57, 0x53, 0x13,
73 0x3c, 0x74, 0x65, 0x81, 0x3f, 0xfd, 0xf1, 0x55, 0xde, 0xf8, 0xf3, 0x6b,
74 0x3c, 0x78, 0x39, 0x58, 0xc6, 0x56, 0xf3, 0x36, 0x11, 0x5d, 0x62, 0xea,
75 0x82, 0x88, 0x2e, 0xbb, 0xf7, 0xa6, 0xe1, 0x3a, 0x62, 0x77, 0x5c, 0x80,
76 0xc9, 0x5e, 0x19, 0x2e, 0xf7, 0xe7, 0xfb, 0x00, 0x6d, 0x80, 0xe4, 0x48,
77 0x8c, 0x88, 0xd1, 0x13, 0x37, 0x34, 0x81, 0xae, 0x0b, 0xce, 0x9e, 0x31,
78 0x48, 0xc4, 0x86, 0x31, 0x34, 0xc1, 0xa5, 0xd9, 0x99, 0x00, 0x40, 0xb5,
79 0x5a, 0x71, 0x05, 0x3d, 0x61, 0xa3, 0xef, 0xde, 0xd4, 0x25, 0x1d, 0xc7,
80 0x05, 0xc8, 0x9c, 0x00, 0xe0, 0x97, 0x60, 0x0b, 0x88, 0xb6, 0x5a, 0x16,
81 0xf1, 0xa4, 0x44, 0x29, 0x07, 0x47, 0x81, 0x02, 0xcf, 0xd2, 0x5e, 0xcb,
82 0x4e, 0x4f, 0x06, 0x00, 0xca, 0xa5, 0x12, 0x86, 0x2e, 0x7a, 0xd6, 0xfb,
83 0xbb, 0x41, 0x09, 0x4c, 0x5d, 0x30, 0x16, 0x73, 0x25, 0x32, 0x13, 0x69,
84 0x3f, 0x25, 0x60, 0xa1, 0xef, 0xc0, 0x16, 0xc0, 0xed, 0x66, 0x13, 0x43,
85 0x17, 0x68, 0xd2, 0x73, 0x40, 0xd2, 0x75, 0xc2, 0x77, 0x23, 0x0c, 0xf0,
86 0x75, 0xb9, 0xd2, 0x7b, 0x46, 0x17, 0x18, 0xba, 0x24, 0x76, 0x56, 0x63,
87 0x3a, 0x15, 0xe1, 0xfe, 0x89, 0xb3, 0x8c, 0x0c, 0xeb, 0x61, 0x07, 0xc6,
88 0x17, 0x97, 0x96, 0x53, 0x61, 0x07, 0xb6, 0x01, 0x6e, 0xdf, 0x6e, 0xa2,
89 0x6b, 0x02, 0x5d, 0x73, 0x17, 0x20, 0xfe, 0xcc, 0x7d, 0x27, 0x50, 0x24,
90 0x13, 0x51, 0xc6, 0x46, 0x93, 0x34, 0xb6, 0xb6, 0x01, 0xd8, 0xdf, 0x3f,
91 0x60, 0x7f, 0x6f, 0x87, 0xe4, 0x48, 0x12, 0xd3, 0x10, 0x24, 0x86, 0x74,
92 0x86, 0x22, 0xfe, 0xbc, 0x7a, 0x91, 0x4e, 0x8d, 0x61, 0x9a, 0x06, 0x96,
93 0x65, 0xfb, 0x65, 0xb8, 0x75, 0xdc, 0x81, 0xc3, 0x16, 0x9a, 0x04, 0x5d,
94 0x03, 0x5d, 0x82, 0xa6, 0x09, 0xb7, 0x49, 0x17, 0x4a, 0x97, 0x12, 0x5d,
95 0x1e, 0x77, 0xa1, 0x56, 0xad, 0x92, 0x4e, 0x1a, 0x9c, 0x4b, 0x9a, 0x03,
96 0xc5, 0xc1, 0x3f, 0x59, 0xbb, 0x2e, 0x74, 0xcb, 0x10, 0x2a, 0x41, 0x0b,
97 0x4d, 0x8a, 0x40, 0xd3, 0xa5, 0x40, 0xd7, 0x40, 0x93, 0xa0, 0x69, 0x2e,
98 0xd4, 0x6c, 0x08, 0x60, 0xbd, 0x56, 0x25, 0x62, 0x0c, 0x16, 0xee, 0x8f,
99 0xe9, 0xcc, 0x39, 0xff, 0xb6, 0xbb, 0x10, 0x03, 0x25, 0x38, 0x3c, 0x6c,
100 0x22, 0x05, 0x68, 0x52, 0x74, 0xad, 0x47, 0x29, 0x14, 0xfd, 0x7d, 0x98,
101 0x9b, 0xc9, 0x04, 0x06, 0xfe, 0xf2, 0xe6, 0xd7, 0xa7, 0x8a, 0x03, 0x5c,
102 0x9c, 0x3c, 0x19, 0xa0, 0x0e, 0xb0, 0xb3, 0x77, 0x80, 0x10, 0x02, 0x29,
103 0x14, 0x4a, 0xb8, 0x62, 0x4a, 0xb8, 0x2f, 0x41, 0x1f, 0x40, 0x00, 0x57,
104 0xee, 0x9f, 0x0e, 0x02, 0xac, 0x7e, 0x6b, 0x80, 0x63, 0x25, 0x28, 0x02,
105 0xd4, 0x36, 0xea, 0x08, 0x40, 0x0a, 0x81, 0x26, 0x04, 0x52, 0x0a, 0xa4,
106 0x04, 0x29, 0x40, 0x4a, 0x30, 0x35, 0xc1, 0x50, 0x44, 0x32, 0x3e, 0x1a,
107 0x67, 0x2c, 0x99, 0xe8, 0x0e, 0xbc, 0xd9, 0xd8, 0x61, 0x7b, 0x67, 0xef,
108 0xdb, 0x00, 0x74, 0x77, 0x82, 0x0f, 0xb0, 0x0a, 0x50, 0x5d, 0xaf, 0x23,
109 0x3c, 0x31, 0x21, 0x3c, 0x61, 0x0f, 0xc4, 0xdf, 0x66, 0x7e, 0xcc, 0x65,
110 0x83, 0x65, 0xf8, 0xe2, 0x2e, 0xca, 0x70, 0xe1, 0x5c, 0x0a, 0x5d, 0xd7,
111 0xfc, 0xee, 0xe5, 0x63, 0x00, 0xb5, 0x8d, 0x3a, 0x4a, 0xa9, 0xae, 0x78,
112 0x0f, 0xc2, 0x5d, 0x17, 0xfd, 0x11, 0x06, 0xf8, 0x72, 0xb5, 0x74, 0x2a,
113 0x80, 0xa6, 0xc9, 0xfe, 0xf3, 0x60, 0xa1, 0x0b, 0x50, 0xc8, 0xe7, 0xb6,
114 0x81, 0x1d, 0xcb, 0x3e, 0xa2, 0xb1, 0xb5, 0x8b, 0x40, 0x78, 0x6b, 0xc1,
115 0xbd, 0x86, 0xc5, 0x01, 0xe6, 0x66, 0x82, 0x3b, 0xe1, 0xbb, 0x2e, 0xc4,
116 0xfe, 0xbd, 0xe3, 0x96, 0x61, 0xc3, 0x2d, 0x03, 0x5e, 0x1b, 0xa0, 0x0d,
117 0xc0, 0xfc, 0xec, 0xd4, 0x8f, 0x04, 0xb0, 0xbe, 0x09, 0x3d, 0xfd, 0x13,
118 0x23, 0x35, 0x9e, 0x24, 0x11, 0x8f, 0x76, 0xfb, 0xeb, 0xb7, 0x1a, 0xd4,
119 0xdd, 0xd7, 0xad, 0x7f, 0xda, 0x9d, 0x06, 0xb0, 0x00, 0xc1, 0x3f, 0xa5,
120 0xde, 0x3a, 0x68, 0xdc, 0x79, 0x0a, 0x7d, 0x31, 0x3e, 0x9a, 0x60, 0x77,
121 0xef, 0xa0, 0xdb, 0x7f, 0xfe, 0xd7, 0xbf, 0x47, 0x29, 0xc5, 0xfc, 0xec,
122 0x14, 0x6f, 0xbc, 0xf2, 0xd2, 0xc0, 0x9c, 0x91, 0x44, 0xac, 0x9b, 0xbe,
123 0xb8, 0xb4, 0x9c, 0x3a, 0x06, 0x50, 0xdd, 0xa8, 0x9f, 0x2a, 0xfc, 0xfe,
124 0x07, 0x1f, 0xf1, 0x9f, 0x4f, 0x3f, 0xe3, 0x66, 0xb1, 0xd2, 0xfd, 0xcd,
125 0x34, 0x0d, 0xa6, 0x26, 0xd2, 0xcc, 0x65, 0x33, 0x5c, 0x59, 0xc8, 0x9e,
126 0x98, 0x6b, 0x1a, 0x46, 0xa0, 0xdf, 0x0f, 0xb0, 0x06, 0xbd, 0x12, 0xdc,
127 0x29, 0xfe, 0xfb, 0xbf, 0x1b, 0x44, 0x4c, 0x83, 0x67, 0x9f, 0x7a, 0x82,
128 0xf9, 0x6c, 0x86, 0xb9, 0x6c, 0x86, 0xa9, 0x89, 0x73, 0x68, 0xda, 0x9d,
129 0x8f, 0xe3, 0x8d, 0xcd, 0x2d, 0xde, 0x7e, 0xef, 0x43, 0xbf, 0xdb, 0x2a,
130 0xe4, 0x73, 0xb7, 0xbe, 0x93, 0x03, 0xaf, 0x5f, 0x1d, 0x6c, 0xaf, 0x1f,
131 0x47, 0x47, 0x1d, 0x8a, 0xa5, 0x2a, 0x2b, 0x6b, 0x65, 0x6e, 0xac, 0x95,
132 0xb9, 0xb9, 0x56, 0xe6, 0xc6, 0x5a, 0x89, 0xfd, 0x83, 0xc3, 0xfe, 0xc7,
133 0xfe, 0x0a, 0x41, 0x07, 0xbe, 0x02, 0x3a, 0x8d, 0xad, 0x5d, 0xad, 0x6d,
134 0xd9, 0x44, 0xcc, 0xa0, 0x55, 0x27, 0xc5, 0xee, 0xde, 0x01, 0x2b, 0x45,
135 0x5f, 0xa4, 0xcc, 0xca, 0x5a, 0x99, 0x62, 0xa9, 0x4a, 0xa7, 0xe3, 0x0c,
136 0x7a, 0xbc, 0x09, 0x5c, 0x07, 0xfe, 0x06, 0xbc, 0x09, 0xa1, 0x85, 0xbe,
137 0xb8, 0xb4, 0xbc, 0x0a, 0x4c, 0xbf, 0x7e, 0xf5, 0x25, 0x1e, 0xbe, 0x32,
138 0x1f, 0xc8, 0x74, 0x1c, 0x87, 0xca, 0xfa, 0x26, 0x2b, 0x9e, 0xc8, 0xca,
139 0x5a, 0x89, 0x95, 0xb5, 0x32, 0x9b, 0x8d, 0x9d, 0x93, 0xd8, 0x8a, 0xc0,
140 0x67, 0xa1, 0x76, 0xa3, 0x90, 0xcf, 0x05, 0xc8, 0xf4, 0x50, 0xd2, 0xc7,
141 0xc0, 0xaf, 0xfe, 0xf0, 0xd6, 0x5f, 0x78, 0xf2, 0x89, 0x47, 0xe9, 0x74,
142 0x3a, 0xec, 0xee, 0x1d, 0xb0, 0xfa, 0x55, 0x85, 0x9b, 0xc5, 0x0a, 0xad,
143 0xb6, 0x35, 0x48, 0x68, 0x1f, 0xb8, 0x16, 0x12, 0xba, 0x56, 0xc8, 0xe7,
144 0x4e, 0x7f, 0x39, 0x70, 0xdc, 0x81, 0xf3, 0xc0, 0x27, 0x0c, 0xf8, 0x82,
145 0xc1, 0xfd, 0x36, 0x59, 0x19, 0x30, 0xab, 0x62, 0x21, 0x9f, 0x53, 0x77,
146 0x23, 0x76, 0x2a, 0x80, 0x07, 0x61, 0x02, 0x8f, 0x03, 0x4f, 0x7b, 0xa2,
147 0xbe, 0xd0, 0xf5, 0x42, 0x3e, 0x77, 0x18, 0x7e, 0xfe, 0xfb, 0xc6, 0x37,
148 0xa1, 0xfe, 0x5a, 0x08, 0x89, 0xe7, 0x8c, 0xbc, 0x00, 0x00, 0x00, 0x00,
149 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
158 #include <qpainter.h>
159 #include <qfiledialog.h>
160 #include <qmessagebox.h>
163 #include <Music/Music.h>
164 using namespace Music;
166 // ---------------------- MScale ------------------------------
168 void MScale::load_scala(const QString& file_name)
170 ifstream file(file_name.latin1());
173 throw MicrotonalView::tr("Unkown filename: '")+file_name+"'";
179 file.getline(buff, 1024);
186 m_name = QString(buff);
187 m_name = m_name.remove("\r");
188 m_name = m_name.remove("\n");
189 m_name = m_name.simplifyWhiteSpace();
192 else if(lines_red==1)
194 // ignore number of lines ...
199 bool is_ratio = true;
200 for(size_t i=0; is_ratio && i<strlen(buff); i++)
201 is_ratio = buff[i]!='.';
207 stringstream in(buff);
208 in >> num >> slash >> den;
209 if(num<0) throw QString("Line ")+QString::number(num_line)+": Parsed numerator is negative '"+QString::number(num)+"'";
210 if(slash!='/') throw QString("Line ")+QString::number(num_line)+": There is no slash between numerator and denominator"+slash+"'";
211 if(den<=0) throw QString("Line ")+QString::number(num_line)+": Parsed denominator is not positive'"+QString::number(den)+"'";
212 values.push_back(MValue(num, den));
217 stringstream in(buff);
219 if(cents<=0.0) throw QString("Line ")+QString::number(num_line)+": Parsed cents value is negative '"+QString::number(cents)+"'";
220 values.push_back(MValue(cents));
224 file.getline(buff, 1024);
229 MScale::MScale(const QString& name)
233 MScale::MScale(const QString& file_name, FileType type)
237 if(type==SCALA) load_scala(file_name);
240 cerr << "MicrotonalView::Scale::Scale unsupported file type '" << type << "'" << endl;
244 bool MScale::operator != (const MScale& scale)
246 return m_name!=scale.m_name;
249 // ---------------------- QRoot button -------------------------
251 QRoot::QRoot(MicrotonalView* view, int ht)
252 : QPushButton(view, "QRoot:"+QString::number(ht))
255 // cerr << "QRoot::QRoot " << m_ht << endl;
259 connect(this, SIGNAL(clicked()), this, SLOT(clicked2()));
260 connect(this, SIGNAL(rootClicked(int)), view, SLOT(selectRoot(int)));
262 setText(h2n(ht, GetNotesName(), GetTonality(), false));
263 setToggleButton(true);
264 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
265 setFixedWidth(35); // TODO
266 setFocusPolicy(QPushButton::NoFocus);
268 void QRoot::clicked2()
270 emit(rootClicked(m_ht));
273 // --------------------------- MicrotonalView ----------------------------
275 MicrotonalView::MicrotonalView(QWidget* parent)
276 : QFrame(parent, "MicrotonalView")
277 , View("Microtonal", this)
278 , ui_scale_menu(this)
280 setting_selectedRoot = -1000;
282 m_selected_jivalue = NULL;
287 img.loadFromData(g_icon_ji, sizeof(g_icon_ji), "PNG");
288 setting_show->setIconSet(QIconSet(QImage(img)));
289 setting_show->setOn(false);
292 m_popup_menu.insertItem(new Title(tr("Root's octave"), &m_popup_menu));
293 setting_octave = new QSpinBox(-3, 8, 1, &m_popup_menu);
294 QToolTip::add(setting_octave, tr("Root's octave"));
295 setting_octave->setValue(3);
296 // m_old_octave = setting_octave->value();
297 // connect(setting_octave, SIGNAL(valueChanged(int)), this, SLOT(octaveChanged(int)));
298 connect(setting_octave, SIGNAL(valueChanged(int)), this, SLOT(emitTuningFreqChanged()));
299 m_popup_menu.insertItem(setting_octave);
301 setting_keepRootToLeft = new QAction(this);
302 setting_keepRootToLeft->setMenuText(tr("Keep root to left side"));
303 setting_keepRootToLeft->setToggleAction(true);
304 connect(setting_keepRootToLeft, SIGNAL(toggled(bool)), this, SLOT(keepRootToLeft(bool)));
305 setting_keepRootToLeft->addTo(&m_popup_menu);
307 setting_loadScale = new QAction(this);
308 setting_loadScale->setMenuText(tr("Load Scala file ..."));
309 setting_loadScale->addTo(&m_popup_menu);
310 connect(setting_loadScale, SIGNAL(activated()), this, SLOT(loadScale()));
311 ui_scale_menu.setCheckable(true);
312 m_popup_menu.insertItem(tr("used scale"), &ui_scale_menu);
314 QVBoxLayout* layout = new QVBoxLayout(this, 0, 0, "MicrotonalView:layout");
315 QHBoxLayout* roots_layout = new QHBoxLayout(layout, 0, "MicrotonalView:roots_layout");
316 for(int i=0; i<13; i++)
318 m_roots.push_back(new QRoot(this, i+3));
319 roots_layout->addWidget(m_roots.back());
321 roots_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
323 m_roots.back()->setDisabled(true);
324 ui_scale = new QScaleLabel(this);
325 layout->addWidget(ui_scale);
326 ui_ratios = new QRatiosLabel(this);
327 layout->addWidget(ui_ratios);
329 setMaximumHeight(ui_scale->maximumHeight()+ui_ratios->maximumHeight()+20);
331 load_default_scales();
338 void MicrotonalView::save()
340 s_settings->writeEntry("octave", setting_octave->value());
341 s_settings->writeEntry("keepRootToLeft", setting_keepRootToLeft->isOn());
342 QStringList scale_list;
343 for(size_t i=0; i<setting_scales.size(); i++)
344 if(!setting_scales[i]->getPath().isEmpty())
345 scale_list.push_back(setting_scales[i]->getPath());
346 s_settings->writeEntry("scales", scale_list);
347 s_settings->writeEntry("selectedScale", setting_selectedScale->getName());
348 s_settings->writeEntry("lastScalesDirectory", setting_lastScalesDirectory);
349 s_settings->writeEntry("selectedRoot", setting_selectedRoot);
351 void MicrotonalView::load()
353 setting_octave->setValue(s_settings->readNumEntry("octave", setting_octave->value()));
354 setting_keepRootToLeft->setOn(s_settings->readBoolEntry("keepRootToLeft", setting_keepRootToLeft->isOn()));
355 QStringList scale_list = s_settings->readListEntry("scales");
356 for(QStringList::iterator it=scale_list.begin(); it!=scale_list.end(); ++it)
360 MScale* scale = new MScale(*it, MScale::SCALA);
361 setting_scales.push_back(scale);
363 catch(QString error){cerr << "MicrotonalView::load " << error << endl;}
367 selectScale(s_settings->readEntry("selectedScale", "default"));
368 setting_lastScalesDirectory = s_settings->readEntry("lastScalesDirectory", ".");
369 selectRoot(s_settings->readNumEntry("selectedRoot", m_roots[0]->m_ht));
371 void MicrotonalView::clearSettings()
373 s_settings->removeEntry("octave");
374 s_settings->removeEntry("keepRootToLeft");
375 s_settings->removeEntry("scales");
376 s_settings->removeEntry("selectedScale");
377 s_settings->removeEntry("lastScalesDirectory");
378 s_settings->removeEntry("selectedRoot");
381 /*void MicrotonalView::octaveChanged(int value)
388 setting_octave->setValue(-1);
390 else if(m_old_octave==-1)
393 setting_octave->setValue(1);
397 m_old_octave = value;
400 int MicrotonalView::getOctaveShift()
402 return 12*(setting_octave->value()-5);
405 QString MicrotonalView::getTuningNoteName()
407 if(hasTuningFreqSelected())
409 if(m_selected_jivalue->is_ratio)
410 return QString(h2n(setting_selectedRoot+getOctaveShift()))+":"+QString::number(m_selected_jivalue->num)+"/"+QString::number(m_selected_jivalue->den);
412 return QString(h2n(setting_selectedRoot+getOctaveShift()))+":"+QString::number(m_selected_jivalue->cents);
415 return "no tuning note selected";
418 void MicrotonalView::selectScale(int index)
420 assert(index>=0 && index<int(setting_scales.size()));
422 setting_selectedScale = setting_scales[index];
424 for(size_t i=0; i<setting_scales.size(); i++)
425 ui_scale_menu.setItemChecked(i, false);
426 ui_scale_menu.setItemChecked(index, true);
428 ui_ratios->repaint();
430 void MicrotonalView::selectScale(const QString& name)
433 for(size_t i=0; index==-1 && i<setting_scales.size(); i++)
435 if(setting_scales[i]->getName()==name)
437 setting_selectedScale = setting_scales[i];
444 cerr << "MicrotonalView::selectScale unknown scale '" << name << "'" << endl;
448 for(size_t i=0; i<setting_scales.size(); i++)
449 ui_scale_menu.setItemChecked(i, false);
450 ui_scale_menu.setItemChecked(index, true);
452 ui_ratios->repaint();
454 int MicrotonalView::getIndex(MScale* scale)
456 for(size_t i=0; i<setting_scales.size(); i++)
457 if(setting_scales[i]==scale)
463 void MicrotonalView::notesNameChanged()
465 for(int i=0; i<13; i++)
466 m_roots[i]->setText(h2n(m_roots[i]->m_ht, GetNotesName(), GetTonality(), false));
469 void MicrotonalView::keepRootToLeft(bool keep)
473 for(int i=0; i<13; i++)
474 m_roots[i]->m_ht = (setting_selectedRoot+i)%12;
476 selectRoot(setting_selectedRoot);
477 ui_ratios->repaint();
484 void MicrotonalView::setAFreq(float AFreq)
486 float AFreq_old = m_AFreq;
490 if(m_AFreq!=AFreq_old)
491 emitTuningFreqChanged();
494 void MicrotonalView::updateCursor(float freq)
496 ui_scale->m_htf = f2hf(freq, m_AFreq);
500 void MicrotonalView::selectRoot(int ht)
502 // cerr << "MicrotonalView::selectRoot " << ht << endl;
504 if(ht==setting_selectedRoot)
506 for(int i=0; i<13; i++)
507 m_roots[i]->setOn(m_roots[i]->m_ht==ht);
511 if(setting_keepRootToLeft->isOn())
513 for(int i=0; i<13; i++)
514 m_roots[i]->m_ht = (ht+i)%12;
518 for(int i=0; i<13; i++)
519 m_roots[i]->setOn(m_roots[i]->m_ht==ht);
521 setting_selectedRoot = ht;
523 ui_ratios->repaint();
524 emitTuningFreqChanged();
527 void MicrotonalView::emitTuningFreqChanged()
530 if(m_selected_jivalue!=NULL)
532 if(m_selected_jivalue->is_ratio)
533 m_tuningFreq = h2f(setting_selectedRoot+getOctaveShift(), m_AFreq)*m_selected_jivalue->ratio;
535 m_tuningFreq = h2f(setting_selectedRoot+getOctaveShift()+m_selected_jivalue->cents/100.0f, m_AFreq);
538 emit(tuningFreqChanged(m_tuningFreq));
541 MicrotonalView::QScaleLabel::QScaleLabel(MicrotonalView* view)
542 : QLabel(view, "QScaleLabel")
545 setMaximumHeight(15);
548 void MicrotonalView::QScaleLabel::drawContents(QPainter* p)
550 int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
551 int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
552 int w = right - left;
553 p->setBrush(QColor(255,255,255));
554 p->setPen(QColor(128,128,128));
555 p->drawRect(0, 0, left+1, height());
556 p->drawRect(right, 0, width()-(right+1), height());
557 p->setPen(QColor(0,0,0));
558 p->drawRect(left, 0, w+1, height());
562 float htw = w*(m_htf-ui_view->m_roots[0]->m_ht)/12.0f;
563 while(htw>=w) htw-=w;
565 int x = int(left+htw);
566 p->setPen(QColor(0,0,255));
567 p->setBrush(QColor(191,191,255));
570 arr.setPoint(0, x-5, 0);
571 arr.setPoint(1, x+5, 0);
572 arr.setPoint(2, x, 2*height()/3);
573 p->drawConvexPolygon(arr);
574 p->drawLine(x, 2*height()/3, x, height());
576 if(htw<(w/12.0f)/4.0f || -(htw-w)<(w/12.0f)/4.0f)
578 if(htw<(w/12.0f)/4.0f) x += w;
580 arr.setPoint(0, x-5, 0);
581 arr.setPoint(1, x+5, 0);
582 arr.setPoint(2, x, 2*height()/3);
583 p->drawConvexPolygon(arr);
584 p->drawLine(x, 2*height()/3, x, height());
589 MicrotonalView::QRatiosLabel::QRatiosLabel(MicrotonalView* view)
590 : QLabel(view, "QRatiosLabel")
593 setMaximumHeight(12+3*(2*fontMetrics().height()+10));
595 void MicrotonalView::QRatiosLabel::drawTicks(QPainter* p, float r, int h)
597 int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
598 int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
599 int w = right - left;
601 for(float i=r; i<=12.0f; i+=2*r)
603 int x = left + int(w*i/12.0f);
604 p->drawLine(x, 0, x, h);
607 void MicrotonalView::QRatiosLabel::drawContents(QPainter* p)
609 QLabel::drawContents(p);
610 // p->eraseRect(rect());
612 int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
613 int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
614 int w = right - left;
616 int tick_height = 12;
620 p->setPen(QColor(0,0,255));
622 int dec_h = 2*p->fontMetrics().height()+2;
623 int dec_h2 = (height()-tick_height-p->fontMetrics().height()+2)/3;
624 dec_h = min(dec_h, dec_h2);
625 int ht = ui_view->setting_selectedRoot - ui_view->m_roots[0]->m_ht;
626 if(ui_view->setting_keepRootToLeft->isOn()) ht = 0;
627 for(list<MScale::MValue>::iterator it=ui_view->setting_selectedScale->values.begin(); it!=ui_view->setting_selectedScale->values.end(); ++it)
632 htw = w*f2hf(h2f(ht)*(*it).ratio)/12.0f;
634 htw = w*(ht+(*it).cents/100.0f)/12.0f;
638 int x = left + int(htw);
639 int y = tick_height + 2 + dec_h*dec;
640 p->drawLine(x, 0, x, y+dec_h);
644 QRect num_rect = fontMetrics().boundingRect(QString::number((*it).num));
645 num_rect.moveBy(x+1, y+p->fontMetrics().height());
646 QRect den_rect = fontMetrics().boundingRect(QString::number((*it).den));
647 den_rect.moveBy(x+1, y+2*p->fontMetrics().height());
648 (*it).bounding_rect = num_rect;
649 (*it).bounding_rect |= den_rect;
653 QRect cents_rect = fontMetrics().boundingRect(QString::number((*it).cents));
654 cents_rect.moveBy(x+1, y+2*p->fontMetrics().height());
656 (*it).bounding_rect = cents_rect;
658 (*it).bounding_rect.rLeft() = x;
659 (*it).bounding_rect.rRight() += 2;
660 (*it).bounding_rect.rTop() -= 2;
661 (*it).bounding_rect.rBottom() = y+dec_h;
663 if(ui_view->m_selected_jivalue==&(*it))
665 p->setBrush(QColor(210,210,255));
666 p->drawRect((*it).bounding_rect);
671 p->drawText(x+1, y+p->fontMetrics().height(), QString::number((*it).num));
672 p->drawLine(x, y+p->fontMetrics().height()+2, x+p->fontMetrics().width(QString::number((*it).num)), y+p->fontMetrics().height()+2);
673 p->drawText(x+1, y+2*p->fontMetrics().height(), QString::number((*it).den));
677 p->drawText(x+1, y+2*p->fontMetrics().height(), QString::number((*it).cents));
681 if(dec>max_dec-1) dec = 0;
682 if(dec<0) dec = max_dec-1;
686 p->setPen(QColor(0,0,0));
687 for(float i=0.0f; i<=12.0f; i+=1.0f)
689 int x = left + int(w*i/12.0f);
690 p->drawLine(x, 0, x, tick_height);
692 drawTicks(p, 0.5f, tick_height/2);
693 drawTicks(p, 0.25f, tick_height/3);
694 drawTicks(p, 0.125f, tick_height/4);
697 void MicrotonalView::mouseReleaseEvent(QMouseEvent* e)
699 if(e->button()==LeftButton)
701 MScale::MValue* selected_jivalue_old = m_selected_jivalue;
702 m_selected_jivalue = NULL;
704 QPoint mouse_pos = e->pos() - ui_ratios->pos();
705 for(list<MScale::MValue>::iterator it=setting_selectedScale->values.begin(); m_selected_jivalue==NULL && it!=setting_selectedScale->values.end(); ++it)
706 if((*it).bounding_rect.contains(mouse_pos.x(), mouse_pos.y()))
707 m_selected_jivalue = &(*it);
709 if(m_selected_jivalue!=selected_jivalue_old)
711 ui_ratios->repaint();
712 emitTuningFreqChanged();
716 View::mouseReleaseEvent(e);
719 void MicrotonalView::refreshScaleList()
721 ui_scale_menu.clear();
722 for(size_t i=0; i<setting_scales.size(); i++)
724 ui_scale_menu.insertItem(setting_scales[i]->getName(), i);
725 ui_scale_menu.connectItem(i, this, SLOT(selectScale(int)));
726 if(setting_selectedScale==setting_scales[i])
727 ui_scale_menu.setItemChecked(i, true);
730 void MicrotonalView::loadScale()
732 QFileDialog dlg_file(setting_lastScalesDirectory, "Scala files (*.scl *.SCL)", this, "open file dialog", true);
733 dlg_file.setCaption(tr("Open scale file"));
734 dlg_file.setMode(QFileDialog::ExistingFile);
735 dlg_file.setInfoPreviewEnabled(true);
736 ScalePreview p(&dlg_file);
737 dlg_file.setInfoPreview(&p,&p);
738 dlg_file.setPreviewMode(QFileDialog::Info);
742 if(dlg_file.result()==QDialog::Accepted)
744 setting_lastScalesDirectory = dlg_file.dirPath();
745 s_settings->writeEntry("MicrotonalView_lastScalesDirectory", setting_lastScalesDirectory);
746 // cerr << "setting_lastScalesDirectory=" << setting_lastScalesDirectory << endl;
749 MScale* scale = new MScale(dlg_file.selectedFile(), MScale::SCALA);
751 for(size_t i=0; new_one && i<setting_scales.size(); i++)
752 new_one = *scale != *(setting_scales[i]);
755 setting_scales.push_back(scale);
756 selectScale(setting_scales.size()-1);
760 QMessageBox::information(this, tr("Open scale file"), tr("Scale name already exist"), QMessageBox::Ok);
764 QMessageBox::information(this, tr("Open scale file"), tr("Invalid file content !")+"\n("+error+")", QMessageBox::Ok);
768 ui_ratios->repaint();
771 void MicrotonalView::load_default_scales()
773 MScale* scale = new MScale("default");
774 scale->values.push_back(MScale::MValue(25,24));
775 scale->values.push_back(MScale::MValue(16,15));
776 scale->values.push_back(MScale::MValue(9,8));
777 scale->values.push_back(MScale::MValue(7,6));
778 scale->values.push_back(MScale::MValue(75,64));
779 scale->values.push_back(MScale::MValue(6,5));
780 scale->values.push_back(MScale::MValue(5,4));
781 scale->values.push_back(MScale::MValue(32,25));
782 scale->values.push_back(MScale::MValue(125,96));
783 scale->values.push_back(MScale::MValue(4,3));
784 scale->values.push_back(MScale::MValue(25,18));
785 scale->values.push_back(MScale::MValue(45,32));
786 scale->values.push_back(MScale::MValue(36,25));
787 scale->values.push_back(MScale::MValue(3,2));
788 scale->values.push_back(MScale::MValue(25,16));
789 scale->values.push_back(MScale::MValue(8,5));
790 scale->values.push_back(MScale::MValue(5,3));
791 scale->values.push_back(MScale::MValue(125,72));
792 scale->values.push_back(MScale::MValue(16,9));
793 scale->values.push_back(MScale::MValue(9,5));
794 scale->values.push_back(MScale::MValue(15,8));
795 scale->values.push_back(MScale::MValue(48,25));
796 scale->values.push_back(MScale::MValue(125,64));
797 setting_scales.push_back(scale);
800 // ------------------ MicrotonalView::ScalePreview --------------------
801 MicrotonalView::ScalePreview::ScalePreview(QWidget* parent)
804 setAlignment(QLabel::WordBreak|QLabel::AlignVCenter);
805 setMinimumWidth(100);
807 void MicrotonalView::ScalePreview::previewUrl(const QUrl& url)
809 if(url.path().contains(QRegExp("\\.scl$"))==0 && url.path().contains(QRegExp("\\.SCL$"))==0)
817 MScale* scale = new MScale(url.path(), MScale::SCALA);
819 txt += tr("<b>name:</b> ") + scale->getName() + "<p>";
820 txt += tr("<b>number of ratio:</b> ") + QString::number(scale->values.size());
826 setText(tr("Invalid Scala file: ")+error);