//========================================================= // MusE // Linux Music Editor // $Id: random.cpp,v 1.1.1.1 2003/10/27 18:52:39 wschweer Exp $ // // (C) Copyright 2001 Werner Schweer (ws@seh.de) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; version 2 of // the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // // This code is an adaption of the random rhythm generator taken // from "The JAZZ++ Midi Sequencer" // Copyright (C) 1994-2000 Andreas Voss and Per Sigmond, all // rights reserved. // Distributed under the GNU General Public License //========================================================= #if 0 #include "random.h" #include "util.h" #include #if USE_ACG ACG rnd(0, 55); #else #include double tRandomGenerator::asDouble() { return double(rand()) / double(RAND_MAX); } tRandomGenerator rnd; #endif // Array of probabilities tRndArray::tRndArray(int nn, int mmin, int mmax) { int i; n = nn; for (i = 0; i < n; i++) array[i] = mmin; min = mmin; max = mmax; nul = min > 0 ? min : 0; } void tRndArray::SetMinMax(int mi, int ma) { min = mi; max = ma; nul = min > 0 ? min : 0; for (int i = 0; i < array.GetSize(); i++) { if (array[i] < min) array[i] = min; else if (array[i] > max) array[i] = max; } } tRndArray::~tRndArray() { } #ifdef FOR_MSW double tRndArray::operator[](double f) #else double tRndArray::operator[](double f) const #endif { int i = (int)f; if (i < 0) i = 0; else if (i >= n - 2) i = n - 2; tMapper map(i, i+1, array[i], array[i+1]); return map(f); } tRndArray & tRndArray::operator = (const tRndArray &o) { if (this == &o) return *this; array = o.array; n = o.n; min = o.min; max = o.max; nul = o.nul; return *this; } tRndArray::tRndArray(const tRndArray &o) : array(o.array) { n = o.n; min = o.min; max = o.max; nul = o.nul; } int tRndArray::Random() { return Random(rnd.asDouble()); } int tRndArray::Random(double rndval) { double sum, dec; int i; assert(n > 0); sum = 0.0; for (i = 0; i < n; i++) { assert(array[i] >= 0); sum += array[i]; } if (sum <= 0) return 0; dec = sum * rndval * 0.99999; assert(dec < sum); i = 0; while (dec >= 0.0) { dec -= array[i]; i++; } i--; assert(i >= 0 && i < n); return i; } int tRndArray::Interval(int seed) { if (seed < 0) // initial ? seed = int(rnd.asDouble() * n); int delta = Random(); if (rnd.asDouble() < 0.5) delta = -delta; seed = (seed + n + delta) % n; return seed; } int tRndArray::Random(int i) { return rnd.asDouble() * (max - min) < array[i]; } void tRndArray::SetUnion(tRndArray &o, int fuzz) { for (int i = 0; i < n; i++) { int val = array[i]; if (o.array[i] > val) val = o.array[i]; array[i] = Fuzz(fuzz, array[i], val); } } void tRndArray::SetIntersection(tRndArray &o, int fuzz) { for (int i = 0; i < n; i++) { int val = array[i]; if (o.array[i] < val) val = o.array[i]; array[i] = Fuzz(fuzz, array[i], val); } } void tRndArray::SetDifference(tRndArray &o, int fuzz) { tRndArray tmp(o); tmp.SetInverse(tmp.Max()); SetIntersection(tmp, fuzz); } void tRndArray::SetInverse(int fuzz) { for (int i = 0; i < n; i++) array[i] = Fuzz(fuzz, array[i], min + max - array[i]); } int tRndArray::Fuzz(int fuz, int v1, int v2) const { // interpolate between v1 and v2 return (fuz - min) * v2 / (max - min) + (max - fuz) * v1 / (max - min); } void tRndArray::Clear() { for (int i = 0; i < n; i++) array[i] = min; } ostream & operator << (ostream &os, tRndArray const &a) { int i; os << a.n << " " << a.min << " " << a.max << endl; for (i = 0; i < a.n; i++) os << a.array[i] << " "; os << endl; return os; } istream & operator >> (istream &is, tRndArray &a) { int i; is >> a.n >> a.min >> a.max; for (i = 0; i < a.n; i++) is >> a.array[i]; return is; } // --------------------------------- tArrayEdit ------------------------------------- // length of tickmark line #define TICK_LINE 0 tArrayEdit::tArrayEdit(wxFrame *frame, tRndArray &ar, long xx, long yy, long ww, long hh, int sty) : wxCanvas(frame, xx, yy, ww, hh), array(ar), n(ar.n), min(ar.min), max(ar.max), nul(ar.nul) { draw_bars = 0; enabled = 1; dragging = 0; index = -1; label = 0; style_bits = sty; xmin = 0; xmax = n; x = 0; // draw to topleft corner of canvas y = 0; w = ww; h = hh; float tw, th; wxDC *dc = GetDC(); dc->SetFont(wxSMALL_FONT); dc->GetTextExtent("123", &tw, &th); if (style_bits & ARED_XTICKS) { // leave space for bottomline h -= (int)th; } if (style_bits & (ARED_MINMAX | ARED_YTICKS)) { // leave space to display min / max x = (int)(tw + TICK_LINE); w -= (int)(tw + TICK_LINE); } ynul = y + h - h * (nul - min) / (max - min); } void tArrayEdit::OnSize(int ww, int hh) { w = ww; h = hh; wxCanvas::OnSize(w, h); float tw, th; GetDC()->GetTextExtent("123", &tw, &th); if (style_bits & ARED_XTICKS) h -= (int)th; if (style_bits & (ARED_MINMAX | ARED_YTICKS)) { x = (int)(tw + TICK_LINE); w -= (int)(tw + TICK_LINE); } ynul = y + h - h * (nul - min) / (max - min); } tArrayEdit::~tArrayEdit() { delete [] label; } void tArrayEdit::DrawBar(int i, int Qt::black) { wxDC *dc = GetDC(); if (style_bits & ARED_LINES) { if (!Qt::black) dc->SetPen(wxWHITE_PEN); tMapper xmap(0, n, 0, w); tMapper ymap(min, max, h, 0); float x1 = (float)xmap(i + 0.5); float y1 = (float)ymap(array[i]); if (i > 0) { // draw line to prev position float x0 = (float)xmap(i - 0.5); float y0 = (float)ymap(array[i-1]); dc->DrawLine(x0, y0, x1, y1); } if (i < n-1) { // draw line to next position float x2 = (float)xmap(i + 1.5); float y2 = (float)ymap(array[i+1]); dc->DrawLine(x1, y1, x2, y2); } if (!Qt::black) dc->SetPen(wxBLACK_PEN); return; } int gap = 0; if (style_bits & ARED_GAP) { gap = w / n / 6; if (!gap && w / n > 3) gap = 1; } long xbar, ybar, wbar, hbar; wbar = w / n - 2 * gap; xbar = x + i * w / n + gap; hbar = h * (array[i] - nul) / (max - min); if (style_bits & ARED_BLOCKS) { /* ybar = ynul - hbar; if (hbar < 0) hbar = -hbar; hbar = (hbar < 2) ? hbar : 2; */ int hblk = 12; ybar = ynul - hbar - hblk/2; hbar = hblk; if (ybar < y) { int d = y - ybar; ybar += d; hbar -= d; } if (ybar + hbar > y + h) { int d = (ybar + hbar) - (y + h); hbar -= d; } if (hbar < 2) hbar = 2; } else if (hbar < 0) { ybar = ynul; hbar = -hbar; } else ybar = ynul - hbar; if (ybar == y) ++ybar, --hbar; if (!Qt::black) { dc->SetBrush(wxWHITE_BRUSH); dc->SetPen(wxWHITE_PEN); } if (wbar && hbar) dc->DrawRectangle(xbar, ybar, wbar, hbar); if (!Qt::black) { dc->SetBrush(wxBLACK_BRUSH); dc->SetPen(wxBLACK_PEN); } } const char *tArrayEdit::GetXText(int xval) { static char buf[8]; sprintf(buf, "%d", xval); return buf; } const char *tArrayEdit::GetYText(int yval) { static char buf[8]; sprintf(buf, "%d", yval); return buf; } void tArrayEdit::DrawXTicks() { float tw, th; if (!(style_bits & ARED_XTICKS)) return; wxDC *dc = GetDC(); dc->SetFont(wxSMALL_FONT); // compute tickmark x-distance dc->GetTextExtent("-123", &tw, &th); int max_labels = (int)(w / (tw + tw/2)); if (max_labels > 0) { int step = (xmax - xmin + 1) / max_labels; if (step <= 0) step = 1; for (int val = xmin; val <= xmax; val += step) { const char *buf = GetXText(val); //sprintf(buf, "%d", val); dc->GetTextExtent((char *)buf, &tw, &th); float yy = y + h; float xx = x + w * (val - xmin) / (xmax - xmin + 1); xx -= tw/2; // center text xx += 0.5 * w / n; // middle of bar dc->DrawText(buf, xx, yy); //dc->DrawLine(x - TICK_LINE, yy, x, yy); } } dc->SetFont(wxNORMAL_FONT); } void tArrayEdit::DrawYTicks() { wxDC *dc = GetDC(); dc->SetFont(wxSMALL_FONT); if (style_bits & ARED_YTICKS) { // compute tickmark y-distance float tw, th; dc->GetTextExtent("-123", &tw, &th); int max_labels = (int)(h / (th + th/2)); if (max_labels > 0) { int step = (max - min) / max_labels; if (step <= 0) step = 1; for (int val = min; val < max; val += step) { const char *buf = GetYText(val); //sprintf(buf, "%d", val); dc->GetTextExtent((char *)buf, &tw, &th); float yy = y + h - h * (val - min) / (max - min) - th/2; dc->DrawText(buf, x - tw - TICK_LINE, yy); //dc->DrawLine(x - TICK_LINE, yy, x, yy); } } } else if (style_bits & ARED_MINMAX) { // min/max float tw, th; char buf[20]; sprintf(buf, "%d", max); dc->GetTextExtent(buf, &tw, &th); dc->DrawText(buf, x - tw, y); sprintf(buf, "%d", min); dc->GetTextExtent(buf, &tw, &th); dc->DrawText(buf, x - tw, y + h - th); } dc->SetFont(wxNORMAL_FONT); } void tArrayEdit::DrawLabel() { wxDC *dc = GetDC(); dc->SetFont(wxSMALL_FONT); if (label) dc->DrawText(label, x + 5, y + 2); dc->SetFont(wxNORMAL_FONT); } void tArrayEdit::OnPaint() { int i; wxDC *dc = GetDC(); // surrounding rectangle dc->Clear(); if (enabled) dc->SetBrush(wxWHITE_BRUSH); else dc->SetBrush(wxGREY_BRUSH); dc->SetPen(wxBLACK_PEN); if (w && h) dc->DrawRectangle(x, y, w, h); // sliders dc->SetBrush(wxBLACK_BRUSH); for (i = 0; i < n; i++) DrawBar(i, 1); DrawXTicks(); DrawLabel(); DrawYTicks(); DrawNull(); if (draw_bars) draw_bars->DrawBars(); } void tArrayEdit::DrawNull() { wxDC *dc = GetDC(); dc->SetPen(wxCYAN_PEN); // draw y-null line if (min < nul && nul < max) dc->DrawLine(x, ynul, x+w, ynul); // draw x-null line if (xmin < 0 && 0 < xmax) { float x0 = w * (0 - xmin) / (xmax - xmin); dc->DrawLine(x0, y, x0, y + h); } dc->SetPen(wxBLACK_PEN); } void tArrayEdit::SetXMinMax(int xmi, int xma) { xmin = xmi; xmax = xma; } int tArrayEdit::Index(wxMouseEvent &e) { float ex, ey; e.Position(&ex, &ey); int i = (int)( ((short)ex - x) * n / w); i = i < 0 ? 0 : i; i = i >= n ? n-1 : i; return i; } int tArrayEdit::Dragging(wxMouseEvent &e) { if (!dragging) return 0; if (index < 0) index = Index(e); int val = nul; if (e.LeftIsDown()) { float ex, ey; e.Position(&ex, &ey); // $blk$ val = (int)( (y + h - (short)ey) * (max - min) / h + min); val = (int)( (double)(y + h - ey) * (max - min) / h + min + 0.5); val = val > max ? max : val; val = val < min ? min : val; } #if 0 { // in msw ex,ey are 65536 for negative values! wxDC *dc = GetDC(); char buf[500]; sprintf(buf, "x %4.0f, y %4.0f, sh %d", ex, ey, e.ShiftDown()); dc->DrawText(buf, 50, 50); } #endif if (e.ShiftDown()) { int k; for (k = 0; k < n; k++) { DrawBar(k, 0); array[k] = val; DrawBar(k, 1); } } else if (e.ControlDown()) { DrawBar(index, 0); array[index] = val; DrawBar(index, 1); } else { int i = Index(e); int k = i; if (i < index) for (; i <= index; i++) { DrawBar(i, 0); array[i] = val; DrawBar(i, 1); } else for (; i >= index; i--) { DrawBar(i, 0); array[i] = val; DrawBar(i, 1); } index = k; } return 0; } int tArrayEdit::ButtonDown(wxMouseEvent &e) { #ifdef wx_msw CaptureMouse(); #endif dragging = 1; index = Index(e); Dragging(e); return 0; } int tArrayEdit::ButtonUp(wxMouseEvent &e) { #ifdef wx_msw ReleaseMouse(); #endif dragging = 0; index = -1; DrawLabel(); DrawNull(); return 0; } void tArrayEdit::OnEvent(wxMouseEvent &e) { if (!enabled) return; if (e.ButtonDown()) ButtonDown(e); else if (e.Dragging()) Dragging(e); else if (e.ButtonUp()) ButtonUp(e); } void tArrayEdit::Enable(int e) { enabled = e; } void tArrayEdit::SetLabel(char const *llabel) { delete label; label = copystring(llabel); } void tArrayEdit::SetYMinMax(int mi, int ma) { array.SetMinMax(mi, ma); ynul = y + h - h * (nul - min) / (max - min); } void tArrayEdit::DrawBarLine (long xx) { wxDC *dc = GetDC (); // fprintf(stderr,"x: %ld, xx: %ld\n",x,xx); if (xx > x && xx + 1 < x + w) { dc->SetPen (wxLIGHT_GREY_PEN); dc->DrawLine (xx, y + 1, xx, y + h - 2); dc->SetPen (wxBLACK_PEN); } } tRhyArrayEdit::tRhyArrayEdit(wxFrame *parent, tRndArray &array, long xx, long yy, long ww, long hh, int sty) : tArrayEdit(parent, array, xx, yy, ww, hh, sty) { steps_per_count = 4; count_per_bar = 4; n_bars = 4; } void tRhyArrayEdit::SetMeter(int s, int c, int b) { steps_per_count = s; count_per_bar = c; n_bars = b; array.Resize(s * c * b); SetXMinMax(1, s * c * b); } void tRhyArrayEdit::DrawXTicks() { if (!(style_bits & ARED_RHYTHM)) { tArrayEdit::DrawXTicks(); return; } char buf[20]; float tw, th; wxDC *dc = GetDC(); dc->SetFont(wxSMALL_FONT); // tick marks assert(steps_per_count && count_per_bar && n_bars); int i; for (i = 0; i < n; i += steps_per_count) { int mark = (i / steps_per_count) % count_per_bar + 1; sprintf(buf, "%d", mark); float yy = y + h; float xx = x + (i + 0.5) * w / n; dc->GetTextExtent(buf, &tw, &th); xx -= tw/2.0; dc->DrawText(buf, xx, yy); } dc->SetFont(wxNORMAL_FONT); } #endif