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>
160 #include <q3filedialog.h>
162 #include <qfiledialog.h>
164 #include <qmessagebox.h>
168 #include <qwidgetaction.h>
169 #include <Music/Music.h>
170 using namespace Music;
172 // ---------------------- MScale ------------------------------
174 void MScale::load_scala(const QString& file_name)
176 ifstream file(file_name.toAscii().constData());
179 throw MicrotonalView::tr("Unkown filename: '")+file_name+"'";
185 file.getline(buff, 1024);
192 m_name = QString(buff);
193 m_name = m_name.remove("\r");
194 m_name = m_name.remove("\n");
195 m_name = m_name.simplified();
198 else if(lines_red==1)
200 // ignore number of lines ...
205 bool is_ratio = true;
206 for(size_t i=0; is_ratio && i<strlen(buff); i++)
207 is_ratio = buff[i]!='.';
213 stringstream in(buff);
214 in >> num >> slash >> den;
215 if(num<0) throw QString("Line ")+QString::number(num_line)+": Parsed numerator is negative '"+QString::number(num)+"'";
216 if(slash!='/') throw QString("Line ")+QString::number(num_line)+": There is no slash between numerator and denominator"+slash+"'";
217 if(den<=0) throw QString("Line ")+QString::number(num_line)+": Parsed denominator is not positive'"+QString::number(den)+"'";
218 values.push_back(MValue(num, den));
223 stringstream in(buff);
225 if(cents<0.0) throw QString("Line ")+QString::number(num_line)+": Parsed cents value is negative '"+QString::number(cents)+"'";
226 values.push_back(MValue(cents));
230 file.getline(buff, 1024);
235 MScale::MScale(const QString& name)
239 MScale::MScale(const QString& file_name, FileType type)
243 if(type==SCALA) load_scala(file_name);
246 cerr << "MicrotonalView::Scale::Scale unsupported file type '" << type << "'" << endl;
250 bool MScale::operator != (const MScale& scale)
252 return m_name!=scale.m_name;
255 // ---------------------- QRoot button -------------------------
257 QRoot::QRoot(MicrotonalView* view, int ht)
261 // cerr << "QRoot::QRoot " << m_ht << endl;
265 connect(this, SIGNAL(clicked()), this, SLOT(clicked2()));
266 connect(this, SIGNAL(rootClicked(int)), view, SLOT(selectRoot(int)));
268 setText(QString::fromStdString(h2n(ht, GetNotesName(), GetTonality(), false)));
270 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
271 setFixedWidth(35); // TODO
272 setFocusPolicy(Qt::NoFocus);
274 void QRoot::clicked2()
276 emit(rootClicked(m_ht));
279 // --------------------------- MicrotonalView ----------------------------
281 MicrotonalView::MicrotonalView(QWidget* parent)
283 , View(tr("Microtonal"), this)
284 , ui_scale_menu(tr("Used scale"), this)
286 setting_selectedRoot = -1000;
288 m_selected_jivalue = NULL;
290 setting_selectedScale = NULL;
294 img.loadFromData(g_icon_ji, sizeof(g_icon_ji), "PNG");
295 setting_show->setIcon(QIcon(img));
296 setting_show->setChecked(false);
299 QHBoxLayout* octaveActionLayout = new QHBoxLayout(&m_popup_menu);
301 QLabel* octaveActionTitle = new QLabel(tr("Root's octave"), &m_popup_menu);
302 octaveActionLayout->addWidget(octaveActionTitle);
304 setting_octave = new QSpinBox(&m_popup_menu);
305 setting_octave->setMinimum(-3);
306 setting_octave->setMaximum(8);
307 setting_octave->setSingleStep(1);
308 setting_octave->setToolTip(tr("Root's octave"));
309 setting_octave->setValue(3);
310 // m_old_octave = setting_octave->value();
311 // connect(setting_octave, SIGNAL(valueChanged(int)), this, SLOT(octaveChanged(int)));
312 connect(setting_octave, SIGNAL(valueChanged(int)), this, SLOT(emitTuningFreqChanged()));
313 octaveActionLayout->addWidget(setting_octave);
315 QWidget* octaveActionWidget = new QWidget(&m_popup_menu);
316 octaveActionWidget->setLayout(octaveActionLayout);
318 QWidgetAction* octaveAction = new QWidgetAction(&m_popup_menu);
319 octaveAction->setDefaultWidget(octaveActionWidget);
320 m_popup_menu.addAction(octaveAction);
322 setting_keepRootToLeft = new QAction(tr("Keep root to left side"), this);
323 setting_keepRootToLeft->setCheckable(true);
324 connect(setting_keepRootToLeft, SIGNAL(toggled(bool)), this, SLOT(keepRootToLeft(bool)));
325 m_popup_menu.addAction(setting_keepRootToLeft);
327 setting_loadScale = new QAction(tr("Load Scala file ..."), this);
328 m_popup_menu.addAction(setting_loadScale);
329 connect(setting_loadScale, SIGNAL(activated()), this, SLOT(loadScale()));
331 m_popup_menu.addMenu(&ui_scale_menu);
333 QVBoxLayout* layout = new QVBoxLayout(this);
334 layout->setMargin(0);
335 layout->setSpacing(0);
336 QHBoxLayout* roots_layout = new QHBoxLayout();
337 roots_layout->setSpacing(0);
338 layout->addLayout(roots_layout);
339 for(int i=0; i<13; i++)
341 m_roots.push_back(new QRoot(this, i+3));
342 roots_layout->addWidget(m_roots.back());
344 roots_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
346 m_roots.back()->setDisabled(true);
347 ui_scale = new QScaleLabel(this);
348 layout->addWidget(ui_scale);
349 ui_ratios = new QRatiosLabel(this);
350 layout->addWidget(ui_ratios);
352 setMaximumHeight(ui_scale->maximumHeight()+ui_ratios->maximumHeight()+20);
354 load_default_scales();
361 void MicrotonalView::save()
363 s_settings->setValue("octave", setting_octave->value());
364 s_settings->setValue("keepRootToLeft", setting_keepRootToLeft->isChecked());
365 QStringList scale_list;
366 for(size_t i=0; i<setting_scales.size(); i++)
367 if(!setting_scales[i]->getPath().isEmpty())
368 scale_list.push_back(setting_scales[i]->getPath());
369 s_settings->setValue("scales", scale_list);
370 s_settings->setValue("selectedScale", setting_selectedScale->getName());
371 s_settings->setValue("lastScalesDirectory", setting_lastScalesDirectory);
372 s_settings->setValue("selectedRoot", setting_selectedRoot);
374 void MicrotonalView::load()
376 setting_octave->setValue(s_settings->value("octave", setting_octave->value()).toInt());
377 setting_keepRootToLeft->setChecked(s_settings->value("keepRootToLeft", setting_keepRootToLeft->isChecked()).toBool());
378 QStringList scale_list = s_settings->value("scales").toStringList();
379 for(QStringList::iterator it=scale_list.begin(); it!=scale_list.end(); ++it)
383 MScale* scale = new MScale(*it, MScale::SCALA);
384 setting_scales.push_back(scale);
386 catch(QString error){cerr << "MicrotonalView::load " << error.toStdString() << endl;}
390 selectScale(s_settings->value("selectedScale", "default").toString());
391 setting_lastScalesDirectory = s_settings->value("lastScalesDirectory", ".").toString();
392 selectRoot(s_settings->value("selectedRoot", m_roots[0]->m_ht).toInt());
394 void MicrotonalView::clearSettings()
396 s_settings->remove("octave");
397 s_settings->remove("keepRootToLeft");
398 s_settings->remove("scales");
399 s_settings->remove("selectedScale");
400 s_settings->remove("lastScalesDirectory");
401 s_settings->remove("selectedRoot");
404 /*void MicrotonalView::octaveChanged(int value)
411 setting_octave->setValue(-1);
413 else if(m_old_octave==-1)
416 setting_octave->setValue(1);
420 m_old_octave = value;
423 int MicrotonalView::getOctaveShift()
425 return 12*(setting_octave->value()-5);
428 QString MicrotonalView::getTuningNoteName()
430 if(hasTuningFreqSelected())
432 if(m_selected_jivalue->is_ratio)
433 return QString::fromStdString(h2n(setting_selectedRoot+getOctaveShift()))+":"+QString::number(m_selected_jivalue->num)+"/"+QString::number(m_selected_jivalue->den);
435 return QString::fromStdString(h2n(setting_selectedRoot+getOctaveShift()))+":"+QString::number(m_selected_jivalue->cents);
438 return "no tuning note selected";
441 void MicrotonalView::scaleActionToggled(bool checked)
444 selectScale(((QAction*)sender())->data().toInt());
447 void MicrotonalView::selectScale(int index)
449 assert(index>=0 && index<int(setting_scales.size()));
451 setting_selectedScale = setting_scales[index];
453 QList<QAction*> scaleActions = ui_scale_menu.actions();
455 for (int i = 0; i < scaleActions.size(); i++)
458 scaleActions[i]->setChecked(true);
460 scaleActions[i]->setChecked(false);
463 ui_ratios->repaint();
465 void MicrotonalView::selectScale(const QString& name)
468 for(size_t i=0; index==-1 && i<setting_scales.size(); i++)
470 if(setting_scales[i]->getName()==name)
472 setting_selectedScale = setting_scales[i];
479 cerr << "MicrotonalView::selectScale unknown scale '" << name.toStdString() << "'" << endl;
483 QList<QAction*> scaleActions = ui_scale_menu.actions();
485 for (int i = 0; i < scaleActions.size(); i++)
488 scaleActions[i]->setChecked(true);
490 scaleActions[i]->setChecked(false);
493 ui_ratios->repaint();
495 int MicrotonalView::getIndex(MScale* scale)
497 for(size_t i=0; i<setting_scales.size(); i++)
498 if(setting_scales[i]==scale)
504 void MicrotonalView::notesNameChanged()
506 for(int i=0; i<13; i++)
507 m_roots[i]->setText(QString::fromStdString(h2n(m_roots[i]->m_ht, GetNotesName(), GetTonality(), false)));
510 void MicrotonalView::keepRootToLeft(bool keep)
514 for(int i=0; i<13; i++)
515 m_roots[i]->m_ht = (setting_selectedRoot+i)%12;
517 selectRoot(setting_selectedRoot);
518 ui_ratios->repaint();
525 void MicrotonalView::setAFreq(float AFreq)
527 float AFreq_old = m_AFreq;
531 if(m_AFreq!=AFreq_old)
532 emitTuningFreqChanged();
535 void MicrotonalView::updateCursor(float freq)
537 ui_scale->m_htf = f2hf(freq, m_AFreq);
541 void MicrotonalView::selectRoot(int ht)
543 // cerr << "MicrotonalView::selectRoot " << ht << endl;
545 if(ht==setting_selectedRoot)
547 for(int i=0; i<13; i++)
548 m_roots[i]->setChecked(m_roots[i]->m_ht==ht);
552 if(setting_keepRootToLeft->isChecked())
554 for(int i=0; i<13; i++)
555 m_roots[i]->m_ht = (ht+i)%12;
559 for(int i=0; i<13; i++)
560 m_roots[i]->setChecked(m_roots[i]->m_ht==ht);
562 setting_selectedRoot = ht;
564 ui_ratios->repaint();
565 emitTuningFreqChanged();
568 void MicrotonalView::emitTuningFreqChanged()
571 if(m_selected_jivalue!=NULL)
573 if(m_selected_jivalue->is_ratio)
574 m_tuningFreq = h2f(setting_selectedRoot+getOctaveShift(), m_AFreq)*m_selected_jivalue->ratio;
576 m_tuningFreq = h2f(setting_selectedRoot+getOctaveShift()+m_selected_jivalue->cents/100.0f, m_AFreq);
579 emit(tuningFreqChanged(m_tuningFreq));
582 MicrotonalView::QScaleLabel::QScaleLabel(MicrotonalView* view)
586 setMaximumHeight(15);
589 void MicrotonalView::QScaleLabel::paintEvent(QPaintEvent* event)
591 QLabel::paintEvent(event);
593 QPainter* p = new QPainter(this);
595 int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
596 int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
597 int w = right - left;
598 p->setBrush(QColor(255,255,255));
599 p->setPen(QColor(128,128,128));
600 p->drawRect(0, 0, left+1, height());
601 p->drawRect(right, 0, width()-(right+1), height());
602 p->setPen(QColor(0,0,0));
603 p->drawRect(left, 0, w+1, height());
607 float htw = w*(m_htf-ui_view->m_roots[0]->m_ht)/12.0f;
608 while(htw>=w) htw-=w;
610 int x = int(left+htw);
611 p->setPen(QColor(0,0,255));
612 p->setBrush(QColor(191,191,255));
614 polygon.setPoint(0, x-5, 0);
615 polygon.setPoint(1, x+5, 0);
616 polygon.setPoint(2, x, 2*height()/3);
617 p->drawConvexPolygon(polygon);
618 p->drawLine(x, 2*height()/3, x, height());
620 if(htw<(w/12.0f)/4.0f || -(htw-w)<(w/12.0f)/4.0f)
622 if(htw<(w/12.0f)/4.0f) x += w;
624 polygon.setPoint(0, x-5, 0);
625 polygon.setPoint(1, x+5, 0);
626 polygon.setPoint(2, x, 2*height()/3);
627 p->drawConvexPolygon(polygon);
628 p->drawLine(x, 2*height()/3, x, height());
635 MicrotonalView::QRatiosLabel::QRatiosLabel(MicrotonalView* view)
639 setMaximumHeight(12+3*(2*fontMetrics().height()+10));
641 void MicrotonalView::QRatiosLabel::drawTicks(QPainter* p, float r, int h)
643 int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
644 int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
645 int w = right - left;
647 for(float i=r; i<=12.0f; i+=2*r)
649 int x = left + int(w*i/12.0f);
650 p->drawLine(x, 0, x, h);
653 void MicrotonalView::QRatiosLabel::paintEvent(QPaintEvent* event)
655 QLabel::paintEvent(event);
657 QPainter* p = new QPainter(this);
659 // p->eraseRect(rect());
661 int left = ui_view->m_roots[0]->x() + ui_view->m_roots[0]->width()/2;
662 int right = ui_view->m_roots[12]->x() + ui_view->m_roots[12]->width()/2;
663 int w = right - left;
665 int tick_height = 12;
669 p->setPen(QColor(0,0,255));
671 int dec_h = 2*p->fontMetrics().height()+2;
672 int dec_h2 = (height()-tick_height-p->fontMetrics().height()+2)/3;
673 dec_h = min(dec_h, dec_h2);
674 int ht = ui_view->setting_selectedRoot - ui_view->m_roots[0]->m_ht;
675 if(ui_view->setting_keepRootToLeft->isChecked()) ht = 0;
676 for(list<MScale::MValue>::iterator it=ui_view->setting_selectedScale->values.begin(); it!=ui_view->setting_selectedScale->values.end(); ++it)
681 htw = w*f2hf(h2f(ht)*(*it).ratio)/12.0f;
683 htw = w*(ht+(*it).cents/100.0f)/12.0f;
687 int x = left + int(htw);
688 int y = tick_height + 2 + dec_h*dec;
689 p->drawLine(x, 0, x, y+dec_h);
693 QRect num_rect = fontMetrics().boundingRect(QString::number((*it).num));
694 num_rect.translate(x+1, y+p->fontMetrics().height());
695 QRect den_rect = fontMetrics().boundingRect(QString::number((*it).den));
696 den_rect.translate(x+1, y+2*p->fontMetrics().height());
697 (*it).bounding_rect = num_rect;
698 (*it).bounding_rect |= den_rect;
702 QRect cents_rect = fontMetrics().boundingRect(QString::number((*it).cents));
703 cents_rect.translate(x+1, y+2*p->fontMetrics().height());
705 (*it).bounding_rect = cents_rect;
707 (*it).bounding_rect.setLeft(x);
708 (*it).bounding_rect.setRight((*it).bounding_rect.right() + 2);
709 (*it).bounding_rect.setTop((*it).bounding_rect.top() - 2);
710 (*it).bounding_rect.setBottom(y+dec_h);
712 if(ui_view->m_selected_jivalue==&(*it))
714 p->setBrush(QColor(210,210,255));
715 p->drawRect((*it).bounding_rect);
720 p->drawText(x+1, y+p->fontMetrics().height(), QString::number((*it).num));
721 p->drawLine(x, y+p->fontMetrics().height()+2, x+p->fontMetrics().width(QString::number((*it).num)), y+p->fontMetrics().height()+2);
722 p->drawText(x+1, y+2*p->fontMetrics().height(), QString::number((*it).den));
726 p->drawText(x+1, y+2*p->fontMetrics().height(), QString::number((*it).cents));
730 if(dec>max_dec-1) dec = 0;
731 if(dec<0) dec = max_dec-1;
735 p->setPen(QColor(0,0,0));
736 for(float i=0.0f; i<=12.0f; i+=1.0f)
738 int x = left + int(w*i/12.0f);
739 p->drawLine(x, 0, x, tick_height);
741 drawTicks(p, 0.5f, tick_height/2);
742 drawTicks(p, 0.25f, tick_height/3);
743 drawTicks(p, 0.125f, tick_height/4);
748 void MicrotonalView::mouseReleaseEvent(QMouseEvent* e)
750 if(e->button()==Qt::LeftButton)
752 MScale::MValue* selected_jivalue_old = m_selected_jivalue;
753 m_selected_jivalue = NULL;
755 QPoint mouse_pos = e->pos() - ui_ratios->pos();
756 for(list<MScale::MValue>::iterator it=setting_selectedScale->values.begin(); m_selected_jivalue==NULL && it!=setting_selectedScale->values.end(); ++it)
757 if((*it).bounding_rect.contains(mouse_pos.x(), mouse_pos.y()))
758 m_selected_jivalue = &(*it);
760 if(m_selected_jivalue!=selected_jivalue_old)
762 ui_ratios->repaint();
763 emitTuningFreqChanged();
767 View::mouseReleaseEvent(e);
770 void MicrotonalView::refreshScaleList()
772 ui_scale_menu.clear();
774 QActionGroup* scaleGroup = new QActionGroup(this);
776 for(size_t i=0; i<setting_scales.size(); i++)
778 QAction* scaleAction = ui_scale_menu.addAction(setting_scales[i]->getName());
779 scaleAction->setCheckable(true);
780 scaleAction->setData((int)i);
781 scaleGroup->addAction(scaleAction);
783 if(setting_selectedScale==setting_scales[i])
784 scaleAction->setChecked(true);
786 connect(scaleAction, SIGNAL(toggled(bool)), this, SLOT(scaleActionToggled(bool)));
789 void MicrotonalView::loadScale()
792 Q3FileDialog dlg_file(setting_lastScalesDirectory, "Scala files (*.scl *.SCL)", this, "open file dialog", true);
793 dlg_file.setCaption(tr("Open scale file"));
794 dlg_file.setMode(Q3FileDialog::ExistingFile);
795 dlg_file.setInfoPreviewEnabled(true);
796 ScalePreview p(&dlg_file);
797 dlg_file.setInfoPreview(&p,&p);
798 dlg_file.setPreviewMode(Q3FileDialog::Info);
800 QFileDialog dlg_file(this, tr("Open scale file"), setting_lastScalesDirectory, "Scala files (*.scl *.SCL)");
801 dlg_file.setFileMode(QFileDialog::ExistingFile);
806 if(dlg_file.result()==QDialog::Accepted)
809 setting_lastScalesDirectory = dlg_file.dirPath();
811 setting_lastScalesDirectory = dlg_file.directory().path();
813 s_settings->setValue("MicrotonalView_lastScalesDirectory", setting_lastScalesDirectory);
814 // cerr << "setting_lastScalesDirectory=" << setting_lastScalesDirectory << endl;
818 MScale* scale = new MScale(dlg_file.selectedFile(), MScale::SCALA);
820 MScale* scale = new MScale(dlg_file.selectedFiles()[0], MScale::SCALA);
823 for(size_t i=0; new_one && i<setting_scales.size(); i++)
824 new_one = *scale != *(setting_scales[i]);
827 setting_scales.push_back(scale);
828 selectScale(setting_scales.size()-1);
832 QMessageBox::information(this, tr("Open scale file"), tr("Scale name already exist"), QMessageBox::Ok);
836 QMessageBox::information(this, tr("Open scale file"), tr("Invalid file content !")+"\n("+error+")", QMessageBox::Ok);
840 ui_ratios->repaint();
843 void MicrotonalView::load_default_scales()
845 MScale* scale = new MScale("default");
846 scale->values.push_back(MScale::MValue(25,24));
847 scale->values.push_back(MScale::MValue(16,15));
848 scale->values.push_back(MScale::MValue(9,8));
849 scale->values.push_back(MScale::MValue(7,6));
850 scale->values.push_back(MScale::MValue(75,64));
851 scale->values.push_back(MScale::MValue(6,5));
852 scale->values.push_back(MScale::MValue(5,4));
853 scale->values.push_back(MScale::MValue(32,25));
854 scale->values.push_back(MScale::MValue(125,96));
855 scale->values.push_back(MScale::MValue(4,3));
856 scale->values.push_back(MScale::MValue(25,18));
857 scale->values.push_back(MScale::MValue(45,32));
858 scale->values.push_back(MScale::MValue(36,25));
859 scale->values.push_back(MScale::MValue(3,2));
860 scale->values.push_back(MScale::MValue(25,16));
861 scale->values.push_back(MScale::MValue(8,5));
862 scale->values.push_back(MScale::MValue(5,3));
863 scale->values.push_back(MScale::MValue(125,72));
864 scale->values.push_back(MScale::MValue(16,9));
865 scale->values.push_back(MScale::MValue(9,5));
866 scale->values.push_back(MScale::MValue(15,8));
867 scale->values.push_back(MScale::MValue(48,25));
868 scale->values.push_back(MScale::MValue(125,64));
869 setting_scales.push_back(scale);
872 // ------------------ MicrotonalView::ScalePreview --------------------
874 MicrotonalView::ScalePreview::ScalePreview(QWidget* parent)
877 setAlignment(Qt::AlignVCenter);
879 setMinimumWidth(100);
881 void MicrotonalView::ScalePreview::previewUrl(const Q3Url& url)
883 if(url.path().contains(QRegExp("\\.scl$"))==0 && url.path().contains(QRegExp("\\.SCL$"))==0)
891 MScale* scale = new MScale(url.path(), MScale::SCALA);
893 txt += tr("<b>name:</b> ") + scale->getName() + "<p>";
894 txt += tr("<b>number of ratio:</b> ") + QString::number(scale->values.size());
900 setText(tr("Invalid Scala file: ")+error);