Polygon Sound_to_Polygon (Sound me, int channel, double tmin, double tmax, double ymin, double ymax, double level) { try { bool clip = ymin < ymax; if (channel < 1 || channel > my ny) { Melder_throw ("Channel does not exist."); } if (tmin >= tmax) { tmin = my xmin; tmax = my xmax; } if (tmin < my xmin) { tmin = my xmin; } if (tmax > my xmax) { tmax = my xmax; } if (tmin >= my xmax || tmax < my xmin) { Melder_throw ("Invalid domain."); } long k = 1, i1 = Sampled_xToHighIndex (me, tmin); long i2 = Sampled_xToLowIndex (me, tmax); long numberOfPoints = i2 - i1 + 1 + 2 + 2; // begin + endpoint + level autoPolygon him = Polygon_create (numberOfPoints); /* In Vector_getValueAtX the interpolation only returns defined values between the left and right edges that are calculated as left = x1 - 0.5 * dx; right = left + my nx * dx. Given a sound, for example on the domain [0,...], the value of 'left' with the above formula might not return exactly xmin but instead a very small deviation (due to the imprecise representation of real numbers in a computer). Querying for the value at xmin which is outside the interpolation domain then produces an 'undefined'. We try to avoid this with the following workaround. */ double xmin = my x1 - 0.5 * my dx; double xmax = xmin + my nx * my dx; tmin = tmin < xmin ? xmin : tmin; tmax = tmax > xmax ? xmax : tmax; // End of workaround his x[k] = tmin; his y[k++] = CLIP_Y (level, ymin, ymax); his x[k] = tmin; double y = Vector_getValueAtX (me, tmin, channel, Vector_VALUE_INTERPOLATION_LINEAR); his y[k++] = CLIP_Y (y, ymin, ymax); for (long i = i1; i <= i2; i++) { y = my z[channel][i]; his x[k] = my x1 + (i - 1) * my dx; his y[k++] = CLIP_Y (y, ymin, ymax); } his x[k] = tmax; y = Vector_getValueAtX (me, tmax, channel, Vector_VALUE_INTERPOLATION_LINEAR); his y[k++] = CLIP_Y (y, ymin, ymax); his x[k] = tmax; his y[k++] = CLIP_Y (level, ymin, ymax); return him.transfer(); } catch (MelderError) { Melder_throw (me, ":no Polygon created."); } }
autoAmplitudeTier PointProcess_Sound_to_AmplitudeTier_point (PointProcess me, Sound thee) { try { long imin, imax, numberOfPeaks = PointProcess_getWindowPoints (me, my xmin, my xmax, & imin, & imax); if (numberOfPeaks < 3) return nullptr; autoAmplitudeTier him = AmplitudeTier_create (my xmin, my xmax); for (long i = imin; i <= imax; i ++) { double value = Vector_getValueAtX (thee, my t [i], Vector_CHANNEL_AVERAGE, Vector_VALUE_INTERPOLATION_SINC700); if (NUMdefined (value)) RealTier_addPoint (him.peek(), my t [i], value); } return him; } catch (MelderError) { Melder_throw (me, U" & ", thee, U": not converted to AmplitudeTier."); } }
void Vector_getMaximumAndX (Vector me, double xmin, double xmax, long channel, int interpolation, double *return_maximum, double *return_xOfMaximum) { long imin, imax, i, n = my nx; Melder_assert (channel >= 1 && channel <= my ny); double *y = my z [channel]; double maximum, x; if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; } if (! Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax)) { /* * No samples between xmin and xmax. * Try to return the greater of the values at these two points. */ double yleft = Vector_getValueAtX (me, xmin, channel, interpolation > Vector_VALUE_INTERPOLATION_NEAREST ? Vector_VALUE_INTERPOLATION_LINEAR : Vector_VALUE_INTERPOLATION_NEAREST); double yright = Vector_getValueAtX (me, xmax, channel, interpolation > Vector_VALUE_INTERPOLATION_NEAREST ? Vector_VALUE_INTERPOLATION_LINEAR : Vector_VALUE_INTERPOLATION_NEAREST); maximum = yleft > yright ? yleft : yright; x = yleft == yright ? (xmin + xmax) / 2 : yleft > yright ? xmin : xmax; } else { maximum = y [imin], x = imin; if (y [imax] > maximum) maximum = y [imax], x = imax; if (imin == 1) imin ++; if (imax == my nx) imax --; for (i = imin; i <= imax; i ++) { if (y [i] > y [i - 1] && y [i] >= y [i + 1]) { double i_real, localMaximum = NUMimproveMaximum (y, n, i, interpolation, & i_real); if (localMaximum > maximum) maximum = localMaximum, x = i_real; } } x = my x1 + (x - 1) * my dx; /* Convert sample to x. */ if (x < xmin) x = xmin; else if (x > xmax) x = xmax; } if (return_maximum) *return_maximum = maximum; if (return_xOfMaximum) *return_xOfMaximum = x; }
Polygon Sounds_to_Polygon_enclosed (Sound me, Sound thee, int channel, double tmin, double tmax, double ymin, double ymax) { try { bool clip = ymin < ymax; if (my ny > 1 && thy ny > 1 && my ny != thy ny) { Melder_throw ("The numbers of channels of the two sounds have to be equal or 1."); } long numberOfChannels = my ny > thy ny ? my ny : thy ny; if (channel < 1 || channel > numberOfChannels) { Melder_throw ("Channel does not exist."); } // find overlap in the domains with xmin workaround as in Sound_to_Polygon double xmin1 = my x1 - 0.5 * my dx, xmin2 = thy x1 - 0.5 * thy dx ; double xmin = my xmin > thy xmin ? xmin1 : xmin2; double xmax = my xmax < thy xmax ? xmin1 + my nx * my dx : xmin2 + thy nx * thy dx; if (xmax <= xmin) { Melder_throw ("Domains must overlap."); } if (tmin >= tmax) { tmin = xmin; tmax = xmax; } if (tmin < xmin) { tmin = xmin; } if (tmax > xmax) { tmax = xmax; } if (tmin >= xmax || tmax < xmin) { Melder_throw ("Invalid domain."); } long k = 1; long ib1 = Sampled_xToHighIndex (me, tmin); long ie1 = Sampled_xToLowIndex (me, tmax); long n1 = ie1 - ib1 + 1; long ib2 = Sampled_xToHighIndex (thee, tmin); long ie2 = Sampled_xToLowIndex (thee, tmax); long n2 = ie2 - ib2 + 1; long numberOfPoints = n1 + n2 + 4; // me + thee + begin + endpoint + closing autoPolygon him = Polygon_create (numberOfPoints); // my starting point at tmin double y = Vector_getValueAtX (me, tmin, (my ny == 1 ? 1 : channel), Vector_VALUE_INTERPOLATION_LINEAR); his x[k] = tmin; his y[k++] = CLIP_Y (y, ymin, ymax); // my samples for (long i = ib1; i <= ie1; i++) { double t = my x1 + (i - 1) * my dx; y = my z[my ny == 1 ? 1 : channel][i]; his x[k] = t; his y[k++] = CLIP_Y (y, ymin, ymax); } // my end point at tmax y = Vector_getValueAtX (me, tmax, (my ny == 1 ? 1 : channel), Vector_VALUE_INTERPOLATION_LINEAR); his x[k] = tmax; his y[k++] = y; // thy starting point at tmax y = Vector_getValueAtX (thee, tmax, (thy ny == 1 ? 1 : channel), Vector_VALUE_INTERPOLATION_LINEAR); his x[k] = tmax; his y[k++] = y; // thy samples for (long i = ie2; i >= ib2; i--) { double t = thy x1 + (i - 1) * thy dx; y = thy z[thy ny == 1 ? 1 : channel][i]; his x[k] = t; his y[k++] = CLIP_Y (y, ymin, ymax); } // thy end point at tmin y = Vector_getValueAtX (thee, tmin, (thy ny == 1 ? 1 : channel), Vector_VALUE_INTERPOLATION_LINEAR); his x[k] = tmin; his y[k] = y; Melder_assert (k == numberOfPoints); return him.transfer(); } catch (MelderError) { Melder_throw (me, ": no enclosed Polygon created."); } }
void TimeSoundEditor_drawSound (TimeSoundEditor me, double globalMinimum, double globalMaximum) { Sound sound = my d_sound.data; LongSound longSound = my d_longSound.data; Melder_assert (!! sound != !! longSound); int nchan = sound ? sound -> ny : longSound -> numberOfChannels; bool cursorVisible = my d_startSelection == my d_endSelection && my d_startSelection >= my d_startWindow && my d_startSelection <= my d_endWindow; Graphics_setColour (my d_graphics, Graphics_BLACK); bool fits; try { fits = sound ? true : LongSound_haveWindow (longSound, my d_startWindow, my d_endWindow); } catch (MelderError) { bool outOfMemory = !! str32str (Melder_getError (), U"memory"); if (Melder_debug == 9) Melder_flushError (); else Melder_clearError (); Graphics_setWindow (my d_graphics, 0.0, 1.0, 0.0, 1.0); Graphics_setTextAlignment (my d_graphics, Graphics_CENTRE, Graphics_HALF); Graphics_text (my d_graphics, 0.5, 0.5, outOfMemory ? U"(out of memory)" : U"(cannot read sound file)"); return; } if (! fits) { Graphics_setWindow (my d_graphics, 0.0, 1.0, 0.0, 1.0); Graphics_setTextAlignment (my d_graphics, Graphics_CENTRE, Graphics_HALF); Graphics_text (my d_graphics, 0.5, 0.5, U"(window too large; zoom in to see the data)"); return; } long first, last; if (Sampled_getWindowSamples (sound ? (Sampled) sound : (Sampled) longSound, my d_startWindow, my d_endWindow, & first, & last) <= 1) { Graphics_setWindow (my d_graphics, 0.0, 1.0, 0.0, 1.0); Graphics_setTextAlignment (my d_graphics, Graphics_CENTRE, Graphics_HALF); Graphics_text (my d_graphics, 0.5, 0.5, U"(zoom out to see the data)"); return; } const int numberOfVisibleChannels = nchan > 8 ? 8 : nchan; const int firstVisibleChannel = my d_sound.channelOffset + 1; int lastVisibleChannel = my d_sound.channelOffset + numberOfVisibleChannels; if (lastVisibleChannel > nchan) lastVisibleChannel = nchan; double maximumExtent = 0.0, visibleMinimum = 0.0, visibleMaximum = 0.0; if (my p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy_BY_WINDOW) { if (longSound) LongSound_getWindowExtrema (longSound, my d_startWindow, my d_endWindow, firstVisibleChannel, & visibleMinimum, & visibleMaximum); else Matrix_getWindowExtrema (sound, first, last, firstVisibleChannel, firstVisibleChannel, & visibleMinimum, & visibleMaximum); for (int ichan = firstVisibleChannel + 1; ichan <= lastVisibleChannel; ichan ++) { double visibleChannelMinimum, visibleChannelMaximum; if (longSound) LongSound_getWindowExtrema (longSound, my d_startWindow, my d_endWindow, ichan, & visibleChannelMinimum, & visibleChannelMaximum); else Matrix_getWindowExtrema (sound, first, last, ichan, ichan, & visibleChannelMinimum, & visibleChannelMaximum); if (visibleChannelMinimum < visibleMinimum) visibleMinimum = visibleChannelMinimum; if (visibleChannelMaximum > visibleMaximum) visibleMaximum = visibleChannelMaximum; } maximumExtent = visibleMaximum - visibleMinimum; } for (int ichan = firstVisibleChannel; ichan <= lastVisibleChannel; ichan ++) { double cursorFunctionValue = longSound ? 0.0 : Vector_getValueAtX (sound, 0.5 * (my d_startSelection + my d_endSelection), ichan, 70); /* * BUG: this will only work for mono or stereo, until Graphics_function16 handles quadro. */ double ymin = (double) (numberOfVisibleChannels - ichan + my d_sound.channelOffset) / numberOfVisibleChannels; double ymax = (double) (numberOfVisibleChannels + 1 - ichan + my d_sound.channelOffset) / numberOfVisibleChannels; Graphics_Viewport vp = Graphics_insetViewport (my d_graphics, 0, 1, ymin, ymax); bool horizontal = false; double minimum = sound ? globalMinimum : -1.0, maximum = sound ? globalMaximum : 1.0; if (my p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy_BY_WINDOW) { if (nchan > 2) { if (longSound) { LongSound_getWindowExtrema (longSound, my d_startWindow, my d_endWindow, ichan, & minimum, & maximum); } else { Matrix_getWindowExtrema (sound, first, last, ichan, ichan, & minimum, & maximum); } if (maximumExtent > 0.0) { double middle = 0.5 * (minimum + maximum); minimum = middle - 0.5 * maximumExtent; maximum = middle + 0.5 * maximumExtent; } } else { minimum = visibleMinimum; maximum = visibleMaximum; } } else if (my p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy_BY_WINDOW_AND_CHANNEL) { if (longSound) { LongSound_getWindowExtrema (longSound, my d_startWindow, my d_endWindow, ichan, & minimum, & maximum); } else { Matrix_getWindowExtrema (sound, first, last, ichan, ichan, & minimum, & maximum); } } else if (my p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy_FIXED_HEIGHT) { if (longSound) { LongSound_getWindowExtrema (longSound, my d_startWindow, my d_endWindow, ichan, & minimum, & maximum); } else { Matrix_getWindowExtrema (sound, first, last, ichan, ichan, & minimum, & maximum); } double channelExtent = my p_sound_scaling_height; double middle = 0.5 * (minimum + maximum); minimum = middle - 0.5 * channelExtent; maximum = middle + 0.5 * channelExtent; } else if (my p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy_FIXED_RANGE) { minimum = my p_sound_scaling_minimum; maximum = my p_sound_scaling_maximum; } if (minimum == maximum) { horizontal = true; minimum -= 1.0; maximum += 1.0;} Graphics_setWindow (my d_graphics, my d_startWindow, my d_endWindow, minimum, maximum); if (horizontal) { Graphics_setTextAlignment (my d_graphics, Graphics_RIGHT, Graphics_HALF); double mid = 0.5 * (minimum + maximum); Graphics_text (my d_graphics, my d_startWindow, mid, Melder_float (Melder_half (mid))); } else { if (! cursorVisible || ! NUMdefined (cursorFunctionValue) || Graphics_dyWCtoMM (my d_graphics, cursorFunctionValue - minimum) > 5.0) { Graphics_setTextAlignment (my d_graphics, Graphics_RIGHT, Graphics_BOTTOM); Graphics_text (my d_graphics, my d_startWindow, minimum, Melder_float (Melder_half (minimum))); } if (! cursorVisible || ! NUMdefined (cursorFunctionValue) || Graphics_dyWCtoMM (my d_graphics, maximum - cursorFunctionValue) > 5.0) { Graphics_setTextAlignment (my d_graphics, Graphics_RIGHT, Graphics_TOP); Graphics_text (my d_graphics, my d_startWindow, maximum, Melder_float (Melder_half (maximum))); } } if (minimum < 0 && maximum > 0 && ! horizontal) { Graphics_setWindow (my d_graphics, 0, 1, minimum, maximum); if (! cursorVisible || ! NUMdefined (cursorFunctionValue) || fabs (Graphics_dyWCtoMM (my d_graphics, cursorFunctionValue - 0.0)) > 3.0) { Graphics_setTextAlignment (my d_graphics, Graphics_RIGHT, Graphics_HALF); Graphics_text (my d_graphics, 0, 0, U"0"); } Graphics_setColour (my d_graphics, Graphics_CYAN); Graphics_setLineType (my d_graphics, Graphics_DOTTED); Graphics_line (my d_graphics, 0, 0, 1, 0); Graphics_setLineType (my d_graphics, Graphics_DRAWN); } /* * Garnish the drawing area of each channel. */ Graphics_setWindow (my d_graphics, 0, 1, 0, 1); Graphics_setColour (my d_graphics, Graphics_CYAN); Graphics_innerRectangle (my d_graphics, 0, 1, 0, 1); Graphics_setColour (my d_graphics, Graphics_BLACK); if (nchan > 1) { Graphics_setTextAlignment (my d_graphics, Graphics_LEFT, Graphics_HALF); const char32 *channelName = my v_getChannelName (ichan); static MelderString channelLabel; MelderString_copy (& channelLabel, ( channelName ? U"ch" : U"Channel " ), ichan); if (channelName) MelderString_append (& channelLabel, U": ", channelName); if (ichan > 8 && ichan - my d_sound.channelOffset == 1) { MelderString_append (& channelLabel, U" " UNITEXT_UPWARDS_ARROW); } else if (ichan >= 8 && ichan - my d_sound.channelOffset == 8 && ichan < nchan) { MelderString_append (& channelLabel, U" " UNITEXT_DOWNWARDS_ARROW); } Graphics_text (my d_graphics, 1, 0.5, channelLabel.string); } /* * Draw a very thin separator line underneath. */ if (ichan < nchan) { /*Graphics_setColour (d_graphics, Graphics_BLACK);*/ Graphics_line (my d_graphics, 0, 0, 1, 0); } /* * Draw the samples. */ /*if (ichan == 1) FunctionEditor_SoundAnalysis_drawPulses (this);*/ if (sound) { Graphics_setWindow (my d_graphics, my d_startWindow, my d_endWindow, minimum, maximum); if (cursorVisible && NUMdefined (cursorFunctionValue)) FunctionEditor_drawCursorFunctionValue (me, cursorFunctionValue, Melder_float (Melder_half (cursorFunctionValue)), U""); Graphics_setColour (my d_graphics, Graphics_BLACK); Graphics_function (my d_graphics, sound -> z [ichan], first, last, Sampled_indexToX (sound, first), Sampled_indexToX (sound, last)); } else { Graphics_setWindow (my d_graphics, my d_startWindow, my d_endWindow, minimum * 32768, maximum * 32768); Graphics_function16 (my d_graphics, longSound -> buffer - longSound -> imin * nchan + (ichan - 1), nchan - 1, first, last, Sampled_indexToX (longSound, first), Sampled_indexToX (longSound, last)); } Graphics_resetViewport (my d_graphics, vp); } Graphics_setWindow (my d_graphics, 0.0, 1.0, 0.0, 1.0); Graphics_rectangle (my d_graphics, 0.0, 1.0, 0.0, 1.0); }