@@ -22,6 +22,7 @@ lv2: libs | |||
ifeq ($(LINUX_EMBED),true) | |||
$(MAKE) -C arctican-function/LV2 | |||
$(MAKE) -C arctican-pilgrim/LV2 | |||
$(MAKE) -C camomile/LV2 | |||
$(MAKE) -C drowaudio-distortion/LV2 | |||
$(MAKE) -C drowaudio-distortionshaper/LV2 | |||
$(MAKE) -C drowaudio-flanger/LV2 | |||
@@ -121,6 +122,7 @@ clean: | |||
# LV2 | |||
$(MAKE) clean -C arctican-function/LV2 | |||
$(MAKE) clean -C arctican-pilgrim/LV2 | |||
$(MAKE) clean -C camomile/LV2 | |||
$(MAKE) clean -C dexed/LV2 | |||
$(MAKE) clean -C drowaudio-distortion/LV2 | |||
$(MAKE) clean -C drowaudio-distortionshaper/LV2 | |||
@@ -156,6 +158,7 @@ clean: | |||
# VST | |||
$(MAKE) clean -C arctican-function/VST | |||
$(MAKE) clean -C arctican-pilgrim/VST | |||
$(MAKE) clean -C camomile/VST | |||
$(MAKE) clean -C dexed/VST | |||
$(MAKE) clean -C drowaudio-distortion/VST | |||
$(MAKE) clean -C drowaudio-distortionshaper/VST | |||
@@ -0,0 +1,190 @@ | |||
dofile("../../../scripts/make-project.lua") | |||
package = make_juce_lv2_project("Camomile") | |||
package.defines = { package.defines, "PD=1", "USEAPI_DUMMY=1", "PD_INTERNAL=1", "PDINSTANCE=1", "PDTHREADS=1", "HAVE_LIBDL=1", "HAVE_UNISTD_H=1" } | |||
package.includepaths = { | |||
package.includepaths, | |||
"../source/LibPd/pure-data/src", | |||
"../source/LibPd/libpd_wrapper" | |||
} | |||
if (os.getenv("LINUX_EMBED")) then | |||
package.files = { | |||
matchfiles ( | |||
"../source/BinaryData.cpp", | |||
"../source/PluginEnvironment.cpp", | |||
"../source/PluginFileWatcher.cpp", | |||
"../source/PluginParameter.cpp", | |||
"../source/PluginParser.cpp", | |||
"../source/PluginProcessor.cpp", | |||
"../source/PluginProcessorBuses.cpp", | |||
"../source/PluginProcessorReceive.cpp", | |||
"../source/Pd/*.c", | |||
"../source/Pd/*.cpp", | |||
"../source/LibPd/pure-data/src/d_arithmetic.c", | |||
"../source/LibPd/pure-data/src/d_array.c", | |||
"../source/LibPd/pure-data/src/d_ctl.c", | |||
"../source/LibPd/pure-data/src/d_dac.c", | |||
"../source/LibPd/pure-data/src/d_delay.c", | |||
"../source/LibPd/pure-data/src/d_fft.c", | |||
"../source/LibPd/pure-data/src/d_fft_fftsg.c", | |||
"../source/LibPd/pure-data/src/d_filter.c", | |||
"../source/LibPd/pure-data/src/d_global.c", | |||
"../source/LibPd/pure-data/src/d_math.c", | |||
"../source/LibPd/pure-data/src/d_misc.c", | |||
"../source/LibPd/pure-data/src/d_osc.c", | |||
"../source/LibPd/pure-data/src/d_resample.c", | |||
"../source/LibPd/pure-data/src/d_soundfile.c", | |||
"../source/LibPd/pure-data/src/d_ugen.c", | |||
"../source/LibPd/pure-data/src/g_all_guis.c", | |||
"../source/LibPd/pure-data/src/g_array.c", | |||
"../source/LibPd/pure-data/src/g_bang.c", | |||
"../source/LibPd/pure-data/src/g_canvas.c", | |||
"../source/LibPd/pure-data/src/g_clone.c", | |||
"../source/LibPd/pure-data/src/g_editor.c", | |||
"../source/LibPd/pure-data/src/g_graph.c", | |||
"../source/LibPd/pure-data/src/g_guiconnect.c", | |||
"../source/LibPd/pure-data/src/g_hdial.c", | |||
"../source/LibPd/pure-data/src/g_hslider.c", | |||
"../source/LibPd/pure-data/src/g_io.c", | |||
"../source/LibPd/pure-data/src/g_mycanvas.c", | |||
"../source/LibPd/pure-data/src/g_numbox.c", | |||
"../source/LibPd/pure-data/src/g_readwrite.c", | |||
"../source/LibPd/pure-data/src/g_rtext.c", | |||
"../source/LibPd/pure-data/src/g_scalar.c", | |||
"../source/LibPd/pure-data/src/g_template.c", | |||
"../source/LibPd/pure-data/src/g_text.c", | |||
"../source/LibPd/pure-data/src/g_toggle.c", | |||
"../source/LibPd/pure-data/src/g_traversal.c", | |||
"../source/LibPd/pure-data/src/g_vdial.c", | |||
"../source/LibPd/pure-data/src/g_vslider.c", | |||
"../source/LibPd/pure-data/src/g_vumeter.c", | |||
"../source/LibPd/pure-data/src/m_atom.c", | |||
"../source/LibPd/pure-data/src/m_binbuf.c", | |||
"../source/LibPd/pure-data/src/m_class.c", | |||
"../source/LibPd/pure-data/src/m_conf.c", | |||
"../source/LibPd/pure-data/src/m_glob.c", | |||
"../source/LibPd/pure-data/src/m_memory.c", | |||
"../source/LibPd/pure-data/src/m_obj.c", | |||
"../source/LibPd/pure-data/src/m_pd.c", | |||
"../source/LibPd/pure-data/src/m_sched.c", | |||
"../source/LibPd/pure-data/src/s_audio.c", | |||
"../source/LibPd/pure-data/src/s_audio_dummy.c", | |||
"../source/LibPd/pure-data/src/s_inter.c", | |||
"../source/LibPd/pure-data/src/s_loader.c", | |||
"../source/LibPd/pure-data/src/s_main.c", | |||
"../source/LibPd/pure-data/src/s_path.c", | |||
"../source/LibPd/pure-data/src/s_print.c", | |||
"../source/LibPd/pure-data/src/s_utf8.c", | |||
"../source/LibPd/pure-data/src/x_acoustics.c", | |||
"../source/LibPd/pure-data/src/x_arithmetic.c", | |||
"../source/LibPd/pure-data/src/x_array.c", | |||
"../source/LibPd/pure-data/src/x_connective.c", | |||
"../source/LibPd/pure-data/src/x_gui.c", | |||
"../source/LibPd/pure-data/src/x_interface.c", | |||
"../source/LibPd/pure-data/src/x_list.c", | |||
"../source/LibPd/pure-data/src/x_midi.c", | |||
"../source/LibPd/pure-data/src/x_misc.c", | |||
"../source/LibPd/pure-data/src/x_net.c", | |||
"../source/LibPd/pure-data/src/x_scalar.c", | |||
"../source/LibPd/pure-data/src/x_text.c", | |||
"../source/LibPd/pure-data/src/x_time.c", | |||
"../source/LibPd/pure-data/src/x_vexp.c", | |||
"../source/LibPd/pure-data/src/x_vexp_fun.c", | |||
"../source/LibPd/pure-data/src/x_vexp_if.c", | |||
"../source/LibPd/libpd_wrapper/s_libpdmidi.c", | |||
"../source/LibPd/libpd_wrapper/x_libpdreceive.c", | |||
"../source/LibPd/libpd_wrapper/z_hooks.c", | |||
"../source/LibPd/libpd_wrapper/z_libpd.c", | |||
"../../../libs/juce-plugin/JucePluginMain.cpp" | |||
) | |||
} | |||
else | |||
package.files = { | |||
matchfiles ( | |||
"../source/*.cpp", | |||
"../source/Pd/*.c", | |||
"../source/Pd/*.cpp", | |||
"../source/LibPd/pure-data/src/d_arithmetic.c", | |||
"../source/LibPd/pure-data/src/d_array.c", | |||
"../source/LibPd/pure-data/src/d_ctl.c", | |||
"../source/LibPd/pure-data/src/d_dac.c", | |||
"../source/LibPd/pure-data/src/d_delay.c", | |||
"../source/LibPd/pure-data/src/d_fft.c", | |||
"../source/LibPd/pure-data/src/d_fft_fftsg.c", | |||
"../source/LibPd/pure-data/src/d_filter.c", | |||
"../source/LibPd/pure-data/src/d_global.c", | |||
"../source/LibPd/pure-data/src/d_math.c", | |||
"../source/LibPd/pure-data/src/d_misc.c", | |||
"../source/LibPd/pure-data/src/d_osc.c", | |||
"../source/LibPd/pure-data/src/d_resample.c", | |||
"../source/LibPd/pure-data/src/d_soundfile.c", | |||
"../source/LibPd/pure-data/src/d_ugen.c", | |||
"../source/LibPd/pure-data/src/g_all_guis.c", | |||
"../source/LibPd/pure-data/src/g_array.c", | |||
"../source/LibPd/pure-data/src/g_bang.c", | |||
"../source/LibPd/pure-data/src/g_canvas.c", | |||
"../source/LibPd/pure-data/src/g_clone.c", | |||
"../source/LibPd/pure-data/src/g_editor.c", | |||
"../source/LibPd/pure-data/src/g_graph.c", | |||
"../source/LibPd/pure-data/src/g_guiconnect.c", | |||
"../source/LibPd/pure-data/src/g_hdial.c", | |||
"../source/LibPd/pure-data/src/g_hslider.c", | |||
"../source/LibPd/pure-data/src/g_io.c", | |||
"../source/LibPd/pure-data/src/g_mycanvas.c", | |||
"../source/LibPd/pure-data/src/g_numbox.c", | |||
"../source/LibPd/pure-data/src/g_readwrite.c", | |||
"../source/LibPd/pure-data/src/g_rtext.c", | |||
"../source/LibPd/pure-data/src/g_scalar.c", | |||
"../source/LibPd/pure-data/src/g_template.c", | |||
"../source/LibPd/pure-data/src/g_text.c", | |||
"../source/LibPd/pure-data/src/g_toggle.c", | |||
"../source/LibPd/pure-data/src/g_traversal.c", | |||
"../source/LibPd/pure-data/src/g_vdial.c", | |||
"../source/LibPd/pure-data/src/g_vslider.c", | |||
"../source/LibPd/pure-data/src/g_vumeter.c", | |||
"../source/LibPd/pure-data/src/m_atom.c", | |||
"../source/LibPd/pure-data/src/m_binbuf.c", | |||
"../source/LibPd/pure-data/src/m_class.c", | |||
"../source/LibPd/pure-data/src/m_conf.c", | |||
"../source/LibPd/pure-data/src/m_glob.c", | |||
"../source/LibPd/pure-data/src/m_memory.c", | |||
"../source/LibPd/pure-data/src/m_obj.c", | |||
"../source/LibPd/pure-data/src/m_pd.c", | |||
"../source/LibPd/pure-data/src/m_sched.c", | |||
"../source/LibPd/pure-data/src/s_audio.c", | |||
"../source/LibPd/pure-data/src/s_audio_dummy.c", | |||
"../source/LibPd/pure-data/src/s_inter.c", | |||
"../source/LibPd/pure-data/src/s_loader.c", | |||
"../source/LibPd/pure-data/src/s_main.c", | |||
"../source/LibPd/pure-data/src/s_path.c", | |||
"../source/LibPd/pure-data/src/s_print.c", | |||
"../source/LibPd/pure-data/src/s_utf8.c", | |||
"../source/LibPd/pure-data/src/x_acoustics.c", | |||
"../source/LibPd/pure-data/src/x_arithmetic.c", | |||
"../source/LibPd/pure-data/src/x_array.c", | |||
"../source/LibPd/pure-data/src/x_connective.c", | |||
"../source/LibPd/pure-data/src/x_gui.c", | |||
"../source/LibPd/pure-data/src/x_interface.c", | |||
"../source/LibPd/pure-data/src/x_list.c", | |||
"../source/LibPd/pure-data/src/x_midi.c", | |||
"../source/LibPd/pure-data/src/x_misc.c", | |||
"../source/LibPd/pure-data/src/x_net.c", | |||
"../source/LibPd/pure-data/src/x_scalar.c", | |||
"../source/LibPd/pure-data/src/x_text.c", | |||
"../source/LibPd/pure-data/src/x_time.c", | |||
"../source/LibPd/pure-data/src/x_vexp.c", | |||
"../source/LibPd/pure-data/src/x_vexp_fun.c", | |||
"../source/LibPd/pure-data/src/x_vexp_if.c", | |||
"../source/LibPd/libpd_wrapper/s_libpdmidi.c", | |||
"../source/LibPd/libpd_wrapper/x_libpdreceive.c", | |||
"../source/LibPd/libpd_wrapper/z_hooks.c", | |||
"../source/LibPd/libpd_wrapper/z_libpd.c", | |||
"../../../libs/juce-plugin/JucePluginMain.cpp" | |||
) | |||
} | |||
end |
@@ -0,0 +1,96 @@ | |||
dofile("../../../scripts/make-project.lua") | |||
package = make_juce_vst_project("Camomile") | |||
package.defines = { package.defines, "PD=1", "USEAPI_DUMMY=1", "PD_INTERNAL=1", "PDINSTANCE=1", "PDTHREADS=1", "HAVE_LIBDL=1", "HAVE_UNISTD_H=1" } | |||
package.includepaths = { | |||
package.includepaths, | |||
"../source/LibPd/pure-data/src", | |||
"../source/LibPd/libpd_wrapper" | |||
} | |||
package.files = { | |||
matchfiles ( | |||
"../source/*.cpp", | |||
"../source/Pd/*.c", | |||
"../source/Pd/*.cpp", | |||
"../source/LibPd/pure-data/src/d_arithmetic.c", | |||
"../source/LibPd/pure-data/src/d_array.c", | |||
"../source/LibPd/pure-data/src/d_ctl.c", | |||
"../source/LibPd/pure-data/src/d_dac.c", | |||
"../source/LibPd/pure-data/src/d_delay.c", | |||
"../source/LibPd/pure-data/src/d_fft.c", | |||
"../source/LibPd/pure-data/src/d_fft_fftsg.c", | |||
"../source/LibPd/pure-data/src/d_filter.c", | |||
"../source/LibPd/pure-data/src/d_global.c", | |||
"../source/LibPd/pure-data/src/d_math.c", | |||
"../source/LibPd/pure-data/src/d_misc.c", | |||
"../source/LibPd/pure-data/src/d_osc.c", | |||
"../source/LibPd/pure-data/src/d_resample.c", | |||
"../source/LibPd/pure-data/src/d_soundfile.c", | |||
"../source/LibPd/pure-data/src/d_ugen.c", | |||
"../source/LibPd/pure-data/src/g_all_guis.c", | |||
"../source/LibPd/pure-data/src/g_array.c", | |||
"../source/LibPd/pure-data/src/g_bang.c", | |||
"../source/LibPd/pure-data/src/g_canvas.c", | |||
"../source/LibPd/pure-data/src/g_clone.c", | |||
"../source/LibPd/pure-data/src/g_editor.c", | |||
"../source/LibPd/pure-data/src/g_graph.c", | |||
"../source/LibPd/pure-data/src/g_guiconnect.c", | |||
"../source/LibPd/pure-data/src/g_hdial.c", | |||
"../source/LibPd/pure-data/src/g_hslider.c", | |||
"../source/LibPd/pure-data/src/g_io.c", | |||
"../source/LibPd/pure-data/src/g_mycanvas.c", | |||
"../source/LibPd/pure-data/src/g_numbox.c", | |||
"../source/LibPd/pure-data/src/g_readwrite.c", | |||
"../source/LibPd/pure-data/src/g_rtext.c", | |||
"../source/LibPd/pure-data/src/g_scalar.c", | |||
"../source/LibPd/pure-data/src/g_template.c", | |||
"../source/LibPd/pure-data/src/g_text.c", | |||
"../source/LibPd/pure-data/src/g_toggle.c", | |||
"../source/LibPd/pure-data/src/g_traversal.c", | |||
"../source/LibPd/pure-data/src/g_vdial.c", | |||
"../source/LibPd/pure-data/src/g_vslider.c", | |||
"../source/LibPd/pure-data/src/g_vumeter.c", | |||
"../source/LibPd/pure-data/src/m_atom.c", | |||
"../source/LibPd/pure-data/src/m_binbuf.c", | |||
"../source/LibPd/pure-data/src/m_class.c", | |||
"../source/LibPd/pure-data/src/m_conf.c", | |||
"../source/LibPd/pure-data/src/m_glob.c", | |||
"../source/LibPd/pure-data/src/m_memory.c", | |||
"../source/LibPd/pure-data/src/m_obj.c", | |||
"../source/LibPd/pure-data/src/m_pd.c", | |||
"../source/LibPd/pure-data/src/m_sched.c", | |||
"../source/LibPd/pure-data/src/s_audio.c", | |||
"../source/LibPd/pure-data/src/s_audio_dummy.c", | |||
"../source/LibPd/pure-data/src/s_inter.c", | |||
"../source/LibPd/pure-data/src/s_loader.c", | |||
"../source/LibPd/pure-data/src/s_main.c", | |||
"../source/LibPd/pure-data/src/s_path.c", | |||
"../source/LibPd/pure-data/src/s_print.c", | |||
"../source/LibPd/pure-data/src/s_utf8.c", | |||
"../source/LibPd/pure-data/src/x_acoustics.c", | |||
"../source/LibPd/pure-data/src/x_arithmetic.c", | |||
"../source/LibPd/pure-data/src/x_array.c", | |||
"../source/LibPd/pure-data/src/x_connective.c", | |||
"../source/LibPd/pure-data/src/x_gui.c", | |||
"../source/LibPd/pure-data/src/x_interface.c", | |||
"../source/LibPd/pure-data/src/x_list.c", | |||
"../source/LibPd/pure-data/src/x_midi.c", | |||
"../source/LibPd/pure-data/src/x_misc.c", | |||
"../source/LibPd/pure-data/src/x_net.c", | |||
"../source/LibPd/pure-data/src/x_scalar.c", | |||
"../source/LibPd/pure-data/src/x_text.c", | |||
"../source/LibPd/pure-data/src/x_time.c", | |||
"../source/LibPd/pure-data/src/x_vexp.c", | |||
"../source/LibPd/pure-data/src/x_vexp_fun.c", | |||
"../source/LibPd/pure-data/src/x_vexp_if.c", | |||
"../source/LibPd/libpd_wrapper/s_libpdmidi.c", | |||
"../source/LibPd/libpd_wrapper/x_libpdreceive.c", | |||
"../source/LibPd/libpd_wrapper/z_hooks.c", | |||
"../source/LibPd/libpd_wrapper/z_libpd.c", | |||
"../../../libs/juce-plugin/JucePluginMain.cpp" | |||
) | |||
} |
@@ -0,0 +1,57 @@ | |||
/* ========================================================================================= | |||
This is an auto-generated file: Any edits you make may be overwritten! | |||
*/ | |||
#pragma once | |||
namespace BinaryData | |||
{ | |||
extern const char* CreditsAU; | |||
const int CreditsAUSize = 479; | |||
extern const char* CreditsLV2; | |||
const int CreditsLV2Size = 624; | |||
extern const char* CreditsVST; | |||
const int CreditsVSTSize = 537; | |||
extern const char* DejaVuSansMono_ttf; | |||
const int DejaVuSansMono_ttfSize = 340712; | |||
extern const char* copy_png; | |||
const int copy_pngSize = 4098; | |||
extern const char* flower_center_png; | |||
const int flower_center_pngSize = 3299; | |||
extern const char* flower_petals_png; | |||
const int flower_petals_pngSize = 22287; | |||
extern const char* garbage_png; | |||
const int garbage_pngSize = 5113; | |||
extern const char* reload_png; | |||
const int reload_pngSize = 8380; | |||
extern const char* settings_png; | |||
const int settings_pngSize = 12539; | |||
// Number of elements in the namedResourceList and originalFileNames arrays. | |||
const int namedResourceListSize = 10; | |||
// Points to the start of a list of resource names. | |||
extern const char* namedResourceList[]; | |||
// Points to the start of a list of resource filenames. | |||
extern const char* originalFilenames[]; | |||
// If you provide the name of one of the binary resource variables above, this function will | |||
// return the corresponding data and its size (or a null pointer if the name isn't found). | |||
const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes); | |||
// If you provide the name of one of the binary resource variables above, this function will | |||
// return the corresponding original, non-mangled filename (or a null pointer if the name isn't found). | |||
const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8); | |||
} |
@@ -0,0 +1,31 @@ | |||
/* | |||
IMPORTANT! This file is auto-generated each time you save your | |||
project - if you alter its contents, your changes may be overwritten! | |||
This is the header file that your files should include in order to get all the | |||
JUCE library headers. You should avoid including the JUCE headers directly in | |||
your own source files, because that wouldn't pick up the correct configuration | |||
options for your app. | |||
*/ | |||
#pragma once | |||
#include "JucePluginMain.h" | |||
#include "BinaryData.h" | |||
#if ! DONT_SET_USING_JUCE_NAMESPACE | |||
// If your code uses a lot of JUCE classes, then this will obviously save you | |||
// a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE. | |||
using namespace juce; | |||
#endif | |||
#if ! JUCE_DONT_DECLARE_PROJECTINFO | |||
namespace ProjectInfo | |||
{ | |||
const char* const projectName = "CamomileLV2"; | |||
const char* const versionString = "1.0.6"; | |||
const int versionNumber = 0x10006; | |||
} | |||
#endif |
@@ -0,0 +1,45 @@ | |||
/* | |||
IMPORTANT! This file is auto-generated each time you save your | |||
project - if you alter its contents, your changes may be overwritten! | |||
If you want to change any of these values, use the Introjucer to do so, | |||
rather than editing this file directly! | |||
Any commented-out settings will assume their default values. | |||
*/ | |||
#ifndef __JUCE_APPCONFIG_E0XYLT__ | |||
#define __JUCE_APPCONFIG_E0XYLT__ | |||
//============================================================================== | |||
// Audio plugin settings.. | |||
#include "PluginConfig.h" | |||
#define JucePlugin_ManufacturerCode 0x50494755 | |||
#define JucePlugin_IsSynth 0 | |||
#define JucePlugin_IsMidiEffect 0 | |||
#define JucePlugin_WantsMidiInput 1 | |||
#define JucePlugin_ProducesMidiOutput 1 | |||
#define JucePlugin_SilenceInProducesSilenceOut 1 | |||
#define JucePlugin_EditorRequiresKeyboardFocus 1 | |||
#define JucePlugin_VersionCode 0x10006 | |||
#define JucePlugin_VersionString "1.0.6" | |||
#define JucePlugin_VSTUniqueID JucePlugin_PluginCode | |||
#define JucePlugin_VSTCategory kPlugCategEffect | |||
#define JucePlugin_AUMainType kAudioUnitType_Effect | |||
#define JucePlugin_AUSubType JucePlugin_PluginCode | |||
#define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode | |||
#define JucePlugin_RTASCategory ePlugInCategory_None | |||
#define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode | |||
#define JucePlugin_RTASProductId JucePlugin_PluginCode | |||
// #define JucePlugin_LV2Category "DynamicsPlugin" | |||
#define JucePlugin_WantsLV2Latency 1 | |||
#define JucePlugin_WantsLV2Presets 1 | |||
#define JucePlugin_WantsLV2State 1 | |||
#define JucePlugin_WantsLV2TimePos 1 | |||
#endif // __JUCE_APPCONFIG_E0XYLT__ |
@@ -0,0 +1,76 @@ | |||
/* Copyright (c) 1997-2010 Miller Puckette and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include "z_libpd.h" | |||
#include "z_hooks.h" | |||
#define CLAMP(x, low, high) ((x > high) ? high : ((x < low) ? low : x)) | |||
#define CLAMP4BIT(x) CLAMP(x, 0, 0x0f) | |||
#define CLAMP7BIT(x) CLAMP(x, 0, 0x7f) | |||
#define CLAMP8BIT(x) CLAMP(x, 0, 0xff) | |||
#define CLAMP12BIT(x) CLAMP(x, 0, 0x0fff) | |||
#define CLAMP14BIT(x) CLAMP(x, 0, 0x3fff) | |||
#define CHANNEL ((CLAMP12BIT(port) << 4) | CLAMP4BIT(channel)) | |||
void outmidi_noteon(int port, int channel, int pitch, int velo) { | |||
if (libpd_noteonhook) | |||
libpd_noteonhook(CHANNEL, CLAMP7BIT(pitch), CLAMP7BIT(velo)); | |||
} | |||
void outmidi_controlchange(int port, int channel, int ctl, int value) { | |||
if (libpd_controlchangehook) | |||
libpd_controlchangehook(CHANNEL, CLAMP7BIT(ctl), CLAMP7BIT(value)); | |||
} | |||
void outmidi_programchange(int port, int channel, int value) { | |||
if (libpd_programchangehook) | |||
libpd_programchangehook(CHANNEL, CLAMP7BIT(value)); | |||
} | |||
void outmidi_pitchbend(int port, int channel, int value) { | |||
if (libpd_pitchbendhook) | |||
libpd_pitchbendhook(CHANNEL, CLAMP14BIT(value) - 8192); // remove offset | |||
} | |||
void outmidi_aftertouch(int port, int channel, int value) { | |||
if (libpd_aftertouchhook) | |||
libpd_aftertouchhook(CHANNEL, CLAMP7BIT(value)); | |||
} | |||
void outmidi_polyaftertouch(int port, int channel, int pitch, int value) { | |||
if (libpd_polyaftertouchhook) | |||
libpd_polyaftertouchhook(CHANNEL, CLAMP7BIT(pitch), CLAMP7BIT(value)); | |||
} | |||
void outmidi_byte(int port, int value) { | |||
if (libpd_midibytehook) | |||
libpd_midibytehook(CLAMP12BIT(port), CLAMP8BIT(value)); | |||
} | |||
/* tell Pd gui that our list of MIDI APIs is empty */ | |||
#include <string.h> | |||
void sys_get_midi_apis(char *buf) {strcpy(buf, "{}");} | |||
// The rest is not relevant to libpd. | |||
void sys_listmididevs(void) {} | |||
void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, | |||
int *pnmidioutdev, int *pmidioutdev) {*pnmidiindev = *pnmidioutdev = 0;} | |||
void sys_open_midi(int nmidiindev, int *midiindev, | |||
int nmidioutdev, int *midioutdev, int enable) {} | |||
void sys_close_midi() {} | |||
void sys_reopen_midi(void) {} | |||
void sys_initmidiqueue(void) {} | |||
void sys_pollmidiqueue(void) {} | |||
void sys_setmiditimediff(double inbuftime, double outbuftime) {} | |||
void glob_midi_setapi(void *dummy, t_floatarg f) {} | |||
void glob_midi_properties(t_pd *dummy, t_floatarg flongform) {} | |||
void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {} | |||
int sys_mididevnametonumber(int output, const char *name) { return 0; } | |||
void sys_mididevnumbertoname(int output, int devno, char *name, int namesize) {} | |||
void sys_set_midi_api(int api) {} | |||
int sys_midiapi; | |||
@@ -0,0 +1,126 @@ | |||
/* | |||
* Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#include "ringbuffer.h" | |||
#include <stdarg.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#if __STDC_VERSION__ >= 201112L // use stdatomic if C11 is available | |||
#include <stdatomic.h> | |||
#define SYNC_FETCH(ptr) atomic_fetch_or((_Atomic int *)ptr, 0) | |||
#define SYNC_COMPARE_AND_SWAP(ptr, oldval, newval) \ | |||
atomic_compare_exchange_strong((_Atomic int *)ptr, &oldval, newval) | |||
#else // use platform specfics | |||
#ifdef __APPLE__ // apple atomics | |||
#include <libkern/OSAtomic.h> | |||
#define SYNC_FETCH(ptr) OSAtomicOr32Barrier(0, (volatile uint32_t *)ptr) | |||
#define SYNC_COMPARE_AND_SWAP(ptr, oldval, newval) \ | |||
OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr) | |||
#elif defined(_WIN32) || defined(_WIN64) // win api atomics | |||
#define SYNC_FETCH(ptr) InterlockedOr(ptr, 0) | |||
#define SYNC_COMPARE_AND_SWAP(ptr, oldval, newval) \ | |||
InterlockedCompareExchange(ptr, oldval, newval) | |||
#else // gcc atomics | |||
#define SYNC_FETCH(ptr) __sync_fetch_and_or(ptr, 0) | |||
#define SYNC_COMPARE_AND_SWAP(ptr, oldval, newval) \ | |||
__sync_val_compare_and_swap(ptr, oldval, newval) | |||
#endif | |||
#endif | |||
ring_buffer *rb_create(int size) { | |||
if (size & 0xff) return NULL; // size must be a multiple of 256 | |||
ring_buffer *buffer = malloc(sizeof(ring_buffer)); | |||
if (!buffer) return NULL; | |||
buffer->buf_ptr = calloc(size, sizeof(char)); | |||
if (!buffer->buf_ptr) { | |||
free(buffer); | |||
return NULL; | |||
} | |||
buffer->size = size; | |||
buffer->write_idx = 0; | |||
buffer->read_idx = 0; | |||
return buffer; | |||
} | |||
void rb_free(ring_buffer *buffer) { | |||
free(buffer->buf_ptr); | |||
free(buffer); | |||
} | |||
int rb_available_to_write(ring_buffer *buffer) { | |||
if (buffer) { | |||
// Note: The largest possible result is buffer->size - 1 because | |||
// we adopt the convention that read_idx == write_idx means that the | |||
// buffer is empty. | |||
int read_idx = SYNC_FETCH(&(buffer->read_idx)); | |||
int write_idx = SYNC_FETCH(&(buffer->write_idx)); | |||
return (buffer->size + read_idx - write_idx - 1) % buffer->size; | |||
} else { | |||
return 0; | |||
} | |||
} | |||
int rb_available_to_read(ring_buffer *buffer) { | |||
if (buffer) { | |||
int read_idx = SYNC_FETCH(&(buffer->read_idx)); | |||
int write_idx = SYNC_FETCH(&(buffer->write_idx)); | |||
return (buffer->size + write_idx - read_idx) % buffer->size; | |||
} else { | |||
return 0; | |||
} | |||
} | |||
int rb_write_to_buffer(ring_buffer *buffer, int n, ...) { | |||
if (!buffer) return -1; | |||
int write_idx = buffer->write_idx; // No need for sync in writer thread. | |||
int available = rb_available_to_write(buffer); | |||
va_list args; | |||
va_start(args, n); | |||
int i; | |||
for (i = 0; i < n; ++i) { | |||
const char* src = va_arg(args, const char*); | |||
int len = va_arg(args, int); | |||
available -= len; | |||
if (len < 0 || available < 0) return -1; | |||
if (write_idx + len <= buffer->size) { | |||
memcpy(buffer->buf_ptr + write_idx, src, len); | |||
} else { | |||
int d = buffer->size - write_idx; | |||
memcpy(buffer->buf_ptr + write_idx, src, d); | |||
memcpy(buffer->buf_ptr, src + d, len - d); | |||
} | |||
write_idx = (write_idx + len) % buffer->size; | |||
} | |||
va_end(args); | |||
SYNC_COMPARE_AND_SWAP(&(buffer->write_idx), buffer->write_idx, | |||
write_idx); // Includes memory barrier. | |||
return 0; | |||
} | |||
int rb_read_from_buffer(ring_buffer *buffer, char *dest, int len) { | |||
if (len == 0) return 0; | |||
if (!buffer || len < 0 || len > rb_available_to_read(buffer)) return -1; | |||
// Note that rb_available_to_read also serves as a memory barrier, and so any | |||
// writes to buffer->buf_ptr that precede the update of buffer->write_idx are | |||
// visible to us now. | |||
int read_idx = buffer->read_idx; // No need for sync in reader thread. | |||
if (read_idx + len <= buffer->size) { | |||
memcpy(dest, buffer->buf_ptr + read_idx, len); | |||
} else { | |||
int d = buffer->size - read_idx; | |||
memcpy(dest, buffer->buf_ptr + read_idx, d); | |||
memcpy(dest + d, buffer->buf_ptr, len - d); | |||
} | |||
SYNC_COMPARE_AND_SWAP(&(buffer->read_idx), buffer->read_idx, | |||
(read_idx + len) % buffer->size); // Includes memory barrier. | |||
return 0; | |||
} |
@@ -0,0 +1,49 @@ | |||
/* | |||
* Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#ifndef __OPENSL_RING_BUFFER_H__ | |||
#define __OPENSL_RING_BUFFER_H__ | |||
// Simple lock-free ring buffer implementation for one writer thread and one | |||
// consumer thread. | |||
typedef struct ring_buffer { | |||
int size; | |||
char *buf_ptr; | |||
int write_idx; | |||
int read_idx; | |||
} ring_buffer; | |||
// Creates a ring buffer (returns NULL on failure). | |||
ring_buffer *rb_create(int size); | |||
// Deletes a ring buffer. | |||
void rb_free(ring_buffer *buffer); | |||
// Returns the number of bytes that can currently be written; safe to be called | |||
// from any thread. | |||
int rb_available_to_write(ring_buffer *buffer); | |||
// Returns the number of bytes that can currently be read; safe to be called | |||
// from any thread. | |||
int rb_available_to_read(ring_buffer *buffer); | |||
// Writes bytes from n sources to the ring buffer (if the ring buffer has | |||
// enough space). The varargs are pairs of type (const char*, int) giving a | |||
// pointer to a buffer and the number of bytes to be copied. Only to be called | |||
// from a single writer thread. | |||
// Returns 0 on success. | |||
int rb_write_to_buffer(ring_buffer *buffer, int n, ...); | |||
// Reads the given number of bytes fromthe ring buffer to dest if the ring | |||
// buffer has enough data. Only to be called from a single reader thread. | |||
// Returns 0 on success. | |||
int rb_read_from_buffer(ring_buffer *buffer, char *dest, int len); | |||
#endif |
@@ -0,0 +1,51 @@ | |||
/* | |||
* Copyright (c) 2013 Dan Wilcox (danomatika@gmail.com) & | |||
* Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#include "z_print_util.h" | |||
#include <stdlib.h> | |||
#include <string.h> | |||
t_libpd_printhook libpd_concatenated_printhook = NULL; | |||
#define PRINT_LINE_SIZE 2048 | |||
void libpd_set_concatenated_printhook(const t_libpd_printhook hook) { | |||
libpd_concatenated_printhook = hook; | |||
} | |||
void libpd_print_concatenator(const char *s) { | |||
if (!libpd_concatenated_printhook) return; | |||
static char concatenated_print_line[PRINT_LINE_SIZE]; | |||
static int len_line = 0; | |||
concatenated_print_line[len_line] = '\0'; | |||
int len = (int) strlen(s); | |||
while (len_line + len >= PRINT_LINE_SIZE) { | |||
int d = PRINT_LINE_SIZE - 1 - len_line; | |||
strncat(concatenated_print_line, s, d); | |||
libpd_concatenated_printhook(concatenated_print_line); | |||
s += d; | |||
len -= d; | |||
len_line = 0; | |||
concatenated_print_line[0] = '\0'; | |||
} | |||
strncat(concatenated_print_line, s, len); | |||
len_line += len; | |||
if (len_line > 0 && concatenated_print_line[len_line - 1] == '\n') { | |||
concatenated_print_line[len_line - 1] = '\0'; | |||
libpd_concatenated_printhook(concatenated_print_line); | |||
len_line = 0; | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* Copyright (c) 2013 Dan Wilcox (danomatika@gmail.com) & | |||
* Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#ifndef __Z_PRINT_UTIL_H__ | |||
#define __Z_PRINT_UTIL_H__ | |||
#include "z_libpd.h" | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif | |||
// Concatenate print messages into single lines before returning them | |||
// to a print hook: ie "hello 123" is sent in 1 part -> "hello 123" | |||
// | |||
// For comparison, the default behavior returns individual words and spaces: | |||
// ie "hello 123" is sent in 3 parts -> "hello", " ", "123" | |||
// Assign the pointer to your print handler. | |||
EXTERN void libpd_set_concatenated_printhook(const t_libpd_printhook hook); | |||
// Assign this function pointer to libpd_printhook or libpd_queued_printhook, | |||
// depending on whether you're using queued messages, to intercept and | |||
// concatenate print messages: | |||
// | |||
// libpd_set_printhook(libpd_print_concatenator); | |||
// libpd_set_concatenated_printhook(your_print_handler); | |||
// | |||
// Note: The char pointer argument is only good for the duration of the print | |||
// callback; if you intend to use the argument after the callback has | |||
// returned, you need to make a defensive copy. | |||
// | |||
void libpd_print_concatenator(const char *s); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif |
@@ -0,0 +1,413 @@ | |||
/* | |||
* Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#include "z_queued.h" | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "ringbuffer.h" | |||
t_libpd_printhook libpd_queued_printhook = NULL; | |||
t_libpd_banghook libpd_queued_banghook = NULL; | |||
t_libpd_floathook libpd_queued_floathook = NULL; | |||
t_libpd_symbolhook libpd_queued_symbolhook = NULL; | |||
t_libpd_listhook libpd_queued_listhook = NULL; | |||
t_libpd_messagehook libpd_queued_messagehook = NULL; | |||
t_libpd_noteonhook libpd_queued_noteonhook = NULL; | |||
t_libpd_controlchangehook libpd_queued_controlchangehook = NULL; | |||
t_libpd_programchangehook libpd_queued_programchangehook = NULL; | |||
t_libpd_pitchbendhook libpd_queued_pitchbendhook = NULL; | |||
t_libpd_aftertouchhook libpd_queued_aftertouchhook = NULL; | |||
t_libpd_polyaftertouchhook libpd_queued_polyaftertouchhook = NULL; | |||
t_libpd_midibytehook libpd_queued_midibytehook = NULL; | |||
typedef struct _pd_params { | |||
enum { | |||
LIBPD_PRINT, LIBPD_BANG, LIBPD_FLOAT, | |||
LIBPD_SYMBOL, LIBPD_LIST, LIBPD_MESSAGE, | |||
} type; | |||
const char *src; | |||
float x; | |||
const char *sym; | |||
int argc; | |||
} pd_params; | |||
typedef struct _midi_params { | |||
enum { | |||
LIBPD_NOTEON, LIBPD_CONTROLCHANGE, LIBPD_PROGRAMCHANGE, LIBPD_PITCHBEND, | |||
LIBPD_AFTERTOUCH, LIBPD_POLYAFTERTOUCH, LIBPD_MIDIBYTE | |||
} type; | |||
int midi1; | |||
int midi2; | |||
int midi3; | |||
} midi_params; | |||
#define BUFFER_SIZE 16384 | |||
#define S_PD_PARAMS sizeof(pd_params) | |||
#define S_MIDI_PARAMS sizeof(midi_params) | |||
#define S_ATOM sizeof(t_atom) | |||
static ring_buffer *pd_receive_buffer = NULL; | |||
static ring_buffer *midi_receive_buffer = NULL; | |||
static void receive_print(pd_params *p, char **buffer) { | |||
if (libpd_queued_printhook) { | |||
libpd_queued_printhook(*buffer); | |||
} | |||
*buffer += p->argc; | |||
} | |||
static void receive_bang(pd_params *p, char **buffer) { | |||
if (libpd_queued_banghook) { | |||
libpd_queued_banghook(p->src); | |||
} | |||
} | |||
static void receive_float(pd_params *p, char **buffer) { | |||
if (libpd_queued_floathook) { | |||
libpd_queued_floathook(p->src, p->x); | |||
} | |||
} | |||
static void receive_symbol(pd_params *p, char **buffer) { | |||
if (libpd_queued_symbolhook) { | |||
libpd_queued_symbolhook(p->src, p->sym); | |||
} | |||
} | |||
static void receive_list(pd_params *p, char **buffer) { | |||
if (libpd_queued_listhook) { | |||
libpd_queued_listhook(p->src, p->argc, (t_atom *) *buffer); | |||
} | |||
*buffer += p->argc * S_ATOM; | |||
} | |||
static void receive_message(pd_params *p, char **buffer) { | |||
if (libpd_queued_messagehook) { | |||
libpd_queued_messagehook(p->src, p->sym, p->argc, (t_atom *) *buffer); | |||
} | |||
*buffer += p->argc * S_ATOM; | |||
} | |||
#define LIBPD_WORD_ALIGN 8 | |||
static void internal_printhook(const char *s) { | |||
static char padding[LIBPD_WORD_ALIGN]; | |||
int len = (int) strlen(s) + 1; // remember terminating null char | |||
int rest = len % LIBPD_WORD_ALIGN; | |||
if (rest) rest = LIBPD_WORD_ALIGN - rest; | |||
int total = len + rest; | |||
if (rb_available_to_write(pd_receive_buffer) >= S_PD_PARAMS + total) { | |||
pd_params p = {LIBPD_PRINT, NULL, 0.0f, NULL, total}; | |||
rb_write_to_buffer(pd_receive_buffer, 3, | |||
(const char *)&p, S_PD_PARAMS, s, len, padding, rest); | |||
} | |||
} | |||
static void internal_banghook(const char *src) { | |||
if (rb_available_to_write(pd_receive_buffer) >= S_PD_PARAMS) { | |||
pd_params p = {LIBPD_BANG, src, 0.0f, NULL, 0}; | |||
rb_write_to_buffer(pd_receive_buffer, 1, (const char *)&p, S_PD_PARAMS); | |||
} | |||
} | |||
static void internal_floathook(const char *src, float x) { | |||
if (rb_available_to_write(pd_receive_buffer) >= S_PD_PARAMS) { | |||
pd_params p = {LIBPD_FLOAT, src, x, NULL, 0}; | |||
rb_write_to_buffer(pd_receive_buffer, 1, (const char *)&p, S_PD_PARAMS); | |||
} | |||
} | |||
static void internal_symbolhook(const char *src, const char *sym) { | |||
if (rb_available_to_write(pd_receive_buffer) >= S_PD_PARAMS) { | |||
pd_params p = {LIBPD_SYMBOL, src, 0.0f, sym, 0}; | |||
rb_write_to_buffer(pd_receive_buffer, 1, (const char *)&p, S_PD_PARAMS); | |||
} | |||
} | |||
static void internal_listhook(const char *src, int argc, t_atom *argv) { | |||
int n = argc * S_ATOM; | |||
if (rb_available_to_write(pd_receive_buffer) >= S_PD_PARAMS + n) { | |||
pd_params p = {LIBPD_LIST, src, 0.0f, NULL, argc}; | |||
rb_write_to_buffer(pd_receive_buffer, 2, | |||
(const char *)&p, S_PD_PARAMS, (const char *)argv, n); | |||
} | |||
} | |||
static void internal_messagehook(const char *src, const char* sym, | |||
int argc, t_atom *argv) { | |||
int n = argc * S_ATOM; | |||
if (rb_available_to_write(pd_receive_buffer) >= S_PD_PARAMS + n) { | |||
pd_params p = {LIBPD_MESSAGE, src, 0.0f, sym, argc}; | |||
rb_write_to_buffer(pd_receive_buffer, 2, | |||
(const char *)&p, S_PD_PARAMS, (const char *)argv, n); | |||
} | |||
} | |||
static void receive_noteon(midi_params *p, char **buffer) { | |||
if (libpd_queued_noteonhook) { | |||
libpd_queued_noteonhook(p->midi1, p->midi2, p->midi3); | |||
} | |||
} | |||
static void receive_controlchange(midi_params *p, char **buffer) { | |||
if (libpd_queued_controlchangehook) { | |||
libpd_queued_controlchangehook(p->midi1, p->midi2, p->midi3); | |||
} | |||
} | |||
static void receive_programchange(midi_params *p, char **buffer) { | |||
if (libpd_queued_programchangehook) { | |||
libpd_queued_programchangehook(p->midi1, p->midi2); | |||
} | |||
} | |||
static void receive_pitchbend(midi_params *p, char **buffer) { | |||
if (libpd_queued_pitchbendhook) { | |||
libpd_queued_pitchbendhook(p->midi1, p->midi2); | |||
} | |||
} | |||
static void receive_aftertouch(midi_params *p, char **buffer) { | |||
if (libpd_queued_aftertouchhook) { | |||
libpd_queued_aftertouchhook(p->midi1, p->midi2); | |||
} | |||
} | |||
static void receive_polyaftertouch(midi_params *p, char **buffer) { | |||
if (libpd_queued_polyaftertouchhook) { | |||
libpd_queued_polyaftertouchhook(p->midi1, p->midi2, p->midi3); | |||
} | |||
} | |||
static void receive_midibyte(midi_params *p, char **buffer) { | |||
if (libpd_queued_midibytehook) { | |||
libpd_queued_midibytehook(p->midi1, p->midi2); | |||
} | |||
} | |||
static void internal_noteonhook(int channel, int pitch, int velocity) { | |||
if (rb_available_to_write(midi_receive_buffer) >= S_MIDI_PARAMS) { | |||
midi_params p = {LIBPD_NOTEON, channel, pitch, velocity}; | |||
rb_write_to_buffer(midi_receive_buffer, 1, (const char *)&p, S_MIDI_PARAMS); | |||
} | |||
} | |||
static void internal_controlchangehook(int channel, int controller, int value) { | |||
if (rb_available_to_write(midi_receive_buffer) >= S_MIDI_PARAMS) { | |||
midi_params p = {LIBPD_CONTROLCHANGE, channel, controller, value}; | |||
rb_write_to_buffer(midi_receive_buffer, 1, (const char *)&p, S_MIDI_PARAMS); | |||
} | |||
} | |||
static void internal_programchangehook(int channel, int value) { | |||
if (rb_available_to_write(midi_receive_buffer) >= S_MIDI_PARAMS) { | |||
midi_params p = {LIBPD_PROGRAMCHANGE, channel, value, 0}; | |||
rb_write_to_buffer(midi_receive_buffer, 1, (const char *)&p, S_MIDI_PARAMS); | |||
} | |||
} | |||
static void internal_pitchbendhook(int channel, int value) { | |||
if (rb_available_to_write(midi_receive_buffer) >= S_MIDI_PARAMS) { | |||
midi_params p = {LIBPD_PITCHBEND, channel, value, 0}; | |||
rb_write_to_buffer(midi_receive_buffer, 1, (const char *)&p, S_MIDI_PARAMS); | |||
} | |||
} | |||
static void internal_aftertouchhook(int channel, int value) { | |||
if (rb_available_to_write(midi_receive_buffer) >= S_MIDI_PARAMS) { | |||
midi_params p = {LIBPD_AFTERTOUCH, channel, value, 0}; | |||
rb_write_to_buffer(midi_receive_buffer, 1, (const char *)&p, S_MIDI_PARAMS); | |||
} | |||
} | |||
static void internal_polyaftertouchhook(int channel, int pitch, int value) { | |||
if (rb_available_to_write(midi_receive_buffer) >= S_MIDI_PARAMS) { | |||
midi_params p = {LIBPD_POLYAFTERTOUCH, channel, pitch, value}; | |||
rb_write_to_buffer(midi_receive_buffer, 1, (const char *)&p, S_MIDI_PARAMS); | |||
} | |||
} | |||
static void internal_midibytehook(int port, int byte) { | |||
if (rb_available_to_write(midi_receive_buffer) >= S_MIDI_PARAMS) { | |||
midi_params p = {LIBPD_MIDIBYTE, port, byte, 0}; | |||
rb_write_to_buffer(midi_receive_buffer, 1, (const char *)&p, S_MIDI_PARAMS); | |||
} | |||
} | |||
void libpd_set_queued_printhook(const t_libpd_printhook hook) { | |||
libpd_queued_printhook = hook; | |||
} | |||
void libpd_set_queued_banghook(const t_libpd_banghook hook) { | |||
libpd_queued_banghook = hook; | |||
} | |||
void libpd_set_queued_floathook(const t_libpd_floathook hook) { | |||
libpd_queued_floathook = hook; | |||
} | |||
void libpd_set_queued_symbolhook(const t_libpd_symbolhook hook) { | |||
libpd_queued_symbolhook = hook; | |||
} | |||
void libpd_set_queued_listhook(const t_libpd_listhook hook) { | |||
libpd_queued_listhook = hook; | |||
} | |||
void libpd_set_queued_messagehook(const t_libpd_messagehook hook) { | |||
libpd_queued_messagehook = hook; | |||
} | |||
void libpd_set_queued_noteonhook(const t_libpd_noteonhook hook) { | |||
libpd_queued_noteonhook = hook; | |||
} | |||
void libpd_set_queued_controlchangehook(const t_libpd_controlchangehook hook) { | |||
libpd_queued_controlchangehook = hook; | |||
} | |||
void libpd_set_queued_programchangehook(const t_libpd_programchangehook hook) { | |||
libpd_queued_programchangehook = hook; | |||
} | |||
void libpd_set_queued_pitchbendhook(const t_libpd_pitchbendhook hook) { | |||
libpd_queued_pitchbendhook = hook; | |||
} | |||
void libpd_set_queued_aftertouchhook(const t_libpd_aftertouchhook hook) { | |||
libpd_queued_aftertouchhook = hook; | |||
} | |||
void libpd_set_queued_polyaftertouchhook(const t_libpd_polyaftertouchhook hook) { | |||
libpd_queued_polyaftertouchhook = hook; | |||
} | |||
void libpd_set_queued_midibytehook(const t_libpd_midibytehook hook) { | |||
libpd_queued_midibytehook = hook; | |||
} | |||
int libpd_queued_init() { | |||
pd_receive_buffer = rb_create(BUFFER_SIZE); | |||
if (!pd_receive_buffer) return -1; | |||
midi_receive_buffer = rb_create(BUFFER_SIZE); | |||
if (!midi_receive_buffer) return -1; | |||
libpd_set_printhook(internal_printhook); | |||
libpd_set_banghook(internal_banghook); | |||
libpd_set_floathook(internal_floathook); | |||
libpd_set_symbolhook(internal_symbolhook); | |||
libpd_set_listhook(internal_listhook); | |||
libpd_set_messagehook(internal_messagehook); | |||
libpd_set_noteonhook(internal_noteonhook); | |||
libpd_set_controlchangehook(internal_controlchangehook); | |||
libpd_set_programchangehook(internal_programchangehook); | |||
libpd_set_pitchbendhook(internal_pitchbendhook); | |||
libpd_set_aftertouchhook(internal_aftertouchhook); | |||
libpd_set_polyaftertouchhook(internal_polyaftertouchhook); | |||
libpd_set_midibytehook(internal_midibytehook); | |||
libpd_init(); | |||
return 0; | |||
} | |||
void libpd_queued_release() { | |||
rb_free(pd_receive_buffer); | |||
rb_free(midi_receive_buffer); | |||
} | |||
void libpd_queued_receive_pd_messages() { | |||
size_t available = rb_available_to_read(pd_receive_buffer); | |||
if (!available) return; | |||
static char temp_buffer[BUFFER_SIZE]; | |||
rb_read_from_buffer(pd_receive_buffer, temp_buffer, (int) available); | |||
char *end = temp_buffer + available; | |||
char *buffer = temp_buffer; | |||
while (buffer < end) { | |||
pd_params *p = (pd_params *)buffer; | |||
buffer += S_PD_PARAMS; | |||
switch (p->type) { | |||
case LIBPD_PRINT: { | |||
receive_print(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_BANG: { | |||
receive_bang(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_FLOAT: { | |||
receive_float(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_SYMBOL: { | |||
receive_symbol(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_LIST: { | |||
receive_list(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_MESSAGE: { | |||
receive_message(p, &buffer); | |||
break; | |||
} | |||
default: | |||
break; | |||
} | |||
} | |||
} | |||
void libpd_queued_receive_midi_messages() { | |||
size_t available = rb_available_to_read(midi_receive_buffer); | |||
if (!available) return; | |||
static char temp_buffer[BUFFER_SIZE]; | |||
rb_read_from_buffer(midi_receive_buffer, temp_buffer, (int) available); | |||
char *end = temp_buffer + available; | |||
char *buffer = temp_buffer; | |||
while (buffer < end) { | |||
midi_params *p = (midi_params *)buffer; | |||
buffer += S_MIDI_PARAMS; | |||
switch (p->type) { | |||
case LIBPD_NOTEON: { | |||
receive_noteon(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_CONTROLCHANGE: { | |||
receive_controlchange(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_PROGRAMCHANGE: { | |||
receive_programchange(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_PITCHBEND: { | |||
receive_pitchbend(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_AFTERTOUCH: { | |||
receive_aftertouch(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_POLYAFTERTOUCH: { | |||
receive_polyaftertouch(p, &buffer); | |||
break; | |||
} | |||
case LIBPD_MIDIBYTE: { | |||
receive_midibyte(p, &buffer); | |||
break; | |||
} | |||
default: | |||
break; | |||
} | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#ifndef __Z_QUEUED_H__ | |||
#define __Z_QUEUED_H__ | |||
#include "z_libpd.h" | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif | |||
EXTERN void libpd_set_queued_printhook(const t_libpd_printhook hook); | |||
EXTERN void libpd_set_queued_banghook(const t_libpd_banghook hook); | |||
EXTERN void libpd_set_queued_floathook(const t_libpd_floathook hook); | |||
EXTERN void libpd_set_queued_symbolhook(const t_libpd_symbolhook hook); | |||
EXTERN void libpd_set_queued_listhook(const t_libpd_listhook hook); | |||
EXTERN void libpd_set_queued_messagehook(const t_libpd_messagehook hook); | |||
EXTERN void libpd_set_queued_noteonhook(const t_libpd_noteonhook hook); | |||
EXTERN void libpd_set_queued_controlchangehook(const t_libpd_controlchangehook hook); | |||
EXTERN void libpd_set_queued_programchangehook(const t_libpd_programchangehook hook); | |||
EXTERN void libpd_set_queued_pitchbendhook(const t_libpd_pitchbendhook hook); | |||
EXTERN void libpd_set_queued_aftertouchhook(const t_libpd_aftertouchhook hook); | |||
EXTERN void libpd_set_queued_polyaftertouchhook(const t_libpd_polyaftertouchhook hook); | |||
EXTERN void libpd_set_queued_midibytehook(const t_libpd_midibytehook hook); | |||
int libpd_queued_init(); | |||
void libpd_queued_release(); | |||
void libpd_queued_receive_pd_messages(); | |||
void libpd_queued_receive_midi_messages(); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif |
@@ -0,0 +1,83 @@ | |||
/* | |||
* Copyright (c) 2010 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#include <stdio.h> | |||
#include "m_pd.h" | |||
#include "x_libpdreceive.h" | |||
#include "z_libpd.h" | |||
#include "z_hooks.h" | |||
static t_class *libpdrec_class; | |||
typedef struct _libpdrec { | |||
t_object x_obj; | |||
t_symbol *x_sym; | |||
} t_libpdrec; | |||
static void libpdrecbang(t_libpdrec *x) { | |||
if (libpd_banghook) (*libpd_banghook)(x->x_sym->s_name); | |||
} | |||
static void libpdrecfloat(t_libpdrec *x, t_float f) { | |||
if (libpd_floathook) (*libpd_floathook)(x->x_sym->s_name, f); | |||
} | |||
static void libpdrecsymbol(t_libpdrec *x, t_symbol *s) { | |||
if (libpd_symbolhook) (*libpd_symbolhook)(x->x_sym->s_name, s->s_name); | |||
} | |||
static void libpdrecpointer(t_libpdrec *x, t_gpointer *gp) { | |||
// just ignore pointers for now... | |||
} | |||
static void libpdreclist(t_libpdrec *x, t_symbol *s, int argc, t_atom *argv) { | |||
if (libpd_listhook) (*libpd_listhook)(x->x_sym->s_name, argc, argv); | |||
} | |||
static void libpdrecanything(t_libpdrec *x, t_symbol *s, | |||
int argc, t_atom *argv) { | |||
if (libpd_messagehook) | |||
(*libpd_messagehook)(x->x_sym->s_name, s->s_name, argc, argv); | |||
} | |||
static void libpdreceive_free(t_libpdrec *x) { | |||
pd_unbind(&x->x_obj.ob_pd, x->x_sym); | |||
} | |||
static void *libpdreceive_donew(t_symbol *s) { | |||
t_libpdrec *x; | |||
x = (t_libpdrec *)pd_new(libpdrec_class); | |||
x->x_sym = s; | |||
pd_bind(&x->x_obj.ob_pd, s); | |||
return x; | |||
} | |||
// This is exposed in the libpd API so must set the lock. | |||
void *libpdreceive_new(t_symbol *s) { | |||
t_libpdrec *x; | |||
sys_lock(); | |||
x = (t_libpdrec *)libpdreceive_donew(s); | |||
sys_unlock(); | |||
return x; | |||
} | |||
void libpdreceive_setup(void) { | |||
sys_lock(); | |||
libpdrec_class = class_new(gensym("libpd_receive"), | |||
(t_newmethod)libpdreceive_donew, (t_method)libpdreceive_free, | |||
sizeof(t_libpdrec), CLASS_DEFAULT, A_DEFSYM, 0); | |||
class_addbang(libpdrec_class, libpdrecbang); | |||
class_addfloat(libpdrec_class, libpdrecfloat); | |||
class_addsymbol(libpdrec_class, libpdrecsymbol); | |||
class_addpointer(libpdrec_class, libpdrecpointer); | |||
class_addlist(libpdrec_class, libpdreclist); | |||
class_addanything(libpdrec_class, libpdrecanything); | |||
sys_unlock(); | |||
} |
@@ -0,0 +1,19 @@ | |||
/* | |||
* Copyright (c) 2010 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#ifndef __X_LIBPDREC_H__ | |||
#define __X_LIBPDREC_H__ | |||
#include "m_pd.h" | |||
void libpdreceive_setup(void); | |||
void *libpdreceive_new(t_symbol *); | |||
#endif |
@@ -0,0 +1,26 @@ | |||
/* | |||
* Copyright (c) 2013 Dan Wilcox (danomatika@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#include "z_hooks.h" | |||
t_libpd_printhook libpd_printhook = NULL; | |||
t_libpd_banghook libpd_banghook = NULL; | |||
t_libpd_floathook libpd_floathook = NULL; | |||
t_libpd_symbolhook libpd_symbolhook = NULL; | |||
t_libpd_listhook libpd_listhook = NULL; | |||
t_libpd_messagehook libpd_messagehook = NULL; | |||
t_libpd_noteonhook libpd_noteonhook = NULL; | |||
t_libpd_controlchangehook libpd_controlchangehook = NULL; | |||
t_libpd_programchangehook libpd_programchangehook = NULL; | |||
t_libpd_pitchbendhook libpd_pitchbendhook = NULL; | |||
t_libpd_aftertouchhook libpd_aftertouchhook = NULL; | |||
t_libpd_polyaftertouchhook libpd_polyaftertouchhook = NULL; | |||
t_libpd_midibytehook libpd_midibytehook = NULL; |
@@ -0,0 +1,35 @@ | |||
/* | |||
* Copyright (c) 2013 Dan Wilcox (danomatika@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#ifndef __Z_HOOKS_H__ | |||
#define __Z_HOOKS_H__ | |||
#include "z_libpd.h" | |||
// the internal hooks | |||
// in a separate file so they can be used throughout the libpd_wrapper sources, | |||
// do *not* include this file in a user-facing header | |||
extern t_libpd_printhook libpd_printhook; | |||
extern t_libpd_banghook libpd_banghook; | |||
extern t_libpd_floathook libpd_floathook; | |||
extern t_libpd_symbolhook libpd_symbolhook; | |||
extern t_libpd_listhook libpd_listhook; | |||
extern t_libpd_messagehook libpd_messagehook; | |||
extern t_libpd_noteonhook libpd_noteonhook; | |||
extern t_libpd_controlchangehook libpd_controlchangehook; | |||
extern t_libpd_programchangehook libpd_programchangehook; | |||
extern t_libpd_pitchbendhook libpd_pitchbendhook; | |||
extern t_libpd_aftertouchhook libpd_aftertouchhook; | |||
extern t_libpd_polyaftertouchhook libpd_polyaftertouchhook; | |||
extern t_libpd_midibytehook libpd_midibytehook; | |||
#endif |
@@ -0,0 +1,639 @@ | |||
/* | |||
* Copyright (c) 2010 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#include <signal.h> | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <limits.h> | |||
#ifndef LIBPD_NO_NUMERIC | |||
# include <locale.h> | |||
#endif | |||
#include "z_libpd.h" | |||
#include "x_libpdreceive.h" | |||
#include "z_hooks.h" | |||
#include "s_stuff.h" | |||
#include "m_imp.h" | |||
#include "g_all_guis.h" | |||
#if PD_MINOR_VERSION < 46 | |||
# define HAVE_SCHED_TICK_ARG | |||
#endif | |||
#ifdef HAVE_SCHED_TICK_ARG | |||
# define SCHED_TICK(x) sched_tick(x) | |||
#else | |||
# define SCHED_TICK(x) sched_tick() | |||
#endif | |||
// forward declares | |||
void pd_init(void); | |||
int sys_startgui(const char *libdir); | |||
void sys_stopgui(void); | |||
int sys_pollgui(void); | |||
// (optional) built in pd externals setup functions | |||
#ifdef LIBPD_EXTRA | |||
void bob_tilde_setup(); | |||
void bonk_tilde_setup(); | |||
void choice_setup(); | |||
void fiddle_tilde_setup(); | |||
void loop_tilde_setup(); | |||
void lrshift_tilde_setup(); | |||
void pique_setup(); | |||
void sigmund_tilde_setup(); | |||
void stdout_setup(); | |||
#endif | |||
static PERTHREAD t_atom *argv = NULL; | |||
static PERTHREAD t_atom *curr = NULL; | |||
static PERTHREAD int argm = 0; | |||
static PERTHREAD int argc = 0; | |||
static void *get_object(const char *s) { | |||
t_pd *x = gensym(s)->s_thing; | |||
return x; | |||
} | |||
// this is called instead of sys_main() to start things | |||
int libpd_init(void) { | |||
static int initialized = 0; | |||
if (initialized) return -1; // only allow init once (for now) | |||
initialized = 1; | |||
signal(SIGFPE, SIG_IGN); | |||
libpd_start_message(32); // allocate array for message assembly | |||
sys_printhook = (t_printhook) libpd_printhook; | |||
// are all these settings necessary? | |||
sys_externalschedlib = 0; | |||
sys_printtostderr = 0; | |||
sys_usestdpath = 0; // don't use pd_extrapath, only sys_searchpath | |||
sys_debuglevel = 0; | |||
sys_noloadbang = 0; | |||
sys_hipriority = 0; | |||
sys_nmidiin = 0; | |||
sys_nmidiout = 0; | |||
#ifdef HAVE_SCHED_TICK_ARG | |||
sys_time = 0; | |||
#endif | |||
pd_init(); | |||
STUFF->st_soundin = NULL; | |||
STUFF->st_soundout = NULL; | |||
STUFF->st_schedblocksize = DEFDACBLKSIZE; | |||
sys_init_fdpoll(); | |||
libpdreceive_setup(); | |||
sys_set_audio_api(API_DUMMY); | |||
STUFF->st_searchpath = NULL; | |||
sys_libdir = gensym(""); | |||
#ifdef LIBPD_EXTRA | |||
bob_tilde_setup(); | |||
bonk_tilde_setup(); | |||
choice_setup(); | |||
fiddle_tilde_setup(); | |||
loop_tilde_setup(); | |||
lrshift_tilde_setup(); | |||
pique_setup(); | |||
sigmund_tilde_setup(); | |||
stdout_setup(); | |||
#endif | |||
#ifndef LIBPD_NO_NUMERIC | |||
setlocale(LC_NUMERIC, "C"); | |||
#endif | |||
return 0; | |||
} | |||
void libpd_clear_search_path(void) { | |||
sys_lock(); | |||
namelist_free(STUFF->st_searchpath); | |||
STUFF->st_searchpath = NULL; | |||
sys_unlock(); | |||
} | |||
void libpd_add_to_search_path(const char *s) { | |||
sys_lock(); | |||
STUFF->st_searchpath = namelist_append(STUFF->st_searchpath, s, 0); | |||
sys_unlock(); | |||
} | |||
void *libpd_openfile(const char *basename, const char *dirname) { | |||
void * retval; | |||
sys_lock(); | |||
pd_globallock(); | |||
retval = (void *)glob_evalfile(NULL, gensym(basename), gensym(dirname)); | |||
pd_globalunlock(); | |||
sys_unlock(); | |||
return retval; | |||
} | |||
void libpd_closefile(void *x) { | |||
sys_lock(); | |||
pd_free((t_pd *)x); | |||
sys_unlock(); | |||
} | |||
int libpd_getdollarzero(void *x) { | |||
sys_lock(); | |||
pd_pushsym((t_pd *)x); | |||
int dzero = canvas_getdollarzero(); | |||
pd_popsym((t_pd *)x); | |||
sys_unlock(); | |||
return dzero; | |||
} | |||
int libpd_init_audio(int inChans, int outChans, int sampleRate) { | |||
int indev[MAXAUDIOINDEV], inch[MAXAUDIOINDEV], | |||
outdev[MAXAUDIOOUTDEV], outch[MAXAUDIOOUTDEV]; | |||
indev[0] = outdev[0] = DEFAULTAUDIODEV; | |||
inch[0] = inChans; | |||
outch[0] = outChans; | |||
sys_lock(); | |||
sys_set_audio_settings(1, indev, 1, inch, | |||
1, outdev, 1, outch, sampleRate, -1, 1, DEFDACBLKSIZE); | |||
sched_set_using_audio(SCHED_AUDIO_CALLBACK); | |||
sys_reopen_audio(); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_process_raw(const float *inBuffer, float *outBuffer) { | |||
size_t n_in = STUFF->st_inchannels * DEFDACBLKSIZE; | |||
size_t n_out = STUFF->st_outchannels * DEFDACBLKSIZE; | |||
t_sample *p; | |||
size_t i; | |||
sys_lock(); | |||
sys_microsleep(0); | |||
for (p = STUFF->st_soundin, i = 0; i < n_in; i++) { | |||
*p++ = *inBuffer++; | |||
} | |||
memset(STUFF->st_soundout, 0, n_out * sizeof(t_sample)); | |||
SCHED_TICK(pd_this->pd_systime + STUFF->st_time_per_dsp_tick); | |||
for (p = STUFF->st_soundout, i = 0; i < n_out; i++) { | |||
*outBuffer++ = *p++; | |||
} | |||
sys_unlock(); | |||
return 0; | |||
} | |||
static const t_sample sample_to_short = SHRT_MAX, | |||
short_to_sample = 1.0 / (t_sample) SHRT_MAX; | |||
#define PROCESS(_x, _y) \ | |||
int i, j, k; \ | |||
t_sample *p0, *p1; \ | |||
sys_lock(); \ | |||
sys_microsleep(0); \ | |||
for (i = 0; i < ticks; i++) { \ | |||
for (j = 0, p0 = STUFF->st_soundin; j < DEFDACBLKSIZE; j++, p0++) { \ | |||
for (k = 0, p1 = p0; k < STUFF->st_inchannels; k++, p1 += DEFDACBLKSIZE) \ | |||
{ \ | |||
*p1 = *inBuffer++ _x; \ | |||
} \ | |||
} \ | |||
memset(STUFF->st_soundout, 0, \ | |||
STUFF->st_outchannels*DEFDACBLKSIZE*sizeof(t_sample)); \ | |||
SCHED_TICK(pd_this->pd_systime + STUFF->st_time_per_dsp_tick); \ | |||
for (j = 0, p0 = STUFF->st_soundout; j < DEFDACBLKSIZE; j++, p0++) { \ | |||
for (k = 0, p1 = p0; k < STUFF->st_outchannels; k++, p1 += DEFDACBLKSIZE) \ | |||
{ \ | |||
*outBuffer++ = *p1 _y; \ | |||
} \ | |||
} \ | |||
} \ | |||
sys_unlock(); \ | |||
return 0; | |||
int libpd_process_short(const int ticks, const short *inBuffer, short *outBuffer) { | |||
PROCESS(* short_to_sample, * sample_to_short) | |||
} | |||
int libpd_process_float(const int ticks, const float *inBuffer, float *outBuffer) { | |||
PROCESS(,) | |||
} | |||
int libpd_process_double(const int ticks, const double *inBuffer, double *outBuffer) { | |||
PROCESS(,) | |||
} | |||
#define GETARRAY \ | |||
t_garray *garray = (t_garray *) pd_findbyclass(gensym(name), garray_class); \ | |||
if (!garray) {sys_unlock(); return -1;} \ | |||
int libpd_arraysize(const char *name) { | |||
int retval; | |||
sys_lock(); | |||
GETARRAY | |||
retval = garray_npoints(garray); | |||
sys_unlock(); | |||
return retval; | |||
} | |||
#define MEMCPY(_x, _y) \ | |||
GETARRAY \ | |||
if (n < 0 || offset < 0 || offset + n > garray_npoints(garray)) return -2; \ | |||
t_word *vec = ((t_word *) garray_vec(garray)) + offset; \ | |||
int i; \ | |||
for (i = 0; i < n; i++) _x = _y; | |||
int libpd_read_array(float *dest, const char *name, int offset, int n) { | |||
sys_lock(); | |||
MEMCPY(*dest++, (vec++)->w_float) | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_write_array(const char *name, int offset, const float *src, int n) { | |||
sys_lock(); | |||
MEMCPY((vec++)->w_float, *src++) | |||
sys_unlock(); | |||
return 0; | |||
} | |||
void libpd_set_float(t_atom *v, float x) { | |||
SETFLOAT(v, x); | |||
} | |||
void libpd_set_symbol(t_atom *v, const char *sym) { | |||
SETSYMBOL(v, gensym(sym)); | |||
} | |||
int libpd_list(const char *recv, int n, t_atom *v) { | |||
t_pd *dest; | |||
sys_lock(); | |||
dest = get_object(recv); | |||
if (dest == NULL) | |||
{ | |||
sys_unlock(); | |||
return -1; | |||
} | |||
pd_list(dest, &s_list, n, v); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_message(const char *recv, const char *msg, int n, t_atom *v) { | |||
t_pd *dest; | |||
sys_lock(); | |||
dest = get_object(recv); | |||
if (dest == NULL) | |||
{ | |||
sys_unlock(); | |||
return -1; | |||
} | |||
pd_typedmess(dest, gensym(msg), n, v); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_start_message(int max_length) { | |||
if (max_length > argm) { | |||
t_atom *v = realloc(argv, max_length * sizeof(t_atom)); | |||
if (v) { | |||
argv = v; | |||
argm = max_length; | |||
} else { | |||
return -1; | |||
} | |||
} | |||
argc = 0; | |||
curr = argv; | |||
return 0; | |||
} | |||
#define ADD_ARG(f) f(curr, x); curr++; argc++; | |||
void libpd_add_float(float x) { | |||
ADD_ARG(SETFLOAT); | |||
} | |||
void libpd_add_symbol(const char *s) { | |||
t_symbol *x; | |||
sys_lock(); | |||
x = gensym(s); | |||
sys_unlock(); | |||
ADD_ARG(SETSYMBOL); | |||
} | |||
int libpd_finish_list(const char *recv) { | |||
return libpd_list(recv, argc, argv); | |||
} | |||
int libpd_finish_message(const char *recv, const char *msg) { | |||
return libpd_message(recv, msg, argc, argv); | |||
} | |||
void *libpd_bind(const char *sym) { | |||
t_symbol *x; | |||
sys_lock(); | |||
x = gensym(sym); | |||
sys_unlock(); | |||
return libpdreceive_new(x); | |||
} | |||
void libpd_unbind(void *p) { | |||
sys_lock(); | |||
pd_free((t_pd *)p); | |||
sys_unlock(); | |||
} | |||
int libpd_is_float(t_atom *a) { | |||
return (a)->a_type == A_FLOAT; | |||
} | |||
int libpd_is_symbol(t_atom *a) { | |||
return (a)->a_type == A_SYMBOL; | |||
} | |||
float libpd_get_float(t_atom *a) { | |||
return (a)->a_w.w_float; | |||
} | |||
char *libpd_get_symbol(t_atom *a) { | |||
return (a)->a_w.w_symbol->s_name; | |||
} | |||
t_atom *libpd_next_atom(t_atom *a) { | |||
return a + 1; | |||
} | |||
void libpd_set_printhook(const t_libpd_printhook hook) { | |||
libpd_printhook = hook; | |||
} | |||
void libpd_set_banghook(const t_libpd_banghook hook) { | |||
libpd_banghook = hook; | |||
} | |||
void libpd_set_floathook(const t_libpd_floathook hook) { | |||
libpd_floathook = hook; | |||
} | |||
void libpd_set_symbolhook(const t_libpd_symbolhook hook) { | |||
libpd_symbolhook = hook; | |||
} | |||
void libpd_set_listhook(const t_libpd_listhook hook) { | |||
libpd_listhook = hook; | |||
} | |||
void libpd_set_messagehook(const t_libpd_messagehook hook) { | |||
libpd_messagehook = hook; | |||
} | |||
int libpd_symbol(const char *recv, const char *sym) { | |||
void *obj; | |||
sys_lock(); | |||
obj = get_object(recv); | |||
if (obj == NULL) | |||
{ | |||
sys_unlock(); | |||
return -1; | |||
} | |||
pd_symbol(obj, gensym(sym)); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_float(const char *recv, float x) { | |||
void *obj; | |||
sys_lock(); | |||
obj = get_object(recv); | |||
if (obj == NULL) | |||
{ | |||
sys_unlock(); | |||
return -1; | |||
} | |||
pd_float(obj, x); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_bang(const char *recv) { | |||
void *obj; | |||
sys_lock(); | |||
obj = get_object(recv); | |||
if (obj == NULL) | |||
{ | |||
sys_unlock(); | |||
return -1; | |||
} | |||
pd_bang(obj); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_blocksize(void) { | |||
return DEFDACBLKSIZE; | |||
} | |||
int libpd_exists(const char *sym) { | |||
int retval; | |||
sys_lock(); | |||
retval = (get_object(sym) != NULL); | |||
sys_unlock(); | |||
return retval; | |||
} | |||
#define CHECK_CHANNEL if (channel < 0) return -1; | |||
#define CHECK_PORT if (port < 0 || port > 0x0fff) return -1; | |||
#define CHECK_RANGE_7BIT(v) if (v < 0 || v > 0x7f) return -1; | |||
#define CHECK_RANGE_8BIT(v) if (v < 0 || v > 0xff) return -1; | |||
#define PORT (channel >> 4) | |||
#define CHANNEL (channel & 0x0f) | |||
int libpd_noteon(int channel, int pitch, int velocity) { | |||
CHECK_CHANNEL | |||
CHECK_RANGE_7BIT(pitch) | |||
CHECK_RANGE_7BIT(velocity) | |||
sys_lock(); | |||
inmidi_noteon(PORT, CHANNEL, pitch, velocity); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_controlchange(int channel, int controller, int value) { | |||
CHECK_CHANNEL | |||
CHECK_RANGE_7BIT(controller) | |||
CHECK_RANGE_7BIT(value) | |||
sys_lock(); | |||
inmidi_controlchange(PORT, CHANNEL, controller, value); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_programchange(int channel, int value) { | |||
CHECK_CHANNEL | |||
CHECK_RANGE_7BIT(value) | |||
sys_lock(); | |||
inmidi_programchange(PORT, CHANNEL, value); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_pitchbend(int channel, int value) { | |||
CHECK_CHANNEL | |||
if (value < -8192 || value > 8191) return -1; | |||
sys_lock(); | |||
inmidi_pitchbend(PORT, CHANNEL, value + 8192); | |||
sys_unlock(); | |||
// Note: For consistency with Pd, we center the output of [pitchin] | |||
// at 8192. | |||
return 0; | |||
} | |||
int libpd_aftertouch(int channel, int value) { | |||
CHECK_CHANNEL | |||
CHECK_RANGE_7BIT(value) | |||
sys_lock(); | |||
inmidi_aftertouch(PORT, CHANNEL, value); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_polyaftertouch(int channel, int pitch, int value) { | |||
CHECK_CHANNEL | |||
CHECK_RANGE_7BIT(pitch) | |||
CHECK_RANGE_7BIT(value) | |||
sys_lock(); | |||
inmidi_polyaftertouch(PORT, CHANNEL, pitch, value); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_midibyte(int port, int byte) { | |||
CHECK_PORT | |||
CHECK_RANGE_8BIT(byte) | |||
sys_lock(); | |||
inmidi_byte(port, byte); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_sysex(int port, int byte) { | |||
CHECK_PORT | |||
CHECK_RANGE_8BIT(byte) | |||
sys_lock(); | |||
inmidi_sysex(port, byte); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
int libpd_sysrealtime(int port, int byte) { | |||
CHECK_PORT | |||
CHECK_RANGE_8BIT(byte) | |||
sys_lock(); | |||
inmidi_realtimein(port, byte); | |||
sys_unlock(); | |||
return 0; | |||
} | |||
void libpd_set_noteonhook(const t_libpd_noteonhook hook) { | |||
libpd_noteonhook = hook; | |||
} | |||
void libpd_set_controlchangehook(const t_libpd_controlchangehook hook) { | |||
libpd_controlchangehook = hook; | |||
} | |||
void libpd_set_programchangehook(const t_libpd_programchangehook hook) { | |||
libpd_programchangehook = hook; | |||
} | |||
void libpd_set_pitchbendhook(const t_libpd_pitchbendhook hook) { | |||
libpd_pitchbendhook = hook; | |||
} | |||
void libpd_set_aftertouchhook(const t_libpd_aftertouchhook hook) { | |||
libpd_aftertouchhook = hook; | |||
} | |||
void libpd_set_polyaftertouchhook(const t_libpd_polyaftertouchhook hook) { | |||
libpd_polyaftertouchhook = hook; | |||
} | |||
void libpd_set_midibytehook(const t_libpd_midibytehook hook) { | |||
libpd_midibytehook = hook; | |||
} | |||
int libpd_start_gui(char *path) { | |||
int retval; | |||
sys_lock(); | |||
retval = sys_startgui(path); | |||
sys_unlock(); | |||
return retval; | |||
} | |||
void libpd_stop_gui(void) { | |||
sys_lock(); | |||
sys_stopgui(); | |||
sys_unlock(); | |||
} | |||
void libpd_poll_gui(void) { | |||
sys_lock(); | |||
sys_pollgui(); | |||
sys_unlock(); | |||
} | |||
t_pdinstance *libpd_new_instance(void) { | |||
#ifdef PDINSTANCE | |||
return pdinstance_new(); | |||
#else | |||
return 0; | |||
#endif | |||
} | |||
void libpd_set_instance(t_pdinstance *x) { | |||
#ifdef PDINSTANCE | |||
pd_setinstance(x); | |||
#endif | |||
} | |||
void libpd_free_instance(t_pdinstance *x) { | |||
#ifdef PDINSTANCE | |||
pdinstance_free(x); | |||
#endif | |||
} | |||
t_pdinstance *libpd_this_instance(void) { | |||
return pd_this; | |||
} | |||
t_pdinstance *libpd_get_instance(int index) { | |||
#ifdef PDINSTANCE | |||
if(index < 0 || index >= pd_ninstances) {return 0;} | |||
return pd_instances[index]; | |||
#else | |||
return pd_this; | |||
#endif | |||
} | |||
int libpd_num_instances(void) { | |||
#ifdef PDINSTANCE | |||
return pd_ninstances; | |||
#else | |||
return 1; | |||
#endif | |||
} | |||
void libpd_set_verbose(int verbose) { | |||
if (verbose < 0) verbose = 0; | |||
sys_verbose = verbose; | |||
} | |||
int libpd_get_verbose(void) { | |||
return sys_verbose; | |||
} | |||
// dummy routines needed because we don't use s_file.c | |||
void glob_loadpreferences(t_pd *dummy, t_symbol *s) {} | |||
void glob_savepreferences(t_pd *dummy, t_symbol *s) {} | |||
void glob_forgetpreferences(t_pd *dummy) {} | |||
void sys_loadpreferences(const char *filename, int startingup) {} | |||
int sys_oktoloadfiles(int done) {return 1;} | |||
void sys_savepreferences(const char *filename) {} // used in s_path.c |
@@ -0,0 +1,163 @@ | |||
/* | |||
* Copyright (c) 2010 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
* | |||
* See https://github.com/libpd/libpd/wiki for documentation | |||
* | |||
*/ | |||
#ifndef __Z_LIBPD_H__ | |||
#define __Z_LIBPD_H__ | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif | |||
#include "m_pd.h" | |||
EXTERN int libpd_init(void); | |||
EXTERN void libpd_clear_search_path(void); | |||
EXTERN void libpd_add_to_search_path(const char *sym); | |||
EXTERN void *libpd_openfile(const char *basename, const char *dirname); | |||
EXTERN void libpd_closefile(void *p); | |||
EXTERN int libpd_getdollarzero(void *p); | |||
EXTERN int libpd_blocksize(void); | |||
EXTERN int libpd_init_audio(int inChans, int outChans, int sampleRate); | |||
EXTERN int libpd_process_raw(const float *inBuffer, float *outBuffer); | |||
EXTERN int libpd_process_short(const int ticks, | |||
const short *inBuffer, short *outBuffer); | |||
EXTERN int libpd_process_float(const int ticks, | |||
const float *inBuffer, float *outBuffer); | |||
EXTERN int libpd_process_double(const int ticks, | |||
const double *inBuffer, double *outBuffer); | |||
EXTERN int libpd_arraysize(const char *name); | |||
// The parameters of the next two functions are inspired by memcpy. | |||
EXTERN int libpd_read_array(float *dest, const char *src, int offset, int n); | |||
EXTERN int libpd_write_array(const char *dest, int offset, const float *src, int n); | |||
EXTERN int libpd_bang(const char *recv); | |||
EXTERN int libpd_float(const char *recv, float x); | |||
EXTERN int libpd_symbol(const char *recv, const char *sym); | |||
EXTERN void libpd_set_float(t_atom *v, float x); | |||
EXTERN void libpd_set_symbol(t_atom *v, const char *sym); | |||
EXTERN int libpd_list(const char *recv, int argc, t_atom *argv); | |||
EXTERN int libpd_message(const char *recv, const char *msg, int argc, t_atom *argv); | |||
EXTERN int libpd_start_message(int max_length); | |||
EXTERN void libpd_add_float(float x); | |||
EXTERN void libpd_add_symbol(const char *sym); | |||
EXTERN int libpd_finish_list(const char *recv); | |||
EXTERN int libpd_finish_message(const char *recv, const char *msg); | |||
EXTERN int libpd_exists(const char *sym); | |||
EXTERN void *libpd_bind(const char *sym); | |||
EXTERN void libpd_unbind(void *p); | |||
EXTERN int libpd_is_float(t_atom *a); | |||
EXTERN int libpd_is_symbol(t_atom *a); | |||
EXTERN float libpd_get_float(t_atom *a); | |||
EXTERN char *libpd_get_symbol(t_atom *a); | |||
EXTERN t_atom *libpd_next_atom(t_atom *a); | |||
typedef void (*t_libpd_printhook)(const char *recv); | |||
typedef void (*t_libpd_banghook)(const char *recv); | |||
typedef void (*t_libpd_floathook)(const char *recv, float x); | |||
typedef void (*t_libpd_symbolhook)(const char *recv, const char *sym); | |||
typedef void (*t_libpd_listhook)(const char *recv, int argc, t_atom *argv); | |||
typedef void (*t_libpd_messagehook)(const char *recv, const char *msg, | |||
int argc, t_atom *argv); | |||
EXTERN void libpd_set_printhook(const t_libpd_printhook hook); | |||
EXTERN void libpd_set_banghook(const t_libpd_banghook hook); | |||
EXTERN void libpd_set_floathook(const t_libpd_floathook hook); | |||
EXTERN void libpd_set_symbolhook(const t_libpd_symbolhook hook); | |||
EXTERN void libpd_set_listhook(const t_libpd_listhook hook); | |||
EXTERN void libpd_set_messagehook(const t_libpd_messagehook hook); | |||
EXTERN int libpd_noteon(int channel, int pitch, int velocity); | |||
EXTERN int libpd_controlchange(int channel, int controller, int value); | |||
EXTERN int libpd_programchange(int channel, int value); | |||
EXTERN int libpd_pitchbend(int channel, int value); | |||
EXTERN int libpd_aftertouch(int channel, int value); | |||
EXTERN int libpd_polyaftertouch(int channel, int pitch, int value); | |||
EXTERN int libpd_midibyte(int port, int byte); | |||
EXTERN int libpd_sysex(int port, int byte); | |||
EXTERN int libpd_sysrealtime(int port, int byte); | |||
typedef void (*t_libpd_noteonhook)(int channel, int pitch, int velocity); | |||
typedef void (*t_libpd_controlchangehook)(int channel, | |||
int controller, int value); | |||
typedef void (*t_libpd_programchangehook)(int channel, int value); | |||
typedef void (*t_libpd_pitchbendhook)(int channel, int value); | |||
typedef void (*t_libpd_aftertouchhook)(int channel, int value); | |||
typedef void (*t_libpd_polyaftertouchhook)(int channel, int pitch, int value); | |||
typedef void (*t_libpd_midibytehook)(int port, int byte); | |||
EXTERN void libpd_set_noteonhook(const t_libpd_noteonhook hook); | |||
EXTERN void libpd_set_controlchangehook(const t_libpd_controlchangehook hook); | |||
EXTERN void libpd_set_programchangehook(const t_libpd_programchangehook hook); | |||
EXTERN void libpd_set_pitchbendhook(const t_libpd_pitchbendhook hook); | |||
EXTERN void libpd_set_aftertouchhook(const t_libpd_aftertouchhook hook); | |||
EXTERN void libpd_set_polyaftertouchhook(const t_libpd_polyaftertouchhook hook); | |||
EXTERN void libpd_set_midibytehook(const t_libpd_midibytehook hook); | |||
/// \section GUI | |||
/// open the current patches within a Pd vanilla GUI | |||
/// requires the path to Pd's main folder that contains bin/, tcl/, etc | |||
/// returns 0 on success | |||
EXTERN int libpd_start_gui(char *path); | |||
/// stop the Pd vanilla GUI | |||
EXTERN void libpd_stop_gui(void); | |||
/// update and handle any GUI messages | |||
EXTERN void libpd_poll_gui(void); | |||
/// \section Multiple Instances | |||
/// create a new pd instance | |||
/// returns 0 when libpd is not compiled with PDINSTANCE | |||
EXTERN t_pdinstance *libpd_new_instance(void); | |||
/// set the current pd instance, | |||
/// subsequent libpd calls will affect this instance only | |||
/// does nothing when libpd is not compiled with PDINSTANCE | |||
EXTERN void libpd_set_instance(t_pdinstance *x); | |||
/// free a pd instance | |||
/// does nothing when libpd is not compiled with PDINSTANCE | |||
EXTERN void libpd_free_instance(t_pdinstance *x); | |||
/// get the current pd instance | |||
EXTERN t_pdinstance *libpd_this_instance(void); | |||
/// get a pd instance by index | |||
/// returns 0 if index is out of bounds | |||
/// returns "this" instance when libpd is not compiled with PDINSTANCE | |||
EXTERN t_pdinstance *libpd_get_instance(int index); | |||
/// get the number of pd instances | |||
/// returns 1 when libpd is not compiled with PDINSTANCE | |||
EXTERN int libpd_num_instances(void); | |||
/// \section Log Level | |||
/// set verbose print state: 0 or 1 | |||
EXTERN void libpd_set_verbose(int verbose); | |||
/// get the verbose print state: 0 or 1 | |||
EXTERN int libpd_get_verbose(void); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif |
@@ -0,0 +1,12 @@ | |||
; see also https://github.com/erdc-cm/petsc-dev/blob/master/.dir-locals.el | |||
( | |||
(nil . ((indent-tabs-mode . nil) | |||
(tab-width . 4) | |||
(fill-column . 80))) | |||
;; Warn about spaces used for indentation: | |||
(c-mode . ((c-file-style . "bsd") | |||
(c-basic-offset . 4) | |||
(c-comment-only-line-offset . 4) | |||
)) | |||
(haskell-mode . ((eval . (highlight-regexp "^ *")))) | |||
(java-mode . ((c-file-style . "bsd")))) |
@@ -0,0 +1,261 @@ | |||
This file describes implementation and API changes; stuff more visible to the | |||
user appears in the "release notes" instead. See the bottom of this file | |||
for original notes on source style and organization. | |||
0.42.0 | |||
changed definition of t_float, t_sample, t_floatarg so that they can be | |||
set via #defines (PD_FLOATTYPE, etc). | |||
0.41.0 | |||
add support for callback-based audio I/O | |||
headers & code changed to use t_float or t_sample instead of float (patches | |||
by zmoelnig). | |||
0.40.0 | |||
0.39.0 | |||
canvas_dspstate and signalinlet_new() exported to m_pd.h | |||
new function verbose() added to m_pd.h | |||
0.38.0 | |||
finally figured out how to do "-enable-", etc., flags in the configure | |||
script correctly. | |||
The scheduler now has a hook (set_so you can add polling routines) : | |||
sys_idlehook(). | |||
I'm now uploading directly to CVS repository ("main" and "stable_0_38" | |||
branches.) There are still problems keeping CVS's and my versions of | |||
portaudio the same (CVS bashes the "ident" lines). | |||
t_int to int in binbuf_addv prototype | |||
64-bit fix to externs makefiles | |||
Pd now uses portaudio out-of-the-box; customized files are moved to | |||
"src" directory. | |||
All "tags" are printf'd as %lx to make 64-bit safe. | |||
GUI queueing mechanism added: sys_queuegui() etc. | |||
massive rewrite of array code to unify arrays and scalars. | |||
fixed empty lists automatically to call "bang" method if one is supplied. | |||
rewrote the "namelist" stuff to facilitate preference saving (s_stuff.h, | |||
s_path.c, s_file.c, s_main.c) | |||
0.37.2 | |||
expr() "exp" temporary variables renamed to avoid compilation problems | |||
0.37.1 | |||
makefile.in: MANINSTDIR = $(DESTDIR)/$(MANDIR) changed to | |||
$(DESTDIR)/$(INSTALL_PREFIX)/$(MANDIR) (thx. Mathieu Bouchard) | |||
applied 2 jack patches from Luke Yelavich | |||
add -fno-strict-aliasing to config script (linux&mac) to improve underflow, | |||
etc., protection | |||
add underflow protection to vcf~ object; rewrote underflow protection to be | |||
faster in throw~/catch~ and send~/receive~ | |||
fixed bug in -inchannels/-outchannels arg parsing | |||
fixed u_main.tk to make "apple" key work to accelerate menus on MACOS | |||
fooled with MIDI to try to get sysex and other system messages to work. | |||
Needs lots of testing now... | |||
finally fixed OSS to open audio with NODELAY... also cleared dup-on-exec flag. | |||
bug fix in scalar_properties | |||
major editions to the IEM GUIs to fix bugs in how "$" variables are handled. | |||
The code still isn't pretty but hopefully at least works now. | |||
tried to get alsa noninterleaved access to work (needed for RME). Failed | |||
to get my RME card to load under ALSA and gave up for now. | |||
fixed scalar drawing to fail gracefully when the template canvas disappears | |||
bug fix in vd~ for very small delays (d_delay.c) | |||
set up sys_oldtclversion flag to correct for changed text selection | |||
(u_main.tk, s_main.c, g_rtext.c) | |||
tried again to add "readn" support to s_audio_alsa.c: coded, but failing so far. | |||
fixed broken octave divider example | |||
removed "-Werror" from default makefile; fixed configure script to respect | |||
"CFLAGS" environment variable instead. Suggest developers should use | |||
"setenv CFLAGS -Werror". | |||
added "-alsaadd" flag so people can specify alsa devnames to add to list. | |||
fixed some problems with Pd crashing when ALSA failed to open. | |||
took out the 2-pixel padding for MSW in g_canvas.g (HORIZBORDER/VERTBORDER) | |||
went back to s_midi_mmio (portaudio version got assertion errors and anyway | |||
I could never get sysex working in it as I had wanted.) | |||
Took bug fixes from s_midi_pm.c, s_audio_jack.c, s_inter.c from "devel" branch; | |||
also added "static" flag to configure.in (but the devel configure.in as a whole | |||
doesn't seem to work for OSX, for me at least.) | |||
Might have fixed a bug where labels disappear in buttons, etc, when saved | |||
and reloaded. | |||
brought s_audio_alsa.c up to alsa 1.0.0 compatibility | |||
fixed "-alsaadd" (never worked before) | |||
fooled with macintosh audio. Fixed some (not all) of the audio I/O APIs | |||
to deal with open failures better (reducing sys_{in,out}channels accordingly) | |||
In the Alsa API, the synchronization test was too stringent and was loosened | |||
to 3*DACBLKSIZE/2. | |||
'make install' fixed to deal with 'extra' correctly. | |||
one more improvement in jack support (guenter) | |||
make an "nrt" flag so mac can disable pthread_setschedparam call if yu want. | |||
------------------- original source notes ------------- | |||
0. structure definition roadmap. First, the containment tree of things | |||
that can be sent messages ("pure data"). (note that t_object and t_text, | |||
and t_graph and t_canvas, should be unified...) | |||
------------ BFFORE 0.35: --------- | |||
m_pd.h t_pd anything with a class | |||
t_gobj "graphic object" | |||
t_text text object | |||
g_canvas.h | |||
t_glist list of graphic objects | |||
g_canvas.c t_canvas Pd "document" | |||
------------ AFTER 0.35: --------- | |||
m_pd.h t_pd anything with a class | |||
t_gobj "graphic object" | |||
t_text patchable object, AKA t_object | |||
g_canvas.h t_glist list of graphic objects, AKA t_canvas | |||
... and other structures: | |||
g_canvas.h t_selection -- linked list of gobjs | |||
t_editor -- editor state, allocated for visible glists | |||
m_imp.h t_methodentry -- method handler | |||
t_widgetbehavior -- class-dependent editing behavior for gobjs | |||
t_parentwidgetbehavior -- objects' behavior on parent window | |||
t_class -- method definitions, instance size, flags, etc. | |||
1. C coding style. The source should pass most "warnings" of C compilers | |||
(-Wall on linux, for instance; see the makefile.) Some informalities | |||
are intentional, for instance the loose use of function prototypes (see | |||
below) and uncast conversions from longer to shorter numerical formats. | |||
The code doesn't respect "const" yet. | |||
1.1. Prefixes in structure elements. The names of structure elements always | |||
have a K&R-style prefix, as in ((t_atom)x)->a_type, where the "a_" prefix | |||
indicates "atom." This is intended to enhance readability (although the | |||
convention arose from a limitation of early C compilers.) Common prefixes are | |||
"w_" (word), "a_" (atom), "s_" (symbol), "ob_" (object), "te_" (text object), | |||
"g_" (graphical object), and "gl_" (glist, a list of graphical objects). Also, | |||
global symbols sometimes get prefixes, as in "s_float" (the symbol whose string | |||
is "float). Typedefs are prefixed by "t_". Most _private_ structures, i.e., | |||
structures whose definitions appear in a ".c" file, are prefixed by "x_". | |||
1.2. Function arguments. Many functions take as their first | |||
argument a pointer named "x", which is a pointer to a structure suggested | |||
by the function prefix; e.g., canvas_dirty(x, n) where "x" points to a canvas | |||
(t_canvas *x). | |||
1.3. Function Prototypes. Functions which are used in at least two different | |||
files (besides where they originate) are prototyped in the appropriate include | |||
file. Functions which are provided in one file and used in one other are | |||
prototyped right where they are used. This is just to keep the size of the | |||
".h" files down for readability's sake. | |||
1.4. Whacko private terminology. Some terms are lifted from other historically | |||
relevant programs, notably "ugen" (which is just a tilde object; see d_ugen.c.) | |||
1.5. Spacing. Tabs are 8 spaces; indentation is 4 spaces. Indenting | |||
curly brackets are by themselves on their own lines, as in: | |||
if (x) | |||
{ | |||
x = 0; | |||
} | |||
Lines should fit within 80 spaces. | |||
2. Max patch-level compatibility. "Import" and "Export" functions are | |||
provided which aspire to strict compatibility with 0.26 patches (ISPW version), | |||
but which don't get anywhere close to that yet. Where possible, features | |||
appearing on the Mac will comeday also be provided; for instance, the connect | |||
message on the Mac offers segmented patch cords; these will devolve into | |||
straight lines in Pd. Many, many UI objects in Opcode Max will not appear in | |||
Pd, at least at first. | |||
3. Compatibility with Max 0.26 "externs", i.e., source-level compatibility. Pd | |||
objects follow the style of 0.26 objects as closely as possible, making | |||
exceptions in cases where the 0.26 model is clearly deficient. These are: | |||
3.1. Anything involving the MacIntosh "Handle" data type is changed to use | |||
char * or void * instead. | |||
3.2. Pd passes true single-precision floating-point arguments to methods; | |||
Max uses double. | |||
Typedefs are provided: | |||
t_floatarg, t_intarg for arguments passed by the message system | |||
t_float, t_int for the "word" union (in atoms, for example.) | |||
3.3. Badly-named entities got name changes: | |||
w_long --> w_int (in the "union word" structure) | |||
3.4. Many library functions are renamed and have different arguments; | |||
I hope to provide an include file to alias them when compiling Max externs. | |||
4. Function name prefixes. | |||
Many function names have prefixes which indicate what "package" they belong | |||
to. The exceptions are: | |||
typedmess, vmess, getfn, gensym (m_class.c) | |||
getbytes, freebytes, resizebytes (m_memory.c) | |||
post, error, bug (s_print.c) | |||
which are all frequently called and which don't fit into simple categories. | |||
Important packages are: | |||
(pd-gui:) pdgui -- everything | |||
(pd:) pd -- functions common to all "pd" objects | |||
obj -- fuctions common to all "patchable" objects ala Max | |||
sys -- "system" level functions | |||
binbuf -- functions manipulating binbufs | |||
class -- functions manipulating classes | |||
(other) -- functions common to the named Pd class | |||
5. Source file prefixes. | |||
PD: | |||
s system interface | |||
m message system | |||
g graphics stuff | |||
d DSP objects | |||
x control objects | |||
z other | |||
PD-GUI: | |||
t TK front end | |||
@@ -0,0 +1,409 @@ | |||
######################################### | |||
##### Defaults & Paths ##### | |||
AUTOMAKE_OPTIONS = foreign | |||
CLEANFILES= | |||
bin_SCRIPTS = | |||
noinst_SCRIPTS = | |||
pd_CFLAGS = -DPD -DINSTALL_PREFIX=\"$(prefix)\" -DPD_INTERNAL | |||
pd_LDFLAGS = | |||
pd_LDADD = | |||
# there are pd_* and pd_*_core variables as we need different flags on Windows | |||
# for the DLL and the EXE, other OSes simply set pd_* = $(pd_*_core) later | |||
# also, the "_core" suffix is used as this keeps automake from thinking these | |||
# are library or binary variables since we only need them as placeholders | |||
pd_LDFLAGS_core = | |||
pd_LDADD_core = | |||
pdsend_CFLAGS = | |||
pdreceive_CFLAGS = | |||
pd_watchdog_CFLAGS = | |||
LIBS = @LIBS@ | |||
SUFFIXES = .@EXTENSION@ .@SHARED_LIB@ | |||
######################################### | |||
##### Files, Binaries, & Libs ##### | |||
# pd core & utils | |||
bin_PROGRAMS = pd pdsend pdreceive | |||
pdsend_SOURCES = u_pdsend.c | |||
pdreceive_SOURCES = u_pdreceive.c | |||
pd_watchdog_SOURCES = s_watchdog.c | |||
# on Windows, pd.exe contains only s_entry.c and links against pd.dll | |||
# (where all the logic resides), that's why we have to split the sources | |||
# (only to later merge them again for non-Windows systems) | |||
pd_SOURCES = s_entry.c | |||
pd_SOURCES_core = \ | |||
d_arithmetic.c \ | |||
d_array.c \ | |||
d_ctl.c \ | |||
d_dac.c \ | |||
d_delay.c \ | |||
d_fft.c \ | |||
d_filter.c \ | |||
d_global.c \ | |||
d_math.c \ | |||
d_misc.c \ | |||
d_osc.c \ | |||
d_resample.c \ | |||
d_soundfile.c \ | |||
d_ugen.c \ | |||
g_all_guis.c \ | |||
g_array.c \ | |||
g_bang.c \ | |||
g_canvas.c \ | |||
g_clone.c \ | |||
g_editor.c \ | |||
g_graph.c \ | |||
g_guiconnect.c \ | |||
g_hdial.c \ | |||
g_hslider.c \ | |||
g_io.c \ | |||
g_mycanvas.c \ | |||
g_numbox.c \ | |||
g_readwrite.c \ | |||
g_rtext.c \ | |||
g_scalar.c \ | |||
g_template.c \ | |||
g_text.c \ | |||
g_toggle.c \ | |||
g_traversal.c \ | |||
g_vdial.c \ | |||
g_vslider.c \ | |||
g_vumeter.c \ | |||
m_atom.c \ | |||
m_binbuf.c \ | |||
m_class.c \ | |||
m_conf.c \ | |||
m_glob.c \ | |||
m_memory.c \ | |||
m_obj.c \ | |||
m_pd.c \ | |||
m_sched.c \ | |||
s_audio.c \ | |||
s_file.c \ | |||
s_inter.c \ | |||
s_loader.c \ | |||
s_main.c \ | |||
s_midi.c \ | |||
s_path.c \ | |||
s_print.c \ | |||
s_utf8.c \ | |||
x_acoustics.c \ | |||
x_arithmetic.c \ | |||
x_array.c \ | |||
x_connective.c \ | |||
x_gui.c \ | |||
x_interface.c \ | |||
x_list.c \ | |||
x_midi.c \ | |||
x_misc.c \ | |||
x_net.c \ | |||
x_scalar.c \ | |||
x_text.c \ | |||
x_time.c \ | |||
x_vexp.c \ | |||
x_vexp_fun.c \ | |||
x_vexp_if.c | |||
# pd-watchdog and "local" pd symlink location for tcl scripts | |||
libpdbindir = $(pkglibdir)/bin | |||
# these install to ${includedir}/pd | |||
pkginclude_HEADERS = m_pd.h m_imp.h g_canvas.h s_stuff.h g_all_guis.h x_vexp.h | |||
# compatibility: m_pd.h also goes into ${includedir}/ | |||
include_HEADERS = m_pd.h | |||
noinst_HEADERS = g_all_guis.h s_audio_alsa.h s_audio_paring.h s_utf8.h x_vexp.h | |||
# we want these in the dist tarball | |||
EXTRA_DIST = CHANGELOG.txt notes.txt pd.ico pd.rc \ | |||
makefile.gnu makefile.mac makefile.mingw makefile.msvc \ | |||
s_audio_audiounit.c s_audio_esd.c | |||
# add WISH define if it's set | |||
WISH=@WISH@ | |||
WISHDEFINE=$(if $(WISH),-DWISH='"$(WISH)"') | |||
pd_CFLAGS += $(WISHDEFINE) | |||
######################################### | |||
##### Configurations Per Library ##### | |||
##### Advanced Linux Sound Architecture ##### | |||
if ALSA | |||
pd_CFLAGS += -DUSEAPI_ALSA | |||
pd_LDADD_core += @ALSA_LIBS@ | |||
pd_SOURCES_core += s_audio_alsa.c s_audio_alsamm.c s_midi_alsa.c | |||
endif | |||
##### OSX CoreAudio ##### | |||
# needed by PortAudio on OSX | |||
if COREAUDIO | |||
LIBS += -framework CoreAudio -framework CoreMIDI \ | |||
-framework AudioUnit -framework AudioToolbox | |||
endif | |||
##### Jack Audio Connection Kit ##### | |||
# TODO support Jack xrun | |||
if JACK | |||
pd_CFLAGS += -DUSEAPI_JACK -DJACK_XRUN | |||
pd_SOURCES_core += s_audio_jack.c | |||
if JACK_FRAMEWORK | |||
# link to Jackmp.framework on macOS | |||
pd_LDFLAGS_core += -weak_framework Jackmp | |||
else | |||
# link to Jack discovered by configure | |||
pd_LDADD_core += @JACK_LIBS@ | |||
endif | |||
endif | |||
##### GNU/Linux Open Sound System ##### | |||
if OSS | |||
pd_CFLAGS += -DUSEAPI_OSS | |||
pd_SOURCES_core += s_audio_oss.c s_midi_oss.c | |||
endif | |||
##### Windows MultiMedia (File) I/O ##### | |||
if MMIO | |||
pd_CFLAGS += -DUSEAPI_MMIO | |||
pd_SOURCES_core += s_audio_mmio.c | |||
endif | |||
##### PortAudio ##### | |||
if PORTAUDIO | |||
pd_CFLAGS += -DUSEAPI_PORTAUDIO | |||
pd_SOURCES_core += s_audio_pa.c s_audio_paring.c | |||
if LOCAL_PORTAUDIO | |||
# link the included portaudio which is built as a static lib | |||
AM_CPPFLAGS += -I$(top_srcdir)/portaudio/portaudio/include | |||
pd_LDADD_core += $(top_builddir)/portaudio/libportaudio.a | |||
else | |||
# link the system's portaudio | |||
pd_LDADD_core += -lportaudio | |||
endif | |||
# need Carbon framework for PA on Mac | |||
if MACOSX | |||
LIBS += -framework Carbon | |||
endif | |||
endif | |||
##### ASIO ##### | |||
# ASIO needs to go after PORTAUDIO in order for it to link properly | |||
if ASIO | |||
# always Windows | |||
pd_LDADD_core += $(top_builddir)/asio/libasio.a | |||
endif | |||
##### PortMidi ##### | |||
if PORTMIDI | |||
pd_SOURCES_core += s_midi_pm.c | |||
if LOCAL_PORTMIDI | |||
# link the included portmidi which is built as a static lib | |||
AM_CPPFLAGS += \ | |||
-I$(top_srcdir)/portmidi/portmidi/pm_common \ | |||
-I$(top_srcdir)/portmidi/portmidi/porttime | |||
pd_LDADD_core += $(top_builddir)/portmidi/libportmidi.a | |||
else | |||
# link the system's portmidi | |||
pd_LDADD_core += -lportmidi | |||
endif | |||
# need Carbon framework for PM on Mac | |||
if MACOSX | |||
LIBS += -framework CoreFoundation -framework Carbon | |||
endif | |||
endif | |||
##### NO API? ##### | |||
# if no audio or midi api was detected/specified, fall back to dummy apis | |||
# ie. GNU/HURD, IPHONEOS, ... have no MIDI (not even OSS) | |||
if AUDIO_DUMMY | |||
pd_CFLAGS += -DUSEAPI_DUMMY | |||
pd_SOURCES_core += s_audio_dummy.c | |||
endif | |||
if MIDI_DUMMY | |||
pd_CFLAGS += -DUSEAPI_MIDIDUMMY | |||
pd_SOURCES_core += s_midi_dummy.c | |||
endif | |||
##### FFTW fft library ##### | |||
if FFTW | |||
pd_SOURCES_core += d_fft_fftw.c | |||
else | |||
pd_SOURCES_core += d_fft_fftsg.c | |||
endif | |||
######################################### | |||
##### Configurations Per Platform ##### | |||
##### GNU/Hurd ##### | |||
if HURD | |||
# install watchdog to $(libdir)/pd/bin as it's not a user facing program | |||
libpdbin_PROGRAMS = pd-watchdog | |||
# this flag has to have a single leading "-" for libtool, even though ld uses | |||
# --export-dynamic, and libtool sends -Wl,--export-dynamic to ld... | |||
pd_LDFLAGS_core += -export-dynamic | |||
# on Ubuntu/Karmic 9.10, it doesn't seem to find libm, so force it | |||
pd_LDFLAGS_core += $(LIBM) | |||
# force linking to pthread, which should really be done with some autotools way | |||
pd_LDFLAGS_core += -lpthread | |||
# force linking to dl, which should really be done with some autotools way | |||
pd_LDFLAGS_core += -ldl | |||
endif | |||
##### GNU/Linux ##### | |||
if LINUX | |||
# install watchdog to $(libdir)/pd/bin as it's not a user facing program | |||
libpdbin_PROGRAMS = pd-watchdog | |||
# this flag has to have a single leading "-" for libtool, even though ld uses | |||
# --export-dynamic, and libtool sends -Wl,--export-dynamic to ld... | |||
pd_LDFLAGS_core += -export-dynamic | |||
# on Ubuntu/Karmic 9.10, it doesn't seem to find libm, so force it | |||
pd_LDFLAGS_core += $(LIBM) | |||
endif | |||
##### Apple Mac OSX ##### | |||
if MACOSX | |||
# install watchdog to $(libdir)/pd/bin as it's not a user facing program | |||
libpdbin_PROGRAMS = pd-watchdog | |||
# kludge, should use auto macro __APPLE__ | |||
# but who knows what externals rely on this | |||
pd_CFLAGS += -DMACOSX | |||
# for dynamic loading & threading | |||
LIBS += -ldl -lm -lpthread | |||
endif | |||
##### Windows ##### | |||
if WINDOWS | |||
# win32 sockets, multimedia, and all that | |||
LIBS += -lwsock32 -lwinmm -lole32 -static-libgcc -static-libstdc++ | |||
bin_SCRIPTS += pd.dll pd.lib pd.def pd.com | |||
CLEANFILES += pd.dll pd.lib pd.def pd.com | |||
noinst_SCRIPTS += libpd.a | |||
CLEANFILES += libpd.a | |||
CLEANFILES += pd.res | |||
# hide the console | |||
pd_LDFLAGS += -mwindows | |||
# link with ressources and pd.dll import library | |||
pd_LDADD += pd.res pd.lib | |||
pd_OBJECTS_core = $(pd_SOURCES_core:.c=.o) | |||
# the variables are taken from the automake Makefile | |||
$(pd_OBJECTS_core) : %.o : %.c | |||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ | |||
$(AM_CPPFLAGS) $(CPPFLAGS) $(pd_CFLAGS) $(CFLAGS) -c -o $@ $< | |||
pd.res: pd.rc | |||
$(WINDRES) $< -O coff -o $@ | |||
# import library for pd.dll. also works with MSVC! | |||
pd.lib: pd.dll | |||
# another import library (when linking with -lpd), the same as pd.lib. | |||
libpd.a: pd.lib | |||
cp $< $@ | |||
pd.def: pd.dll | |||
pd.dll: $(pd_OBJECTS_core) | |||
$(CXX) -shared $(pd_LDFLAGS_core) -o pd.dll \ | |||
$(pd_OBJECTS_core) $(pd_LDADD_core) $(LIBS) \ | |||
-Wl,--export-all-symbols -Wl,--out-implib=pd.lib -Wl,--output-def=pd.def | |||
# same as pd.exe but without -mwindows and resources | |||
# NOTE: this is a bit ugly. I couldn't figure out how to get automake to build | |||
# two programs with the same basename but different suffix. | |||
pd.com: pd-s_entry.o pd.lib | |||
$(CXX) $(LDFLAGS) -o pd.com pd-s_entry.o $(LIBS) pd.lib | |||
else | |||
# for other OS, join pd_* with pd_*_core | |||
pd_SOURCES += $(pd_SOURCES_core) | |||
pd_LDADD += $(pd_LDADD_core) | |||
pd_LDFLAGS += $(pd_LDFLAGS_core) | |||
endif | |||
##### Windows MinGW ##### | |||
if MINGW | |||
# To use SetDllDirectory() in s_loader.c, we need a minimum of Windows | |||
# XP SP1. WINVER isnt' fine-grained enough for that, so we use the | |||
# next minor version of Windows, 5.2. That gives us -DWINVER=0x0502 | |||
pd_CFLAGS += -DWINVER=0x0502 -D_WIN32_WINNT=0x0502 | |||
endif | |||
######################################### | |||
##### Targets ##### | |||
.PHONY: convenience-links | |||
all-local: convenience-links | |||
# create a bin folder & symlinks to the binaries in order to | |||
# replicate the src/makefile.* build result | |||
convenience-links: $(libpdbin_PROGRAMS) $(bin_PROGRAMS) | |||
$(MKDIR_P) $(top_builddir)/bin | |||
rm -rf $(top_builddir)/bin/pd* | |||
$(LN_S) $(top_builddir)/src/pd$(EXEEXT) $(top_builddir)/bin/pd$(EXEEXT) | |||
$(LN_S) $(top_builddir)/src/pdsend$(EXEEXT) $(top_builddir)/bin/pdsend$(EXEEXT) | |||
$(LN_S) $(top_builddir)/src/pdreceive$(EXEEXT) $(top_builddir)/bin/pdreceive$(EXEEXT) | |||
$(LN_S) $(top_srcdir)/tcl/pd-gui.in $(top_builddir)/bin/pd-gui | |||
test -e $(top_builddir)/src/pd-watchdog$(EXEEXT) && $(LN_S) $(top_builddir)/src/pd-watchdog$(EXEEXT) $(top_builddir)/bin/pd-watchdog$(EXEEXT) || true | |||
clean-local: | |||
rm -rf $(top_builddir)/bin | |||
# link to $(libdir)/pd/bin so the tcl scripts can | |||
# launch the core if the gui is started first | |||
# | |||
# We have to make the dir just in case as it may not exist yet & | |||
# we remove any existing symlink if doing a repeated install. | |||
install-exec-hook: | |||
$(MKDIR_P) $(DESTDIR)$(libpdbindir) | |||
rm -f $(DESTDIR)$(libpdbindir)/pd | |||
$(LN_S) $(DESTDIR)$(bindir)/pd $(DESTDIR)$(libpdbindir)/pd | |||
# remove the $(libdir)/pd/bin link | |||
# & | |||
# remove the leftover $(includedir)/pd dir, fail silently on any non-empty dirs | |||
# | |||
# The "|| true" ensures that if the dir is *not* empty, then rmdir does not throw | |||
# an error and stop make. | |||
uninstall-hook: | |||
rm -f $(DESTDIR)$(libpdbindir)/pd | |||
if test -d $(DESTDIR)$(pkgincludedir) ; then \ | |||
rmdir $(DESTDIR)$(pkgincludedir) 2>/dev/null || true ; \ | |||
fi | |||
# generate Emacs tags | |||
etags: TAGS | |||
etags --append --language=none --regex="/proc[ \t]+\([^ \t]+\)/\1/" *.tcl |
@@ -0,0 +1,843 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* arithmetic binops (+, -, *, /). | |||
If no creation argument is given, there are two signal inlets for vector/vector | |||
operation; otherwise it's vector/scalar and the second inlet takes a float | |||
to reset the value. | |||
*/ | |||
#include "m_pd.h" | |||
/* ----------------------------- plus ----------------------------- */ | |||
static t_class *plus_class, *scalarplus_class; | |||
typedef struct _plus | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_plus; | |||
typedef struct _scalarplus | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
t_float x_g; /* inlet value */ | |||
} t_scalarplus; | |||
static void *plus_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
if (argc > 1) post("+~: extra arguments ignored"); | |||
if (argc) | |||
{ | |||
t_scalarplus *x = (t_scalarplus *)pd_new(scalarplus_class); | |||
floatinlet_new(&x->x_obj, &x->x_g); | |||
x->x_g = atom_getfloatarg(0, argc, argv); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
else | |||
{ | |||
t_plus *x = (t_plus *)pd_new(plus_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
} | |||
t_int *plus_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) *out++ = *in1++ + *in2++; | |||
return (w+5); | |||
} | |||
t_int *plus_perf8(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) | |||
{ | |||
t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; | |||
t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; | |||
t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; | |||
t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; | |||
out[0] = f0 + g0; out[1] = f1 + g1; out[2] = f2 + g2; out[3] = f3 + g3; | |||
out[4] = f4 + g4; out[5] = f5 + g5; out[6] = f6 + g6; out[7] = f7 + g7; | |||
} | |||
return (w+5); | |||
} | |||
t_int *scalarplus_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float f = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) *out++ = *in++ + f; | |||
return (w+5); | |||
} | |||
t_int *scalarplus_perf8(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float g = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; | |||
t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; | |||
out[0] = f0 + g; out[1] = f1 + g; out[2] = f2 + g; out[3] = f3 + g; | |||
out[4] = f4 + g; out[5] = f5 + g; out[6] = f6 + g; out[7] = f7 + g; | |||
} | |||
return (w+5); | |||
} | |||
void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n) | |||
{ | |||
if (n&7) | |||
dsp_add(plus_perform, 4, in1, in2, out, n); | |||
else | |||
dsp_add(plus_perf8, 4, in1, in2, out, n); | |||
} | |||
static void plus_dsp(t_plus *x, t_signal **sp) | |||
{ | |||
dsp_add_plus(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
} | |||
static void scalarplus_dsp(t_scalarplus *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(scalarplus_perform, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(scalarplus_perf8, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void plus_setup(void) | |||
{ | |||
plus_class = class_new(gensym("+~"), (t_newmethod)plus_new, 0, | |||
sizeof(t_plus), 0, A_GIMME, 0); | |||
class_addmethod(plus_class, (t_method)plus_dsp, gensym("dsp"), A_CANT, 0); | |||
CLASS_MAINSIGNALIN(plus_class, t_plus, x_f); | |||
class_sethelpsymbol(plus_class, gensym("sigbinops")); | |||
scalarplus_class = class_new(gensym("+~"), 0, 0, | |||
sizeof(t_scalarplus), 0, 0); | |||
CLASS_MAINSIGNALIN(scalarplus_class, t_scalarplus, x_f); | |||
class_addmethod(scalarplus_class, (t_method)scalarplus_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(scalarplus_class, gensym("sigbinops")); | |||
} | |||
/* ----------------------------- minus ----------------------------- */ | |||
static t_class *minus_class, *scalarminus_class; | |||
typedef struct _minus | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_minus; | |||
typedef struct _scalarminus | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
t_float x_g; | |||
} t_scalarminus; | |||
static void *minus_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
if (argc > 1) post("-~: extra arguments ignored"); | |||
if (argc) | |||
{ | |||
t_scalarminus *x = (t_scalarminus *)pd_new(scalarminus_class); | |||
floatinlet_new(&x->x_obj, &x->x_g); | |||
x->x_g = atom_getfloatarg(0, argc, argv); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
else | |||
{ | |||
t_minus *x = (t_minus *)pd_new(minus_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
} | |||
t_int *minus_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) *out++ = *in1++ - *in2++; | |||
return (w+5); | |||
} | |||
t_int *minus_perf8(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) | |||
{ | |||
t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; | |||
t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; | |||
t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; | |||
t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; | |||
out[0] = f0 - g0; out[1] = f1 - g1; out[2] = f2 - g2; out[3] = f3 - g3; | |||
out[4] = f4 - g4; out[5] = f5 - g5; out[6] = f6 - g6; out[7] = f7 - g7; | |||
} | |||
return (w+5); | |||
} | |||
t_int *scalarminus_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float f = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) *out++ = *in++ - f; | |||
return (w+5); | |||
} | |||
t_int *scalarminus_perf8(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float g = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; | |||
t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; | |||
out[0] = f0 - g; out[1] = f1 - g; out[2] = f2 - g; out[3] = f3 - g; | |||
out[4] = f4 - g; out[5] = f5 - g; out[6] = f6 - g; out[7] = f7 - g; | |||
} | |||
return (w+5); | |||
} | |||
static void minus_dsp(t_minus *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(minus_perform, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(minus_perf8, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
} | |||
static void scalarminus_dsp(t_scalarminus *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(scalarminus_perform, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(scalarminus_perf8, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void minus_setup(void) | |||
{ | |||
minus_class = class_new(gensym("-~"), (t_newmethod)minus_new, 0, | |||
sizeof(t_minus), 0, A_GIMME, 0); | |||
CLASS_MAINSIGNALIN(minus_class, t_minus, x_f); | |||
class_addmethod(minus_class, (t_method)minus_dsp, gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(minus_class, gensym("sigbinops")); | |||
scalarminus_class = class_new(gensym("-~"), 0, 0, | |||
sizeof(t_scalarminus), 0, 0); | |||
CLASS_MAINSIGNALIN(scalarminus_class, t_scalarminus, x_f); | |||
class_addmethod(scalarminus_class, (t_method)scalarminus_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(scalarminus_class, gensym("sigbinops")); | |||
} | |||
/* ----------------------------- times ----------------------------- */ | |||
static t_class *times_class, *scalartimes_class; | |||
typedef struct _times | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_times; | |||
typedef struct _scalartimes | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
t_float x_g; | |||
} t_scalartimes; | |||
static void *times_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
if (argc > 1) post("*~: extra arguments ignored"); | |||
if (argc) | |||
{ | |||
t_scalartimes *x = (t_scalartimes *)pd_new(scalartimes_class); | |||
floatinlet_new(&x->x_obj, &x->x_g); | |||
x->x_g = atom_getfloatarg(0, argc, argv); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
else | |||
{ | |||
t_times *x = (t_times *)pd_new(times_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
} | |||
t_int *times_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) *out++ = *in1++ * *in2++; | |||
return (w+5); | |||
} | |||
t_int *times_perf8(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) | |||
{ | |||
t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; | |||
t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; | |||
t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; | |||
t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; | |||
out[0] = f0 * g0; out[1] = f1 * g1; out[2] = f2 * g2; out[3] = f3 * g3; | |||
out[4] = f4 * g4; out[5] = f5 * g5; out[6] = f6 * g6; out[7] = f7 * g7; | |||
} | |||
return (w+5); | |||
} | |||
t_int *scalartimes_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float f = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) *out++ = *in++ * f; | |||
return (w+5); | |||
} | |||
t_int *scalartimes_perf8(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float g = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; | |||
t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; | |||
out[0] = f0 * g; out[1] = f1 * g; out[2] = f2 * g; out[3] = f3 * g; | |||
out[4] = f4 * g; out[5] = f5 * g; out[6] = f6 * g; out[7] = f7 * g; | |||
} | |||
return (w+5); | |||
} | |||
static void times_dsp(t_times *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(times_perform, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(times_perf8, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
} | |||
static void scalartimes_dsp(t_scalartimes *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(scalartimes_perform, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(scalartimes_perf8, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void times_setup(void) | |||
{ | |||
times_class = class_new(gensym("*~"), (t_newmethod)times_new, 0, | |||
sizeof(t_times), 0, A_GIMME, 0); | |||
CLASS_MAINSIGNALIN(times_class, t_times, x_f); | |||
class_addmethod(times_class, (t_method)times_dsp, gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(times_class, gensym("sigbinops")); | |||
scalartimes_class = class_new(gensym("*~"), 0, 0, | |||
sizeof(t_scalartimes), 0, 0); | |||
CLASS_MAINSIGNALIN(scalartimes_class, t_scalartimes, x_f); | |||
class_addmethod(scalartimes_class, (t_method)scalartimes_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(scalartimes_class, gensym("sigbinops")); | |||
} | |||
/* ----------------------------- over ----------------------------- */ | |||
static t_class *over_class, *scalarover_class; | |||
typedef struct _over | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_over; | |||
typedef struct _scalarover | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
t_float x_g; | |||
} t_scalarover; | |||
static void *over_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
if (argc > 1) post("/~: extra arguments ignored"); | |||
if (argc) | |||
{ | |||
t_scalarover *x = (t_scalarover *)pd_new(scalarover_class); | |||
floatinlet_new(&x->x_obj, &x->x_g); | |||
x->x_g = atom_getfloatarg(0, argc, argv); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
else | |||
{ | |||
t_over *x = (t_over *)pd_new(over_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
} | |||
t_int *over_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) | |||
{ | |||
t_sample f = *in1++, g = *in2++; | |||
*out++ = (g ? f / g : 0); | |||
} | |||
return (w+5); | |||
} | |||
t_int *over_perf8(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) | |||
{ | |||
t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; | |||
t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; | |||
t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; | |||
t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; | |||
out[0] = (g0? f0 / g0 : 0); | |||
out[1] = (g1? f1 / g1 : 0); | |||
out[2] = (g2? f2 / g2 : 0); | |||
out[3] = (g3? f3 / g3 : 0); | |||
out[4] = (g4? f4 / g4 : 0); | |||
out[5] = (g5? f5 / g5 : 0); | |||
out[6] = (g6? f6 / g6 : 0); | |||
out[7] = (g7? f7 / g7 : 0); | |||
} | |||
return (w+5); | |||
} | |||
t_int *scalarover_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float f = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
if(f) f = 1./f; | |||
while (n--) *out++ = *in++ * f; | |||
return (w+5); | |||
} | |||
t_int *scalarover_perf8(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float g = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
if (g) g = 1.f / g; | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; | |||
t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; | |||
out[0] = f0 * g; out[1] = f1 * g; out[2] = f2 * g; out[3] = f3 * g; | |||
out[4] = f4 * g; out[5] = f5 * g; out[6] = f6 * g; out[7] = f7 * g; | |||
} | |||
return (w+5); | |||
} | |||
static void over_dsp(t_over *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(over_perform, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(over_perf8, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
} | |||
static void scalarover_dsp(t_scalarover *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(scalarover_perform, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(scalarover_perf8, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void over_setup(void) | |||
{ | |||
over_class = class_new(gensym("/~"), (t_newmethod)over_new, 0, | |||
sizeof(t_over), 0, A_GIMME, 0); | |||
CLASS_MAINSIGNALIN(over_class, t_over, x_f); | |||
class_addmethod(over_class, (t_method)over_dsp, gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(over_class, gensym("sigbinops")); | |||
scalarover_class = class_new(gensym("/~"), 0, 0, | |||
sizeof(t_scalarover), 0, 0); | |||
CLASS_MAINSIGNALIN(scalarover_class, t_scalarover, x_f); | |||
class_addmethod(scalarover_class, (t_method)scalarover_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(scalarover_class, gensym("sigbinops")); | |||
} | |||
/* ----------------------------- max ----------------------------- */ | |||
static t_class *max_class, *scalarmax_class; | |||
typedef struct _max | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_max; | |||
typedef struct _scalarmax | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
t_float x_g; | |||
} t_scalarmax; | |||
static void *max_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
if (argc > 1) post("max~: extra arguments ignored"); | |||
if (argc) | |||
{ | |||
t_scalarmax *x = (t_scalarmax *)pd_new(scalarmax_class); | |||
floatinlet_new(&x->x_obj, &x->x_g); | |||
x->x_g = atom_getfloatarg(0, argc, argv); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
else | |||
{ | |||
t_max *x = (t_max *)pd_new(max_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
} | |||
t_int *max_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) | |||
{ | |||
t_sample f = *in1++, g = *in2++; | |||
*out++ = (f > g ? f : g); | |||
} | |||
return (w+5); | |||
} | |||
t_int *max_perf8(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) | |||
{ | |||
t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; | |||
t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; | |||
t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; | |||
t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; | |||
out[0] = (f0 > g0 ? f0 : g0); out[1] = (f1 > g1 ? f1 : g1); | |||
out[2] = (f2 > g2 ? f2 : g2); out[3] = (f3 > g3 ? f3 : g3); | |||
out[4] = (f4 > g4 ? f4 : g4); out[5] = (f5 > g5 ? f5 : g5); | |||
out[6] = (f6 > g6 ? f6 : g6); out[7] = (f7 > g7 ? f7 : g7); | |||
} | |||
return (w+5); | |||
} | |||
t_int *scalarmax_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float f = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) | |||
{ | |||
t_sample g = *in++; | |||
*out++ = (f > g ? f : g); | |||
} | |||
return (w+5); | |||
} | |||
t_int *scalarmax_perf8(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float g = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; | |||
t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; | |||
out[0] = (f0 > g ? f0 : g); out[1] = (f1 > g ? f1 : g); | |||
out[2] = (f2 > g ? f2 : g); out[3] = (f3 > g ? f3 : g); | |||
out[4] = (f4 > g ? f4 : g); out[5] = (f5 > g ? f5 : g); | |||
out[6] = (f6 > g ? f6 : g); out[7] = (f7 > g ? f7 : g); | |||
} | |||
return (w+5); | |||
} | |||
static void max_dsp(t_max *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(max_perform, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(max_perf8, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
} | |||
static void scalarmax_dsp(t_scalarmax *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(scalarmax_perform, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(scalarmax_perf8, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void max_setup(void) | |||
{ | |||
max_class = class_new(gensym("max~"), (t_newmethod)max_new, 0, | |||
sizeof(t_max), 0, A_GIMME, 0); | |||
CLASS_MAINSIGNALIN(max_class, t_max, x_f); | |||
class_addmethod(max_class, (t_method)max_dsp, gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(max_class, gensym("sigbinops")); | |||
scalarmax_class = class_new(gensym("max~"), 0, 0, | |||
sizeof(t_scalarmax), 0, 0); | |||
CLASS_MAINSIGNALIN(scalarmax_class, t_scalarmax, x_f); | |||
class_addmethod(scalarmax_class, (t_method)scalarmax_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(scalarmax_class, gensym("sigbinops")); | |||
} | |||
/* ----------------------------- min ----------------------------- */ | |||
static t_class *min_class, *scalarmin_class; | |||
typedef struct _min | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_min; | |||
typedef struct _scalarmin | |||
{ | |||
t_object x_obj; | |||
t_float x_g; | |||
t_float x_f; | |||
} t_scalarmin; | |||
static void *min_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
if (argc > 1) post("min~: extra arguments ignored"); | |||
if (argc) | |||
{ | |||
t_scalarmin *x = (t_scalarmin *)pd_new(scalarmin_class); | |||
floatinlet_new(&x->x_obj, &x->x_g); | |||
x->x_g = atom_getfloatarg(0, argc, argv); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
else | |||
{ | |||
t_min *x = (t_min *)pd_new(min_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
} | |||
t_int *min_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) | |||
{ | |||
t_sample f = *in1++, g = *in2++; | |||
*out++ = (f < g ? f : g); | |||
} | |||
return (w+5); | |||
} | |||
t_int *min_perf8(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) | |||
{ | |||
t_sample f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; | |||
t_sample f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; | |||
t_sample g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; | |||
t_sample g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; | |||
out[0] = (f0 < g0 ? f0 : g0); out[1] = (f1 < g1 ? f1 : g1); | |||
out[2] = (f2 < g2 ? f2 : g2); out[3] = (f3 < g3 ? f3 : g3); | |||
out[4] = (f4 < g4 ? f4 : g4); out[5] = (f5 < g5 ? f5 : g5); | |||
out[6] = (f6 < g6 ? f6 : g6); out[7] = (f7 < g7 ? f7 : g7); | |||
} | |||
return (w+5); | |||
} | |||
t_int *scalarmin_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float f = *(t_float *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) | |||
{ | |||
t_sample g = *in++; | |||
*out++ = (f < g ? f : g); | |||
} | |||
return (w+5); | |||
} | |||
t_int *scalarmin_perf8(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_float g = *(t_float *)(w[2]); | |||
t_float *out = (t_float *)(w[3]); | |||
int n = (int)(w[4]); | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
t_sample f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; | |||
t_sample f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; | |||
out[0] = (f0 < g ? f0 : g); out[1] = (f1 < g ? f1 : g); | |||
out[2] = (f2 < g ? f2 : g); out[3] = (f3 < g ? f3 : g); | |||
out[4] = (f4 < g ? f4 : g); out[5] = (f5 < g ? f5 : g); | |||
out[6] = (f6 < g ? f6 : g); out[7] = (f7 < g ? f7 : g); | |||
} | |||
return (w+5); | |||
} | |||
static void min_dsp(t_min *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(min_perform, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(min_perf8, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
} | |||
static void scalarmin_dsp(t_scalarmin *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n&7) | |||
dsp_add(scalarmin_perform, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(scalarmin_perf8, 4, sp[0]->s_vec, &x->x_g, | |||
sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void min_setup(void) | |||
{ | |||
min_class = class_new(gensym("min~"), (t_newmethod)min_new, 0, | |||
sizeof(t_min), 0, A_GIMME, 0); | |||
CLASS_MAINSIGNALIN(min_class, t_min, x_f); | |||
class_addmethod(min_class, (t_method)min_dsp, gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(min_class, gensym("sigbinops")); | |||
scalarmin_class = class_new(gensym("min~"), 0, 0, | |||
sizeof(t_scalarmin), 0, 0); | |||
CLASS_MAINSIGNALIN(scalarmin_class, t_scalarmin, x_f); | |||
class_addmethod(scalarmin_class, (t_method)scalarmin_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(scalarmin_class, gensym("sigbinops")); | |||
} | |||
/* ----------------------- global setup routine ---------------- */ | |||
void d_arithmetic_setup(void) | |||
{ | |||
plus_setup(); | |||
minus_setup(); | |||
times_setup(); | |||
over_setup(); | |||
max_setup(); | |||
min_setup(); | |||
} | |||
@@ -0,0 +1,850 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* sig~ and line~ control-to-signal converters; | |||
snapshot~ signal-to-control converter. | |||
*/ | |||
#include "m_pd.h" | |||
#include "math.h" | |||
/* -------------------------- sig~ ------------------------------ */ | |||
static t_class *sig_tilde_class; | |||
typedef struct _sig | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_sig; | |||
static t_int *sig_tilde_perform(t_int *w) | |||
{ | |||
t_float f = *(t_float *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
while (n--) | |||
*out++ = f; | |||
return (w+4); | |||
} | |||
static t_int *sig_tilde_perf8(t_int *w) | |||
{ | |||
t_float f = *(t_float *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
for (; n; n -= 8, out += 8) | |||
{ | |||
out[0] = f; | |||
out[1] = f; | |||
out[2] = f; | |||
out[3] = f; | |||
out[4] = f; | |||
out[5] = f; | |||
out[6] = f; | |||
out[7] = f; | |||
} | |||
return (w+4); | |||
} | |||
void dsp_add_scalarcopy(t_float *in, t_sample *out, int n) | |||
{ | |||
if (n&7) | |||
dsp_add(sig_tilde_perform, 3, in, out, n); | |||
else | |||
dsp_add(sig_tilde_perf8, 3, in, out, n); | |||
} | |||
static void sig_tilde_float(t_sig *x, t_float f) | |||
{ | |||
x->x_f = f; | |||
} | |||
static void sig_tilde_dsp(t_sig *x, t_signal **sp) | |||
{ | |||
dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n); | |||
} | |||
static void *sig_tilde_new(t_floatarg f) | |||
{ | |||
t_sig *x = (t_sig *)pd_new(sig_tilde_class); | |||
x->x_f = f; | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
return (x); | |||
} | |||
static void sig_tilde_setup(void) | |||
{ | |||
sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0, | |||
sizeof(t_sig), 0, A_DEFFLOAT, 0); | |||
class_addfloat(sig_tilde_class, (t_method)sig_tilde_float); | |||
class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* -------------------------- line~ ------------------------------ */ | |||
static t_class *line_tilde_class; | |||
typedef struct _line | |||
{ | |||
t_object x_obj; | |||
t_sample x_target; /* target value of ramp */ | |||
t_sample x_value; /* current value of ramp at block-borders */ | |||
t_sample x_biginc; | |||
t_sample x_inc; | |||
t_float x_1overn; | |||
t_float x_dspticktomsec; | |||
t_float x_inletvalue; | |||
t_float x_inletwas; | |||
int x_ticksleft; | |||
int x_retarget; | |||
} t_line; | |||
static t_int *line_tilde_perform(t_int *w) | |||
{ | |||
t_line *x = (t_line *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_sample f = x->x_value; | |||
if (PD_BIGORSMALL(f)) | |||
x->x_value = f = 0; | |||
if (x->x_retarget) | |||
{ | |||
int nticks = x->x_inletwas * x->x_dspticktomsec; | |||
if (!nticks) nticks = 1; | |||
x->x_ticksleft = nticks; | |||
x->x_biginc = (x->x_target - x->x_value)/(t_float)nticks; | |||
x->x_inc = x->x_1overn * x->x_biginc; | |||
x->x_retarget = 0; | |||
} | |||
if (x->x_ticksleft) | |||
{ | |||
t_sample f = x->x_value; | |||
while (n--) *out++ = f, f += x->x_inc; | |||
x->x_value += x->x_biginc; | |||
x->x_ticksleft--; | |||
} | |||
else | |||
{ | |||
t_sample g = x->x_value = x->x_target; | |||
while (n--) | |||
*out++ = g; | |||
} | |||
return (w+4); | |||
} | |||
/* TB: vectorized version */ | |||
static t_int *line_tilde_perf8(t_int *w) | |||
{ | |||
t_line *x = (t_line *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_sample f = x->x_value; | |||
if (PD_BIGORSMALL(f)) | |||
x->x_value = f = 0; | |||
if (x->x_retarget) | |||
{ | |||
int nticks = x->x_inletwas * x->x_dspticktomsec; | |||
if (!nticks) nticks = 1; | |||
x->x_ticksleft = nticks; | |||
x->x_biginc = (x->x_target - x->x_value)/(t_sample)nticks; | |||
x->x_inc = x->x_1overn * x->x_biginc; | |||
x->x_retarget = 0; | |||
} | |||
if (x->x_ticksleft) | |||
{ | |||
t_sample f = x->x_value; | |||
while (n--) *out++ = f, f += x->x_inc; | |||
x->x_value += x->x_biginc; | |||
x->x_ticksleft--; | |||
} | |||
else | |||
{ | |||
t_sample f = x->x_value = x->x_target; | |||
for (; n; n -= 8, out += 8) | |||
{ | |||
out[0] = f; out[1] = f; out[2] = f; out[3] = f; | |||
out[4] = f; out[5] = f; out[6] = f; out[7] = f; | |||
} | |||
} | |||
return (w+4); | |||
} | |||
static void line_tilde_float(t_line *x, t_float f) | |||
{ | |||
if (x->x_inletvalue <= 0) | |||
{ | |||
x->x_target = x->x_value = f; | |||
x->x_ticksleft = x->x_retarget = 0; | |||
} | |||
else | |||
{ | |||
x->x_target = f; | |||
x->x_retarget = 1; | |||
x->x_inletwas = x->x_inletvalue; | |||
x->x_inletvalue = 0; | |||
} | |||
} | |||
static void line_tilde_stop(t_line *x) | |||
{ | |||
x->x_target = x->x_value; | |||
x->x_ticksleft = x->x_retarget = 0; | |||
} | |||
static void line_tilde_dsp(t_line *x, t_signal **sp) | |||
{ | |||
if(sp[0]->s_n&7) | |||
dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(line_tilde_perf8, 3, x, sp[0]->s_vec, sp[0]->s_n); | |||
x->x_1overn = 1./sp[0]->s_n; | |||
x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n); | |||
} | |||
static void *line_tilde_new(void) | |||
{ | |||
t_line *x = (t_line *)pd_new(line_tilde_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
floatinlet_new(&x->x_obj, &x->x_inletvalue); | |||
x->x_ticksleft = x->x_retarget = 0; | |||
x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0; | |||
return (x); | |||
} | |||
static void line_tilde_setup(void) | |||
{ | |||
line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0, | |||
sizeof(t_line), 0, 0); | |||
class_addfloat(line_tilde_class, (t_method)line_tilde_float); | |||
class_addmethod(line_tilde_class, (t_method)line_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addmethod(line_tilde_class, (t_method)line_tilde_stop, | |||
gensym("stop"), 0); | |||
} | |||
/* -------------------------- vline~ ------------------------------ */ | |||
static t_class *vline_tilde_class; | |||
#include "s_stuff.h" /* for DEFDACBLKSIZE; this should be in m_pd.h */ | |||
typedef struct _vseg | |||
{ | |||
double s_targettime; | |||
double s_starttime; | |||
t_sample s_target; | |||
struct _vseg *s_next; | |||
} t_vseg; | |||
typedef struct _vline | |||
{ | |||
t_object x_obj; | |||
double x_value; | |||
double x_inc; | |||
double x_referencetime; | |||
double x_lastlogicaltime; | |||
double x_nextblocktime; | |||
double x_samppermsec; | |||
double x_msecpersamp; | |||
double x_targettime; | |||
t_sample x_target; | |||
t_float x_inlet1; | |||
t_float x_inlet2; | |||
t_vseg *x_list; | |||
} t_vline; | |||
static t_int *vline_tilde_perform(t_int *w) | |||
{ | |||
t_vline *x = (t_vline *)(w[1]); | |||
t_float *out = (t_float *)(w[2]); | |||
int n = (int)(w[3]), i; | |||
double f = x->x_value; | |||
double inc = x->x_inc; | |||
double msecpersamp = x->x_msecpersamp; | |||
double samppermsec = x->x_samppermsec; | |||
double timenow, logicaltimenow = clock_gettimesince(x->x_referencetime); | |||
t_vseg *s = x->x_list; | |||
if (logicaltimenow != x->x_lastlogicaltime) | |||
{ | |||
int sampstotime = (n > DEFDACBLKSIZE ? n : DEFDACBLKSIZE); | |||
x->x_lastlogicaltime = logicaltimenow; | |||
x->x_nextblocktime = logicaltimenow - sampstotime * msecpersamp; | |||
} | |||
timenow = x->x_nextblocktime; | |||
x->x_nextblocktime = timenow + n * msecpersamp; | |||
for (i = 0; i < n; i++) | |||
{ | |||
double timenext = timenow + msecpersamp; | |||
checknext: | |||
if (s) | |||
{ | |||
/* has starttime elapsed? If so update value and increment */ | |||
if (s->s_starttime < timenext) | |||
{ | |||
if (x->x_targettime <= timenext) | |||
f = x->x_target, inc = 0; | |||
/* if zero-length segment bash output value */ | |||
if (s->s_targettime <= s->s_starttime) | |||
{ | |||
f = s->s_target; | |||
inc = 0; | |||
} | |||
else | |||
{ | |||
double incpermsec = (s->s_target - f)/ | |||
(s->s_targettime - s->s_starttime); | |||
f = f + incpermsec * (timenext - s->s_starttime); | |||
inc = incpermsec * msecpersamp; | |||
} | |||
x->x_inc = inc; | |||
x->x_target = s->s_target; | |||
x->x_targettime = s->s_targettime; | |||
x->x_list = s->s_next; | |||
t_freebytes(s, sizeof(*s)); | |||
s = x->x_list; | |||
goto checknext; | |||
} | |||
} | |||
if (x->x_targettime <= timenext) | |||
f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20; | |||
*out++ = f; | |||
f = f + inc; | |||
timenow = timenext; | |||
} | |||
x->x_value = f; | |||
return (w+4); | |||
} | |||
static void vline_tilde_stop(t_vline *x) | |||
{ | |||
t_vseg *s1, *s2; | |||
for (s1 = x->x_list; s1; s1 = s2) | |||
s2 = s1->s_next, t_freebytes(s1, sizeof(*s1)); | |||
x->x_list = 0; | |||
x->x_inc = 0; | |||
x->x_inlet1 = x->x_inlet2 = 0; | |||
x->x_target = x->x_value; | |||
x->x_targettime = 1e20; | |||
} | |||
static void vline_tilde_float(t_vline *x, t_float f) | |||
{ | |||
double timenow = clock_gettimesince(x->x_referencetime); | |||
t_float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1); | |||
t_float inlet2 = x->x_inlet2; | |||
double starttime = timenow + inlet2; | |||
t_vseg *s1, *s2, *deletefrom = 0, *snew; | |||
if (PD_BIGORSMALL(f)) | |||
f = 0; | |||
/* negative delay input means stop and jump immediately to new value */ | |||
if (inlet2 < 0) | |||
{ | |||
x->x_value = f; | |||
vline_tilde_stop(x); | |||
return; | |||
} | |||
snew = (t_vseg *)t_getbytes(sizeof(*snew)); | |||
/* check if we supplant the first item in the list. We supplant | |||
an item by having an earlier starttime, or an equal starttime unless | |||
the equal one was instantaneous and the new one isn't (in which case | |||
we'll do a jump-and-slide starting at that time.) */ | |||
if (!x->x_list || x->x_list->s_starttime > starttime || | |||
(x->x_list->s_starttime == starttime && | |||
(x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0))) | |||
{ | |||
deletefrom = x->x_list; | |||
x->x_list = snew; | |||
} | |||
else | |||
{ | |||
for (s1 = x->x_list; (s2 = s1->s_next); s1 = s2) | |||
{ | |||
if (s2->s_starttime > starttime || | |||
(s2->s_starttime == starttime && | |||
(s2->s_targettime > s2->s_starttime || inlet1 <= 0))) | |||
{ | |||
deletefrom = s2; | |||
s1->s_next = snew; | |||
goto didit; | |||
} | |||
} | |||
s1->s_next = snew; | |||
deletefrom = 0; | |||
didit: ; | |||
} | |||
while (deletefrom) | |||
{ | |||
s1 = deletefrom->s_next; | |||
t_freebytes(deletefrom, sizeof(*deletefrom)); | |||
deletefrom = s1; | |||
} | |||
snew->s_next = 0; | |||
snew->s_target = f; | |||
snew->s_starttime = starttime; | |||
snew->s_targettime = starttime + inlet1; | |||
x->x_inlet1 = x->x_inlet2 = 0; | |||
} | |||
static void vline_tilde_dsp(t_vline *x, t_signal **sp) | |||
{ | |||
dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); | |||
x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000; | |||
x->x_msecpersamp = ((double)1000) / sp[0]->s_sr; | |||
} | |||
static void *vline_tilde_new(void) | |||
{ | |||
t_vline *x = (t_vline *)pd_new(vline_tilde_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
floatinlet_new(&x->x_obj, &x->x_inlet1); | |||
floatinlet_new(&x->x_obj, &x->x_inlet2); | |||
x->x_inlet1 = x->x_inlet2 = 0; | |||
x->x_value = x->x_inc = 0; | |||
x->x_referencetime = x->x_lastlogicaltime = x->x_nextblocktime = | |||
clock_getlogicaltime(); | |||
x->x_list = 0; | |||
x->x_samppermsec = 0; | |||
x->x_targettime = 1e20; | |||
return (x); | |||
} | |||
static void vline_tilde_setup(void) | |||
{ | |||
vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new, | |||
(t_method)vline_tilde_stop, sizeof(t_vline), 0, 0); | |||
class_addfloat(vline_tilde_class, (t_method)vline_tilde_float); | |||
class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop, | |||
gensym("stop"), 0); | |||
} | |||
/* -------------------------- snapshot~ ------------------------------ */ | |||
static t_class *snapshot_tilde_class; | |||
typedef struct _snapshot | |||
{ | |||
t_object x_obj; | |||
t_sample x_value; | |||
t_float x_f; | |||
} t_snapshot; | |||
static void *snapshot_tilde_new(void) | |||
{ | |||
t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class); | |||
x->x_value = 0; | |||
outlet_new(&x->x_obj, &s_float); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *snapshot_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
*out = *in; | |||
return (w+3); | |||
} | |||
static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp) | |||
{ | |||
dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1), | |||
&x->x_value); | |||
} | |||
static void snapshot_tilde_bang(t_snapshot *x) | |||
{ | |||
outlet_float(x->x_obj.ob_outlet, x->x_value); | |||
} | |||
static void snapshot_tilde_set(t_snapshot *x, t_floatarg f) | |||
{ | |||
x->x_value = f; | |||
} | |||
static void snapshot_tilde_setup(void) | |||
{ | |||
snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0, | |||
sizeof(t_snapshot), 0, 0); | |||
CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f); | |||
class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set, | |||
gensym("set"), A_DEFFLOAT, 0); | |||
class_addbang(snapshot_tilde_class, snapshot_tilde_bang); | |||
} | |||
/* -------------------------- vsnapshot~ ------------------------------ */ | |||
static t_class *vsnapshot_tilde_class; | |||
typedef struct _vsnapshot | |||
{ | |||
t_object x_obj; | |||
int x_n; | |||
int x_gotone; | |||
t_sample *x_vec; | |||
t_float x_f; | |||
t_float x_sampspermsec; | |||
double x_time; | |||
} t_vsnapshot; | |||
static void *vsnapshot_tilde_new(void) | |||
{ | |||
t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class); | |||
outlet_new(&x->x_obj, &s_float); | |||
x->x_f = 0; | |||
x->x_n = 0; | |||
x->x_vec = 0; | |||
x->x_gotone = 0; | |||
return (x); | |||
} | |||
static t_int *vsnapshot_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_vsnapshot *x = (t_vsnapshot *)(w[2]); | |||
t_sample *out = x->x_vec; | |||
int n = x->x_n, i; | |||
for (i = 0; i < n; i++) | |||
out[i] = in[i]; | |||
x->x_time = clock_getlogicaltime(); | |||
x->x_gotone = 1; | |||
return (w+3); | |||
} | |||
static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp) | |||
{ | |||
int n = sp[0]->s_n; | |||
if (n != x->x_n) | |||
{ | |||
if (x->x_vec) | |||
t_freebytes(x->x_vec, x->x_n * sizeof(t_sample)); | |||
x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample)); | |||
x->x_gotone = 0; | |||
x->x_n = n; | |||
} | |||
x->x_sampspermsec = sp[0]->s_sr / 1000; | |||
dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x); | |||
} | |||
static void vsnapshot_tilde_bang(t_vsnapshot *x) | |||
{ | |||
t_sample val; | |||
if (x->x_gotone) | |||
{ | |||
int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec; | |||
if (indx < 0) | |||
indx = 0; | |||
else if (indx >= x->x_n) | |||
indx = x->x_n - 1; | |||
val = x->x_vec[indx]; | |||
} | |||
else val = 0; | |||
outlet_float(x->x_obj.ob_outlet, val); | |||
} | |||
static void vsnapshot_tilde_ff(t_vsnapshot *x) | |||
{ | |||
if (x->x_vec) | |||
t_freebytes(x->x_vec, x->x_n * sizeof(t_sample)); | |||
} | |||
static void vsnapshot_tilde_setup(void) | |||
{ | |||
vsnapshot_tilde_class = class_new(gensym("vsnapshot~"), | |||
vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff, | |||
sizeof(t_vsnapshot), 0, 0); | |||
CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f); | |||
class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang); | |||
} | |||
/* ---------------- env~ - simple envelope follower. ----------------- */ | |||
#define MAXOVERLAP 32 | |||
#define INITVSTAKEN 64 | |||
typedef struct sigenv | |||
{ | |||
t_object x_obj; /* header */ | |||
void *x_outlet; /* a "float" outlet */ | |||
void *x_clock; /* a "clock" object */ | |||
t_sample *x_buf; /* a Hanning window */ | |||
int x_phase; /* number of points since last output */ | |||
int x_period; /* requested period of output */ | |||
int x_realperiod; /* period rounded up to vecsize multiple */ | |||
int x_npoints; /* analysis window size in samples */ | |||
t_float x_result; /* result to output */ | |||
t_sample x_sumbuf[MAXOVERLAP]; /* summing buffer */ | |||
t_float x_f; | |||
int x_allocforvs; /* extra buffer for DSP vector size */ | |||
} t_sigenv; | |||
t_class *env_tilde_class; | |||
static void env_tilde_tick(t_sigenv *x); | |||
static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod) | |||
{ | |||
int npoints = fnpoints; | |||
int period = fperiod; | |||
t_sigenv *x; | |||
t_sample *buf; | |||
int i; | |||
if (npoints < 1) npoints = 1024; | |||
if (period < 1) period = npoints/2; | |||
if (period < npoints / MAXOVERLAP + 1) | |||
period = npoints / MAXOVERLAP + 1; | |||
if (!(buf = getbytes(sizeof(t_sample) * (npoints + INITVSTAKEN)))) | |||
{ | |||
error("env: couldn't allocate buffer"); | |||
return (0); | |||
} | |||
x = (t_sigenv *)pd_new(env_tilde_class); | |||
x->x_buf = buf; | |||
x->x_npoints = npoints; | |||
x->x_phase = 0; | |||
x->x_period = period; | |||
for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0; | |||
for (i = 0; i < npoints; i++) | |||
buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints; | |||
for (; i < npoints+INITVSTAKEN; i++) buf[i] = 0; | |||
x->x_clock = clock_new(x, (t_method)env_tilde_tick); | |||
x->x_outlet = outlet_new(&x->x_obj, gensym("float")); | |||
x->x_f = 0; | |||
x->x_allocforvs = INITVSTAKEN; | |||
return (x); | |||
} | |||
static t_int *env_tilde_perform(t_int *w) | |||
{ | |||
t_sigenv *x = (t_sigenv *)(w[1]); | |||
t_sample *in = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
int count; | |||
t_sample *sump; | |||
in += n; | |||
for (count = x->x_phase, sump = x->x_sumbuf; | |||
count < x->x_npoints; count += x->x_realperiod, sump++) | |||
{ | |||
t_sample *hp = x->x_buf + count; | |||
t_sample *fp = in; | |||
t_sample sum = *sump; | |||
int i; | |||
for (i = 0; i < n; i++) | |||
{ | |||
fp--; | |||
sum += *hp++ * (*fp * *fp); | |||
} | |||
*sump = sum; | |||
} | |||
sump[0] = 0; | |||
x->x_phase -= n; | |||
if (x->x_phase < 0) | |||
{ | |||
x->x_result = x->x_sumbuf[0]; | |||
for (count = x->x_realperiod, sump = x->x_sumbuf; | |||
count < x->x_npoints; count += x->x_realperiod, sump++) | |||
sump[0] = sump[1]; | |||
sump[0] = 0; | |||
x->x_phase = x->x_realperiod - n; | |||
clock_delay(x->x_clock, 0L); | |||
} | |||
return (w+4); | |||
} | |||
static void env_tilde_dsp(t_sigenv *x, t_signal **sp) | |||
{ | |||
if (x->x_period % sp[0]->s_n) x->x_realperiod = | |||
x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n); | |||
else x->x_realperiod = x->x_period; | |||
if (sp[0]->s_n > x->x_allocforvs) | |||
{ | |||
void *xx = resizebytes(x->x_buf, | |||
(x->x_npoints + x->x_allocforvs) * sizeof(t_sample), | |||
(x->x_npoints + sp[0]->s_n) * sizeof(t_sample)); | |||
if (!xx) | |||
{ | |||
error("env~: out of memory"); | |||
return; | |||
} | |||
x->x_buf = (t_sample *)xx; | |||
x->x_allocforvs = sp[0]->s_n; | |||
} | |||
dsp_add(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); | |||
} | |||
static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */ | |||
{ | |||
outlet_float(x->x_outlet, powtodb(x->x_result)); | |||
} | |||
static void env_tilde_ff(t_sigenv *x) /* cleanup on free */ | |||
{ | |||
clock_free(x->x_clock); | |||
freebytes(x->x_buf, (x->x_npoints + x->x_allocforvs) * sizeof(*x->x_buf)); | |||
} | |||
void env_tilde_setup(void ) | |||
{ | |||
env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new, | |||
(t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f); | |||
class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* --------------------- threshold~ ----------------------------- */ | |||
static t_class *threshold_tilde_class; | |||
typedef struct _threshold_tilde | |||
{ | |||
t_object x_obj; | |||
t_outlet *x_outlet1; /* bang out for high thresh */ | |||
t_outlet *x_outlet2; /* bang out for low thresh */ | |||
t_clock *x_clock; /* wakeup for message output */ | |||
t_float x_f; /* scalar inlet */ | |||
int x_state; /* 1 = high, 0 = low */ | |||
t_float x_hithresh; /* value of high threshold */ | |||
t_float x_lothresh; /* value of low threshold */ | |||
t_float x_deadwait; /* msec remaining in dead period */ | |||
t_float x_msecpertick; /* msec per DSP tick */ | |||
t_float x_hideadtime; /* hi dead time in msec */ | |||
t_float x_lodeadtime; /* lo dead time in msec */ | |||
} t_threshold_tilde; | |||
static void threshold_tilde_tick(t_threshold_tilde *x); | |||
static void threshold_tilde_set(t_threshold_tilde *x, | |||
t_floatarg hithresh, t_floatarg hideadtime, | |||
t_floatarg lothresh, t_floatarg lodeadtime); | |||
static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh, | |||
t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime) | |||
{ | |||
t_threshold_tilde *x = (t_threshold_tilde *) | |||
pd_new(threshold_tilde_class); | |||
x->x_state = 0; /* low state */ | |||
x->x_deadwait = 0; /* no dead time */ | |||
x->x_clock = clock_new(x, (t_method)threshold_tilde_tick); | |||
x->x_outlet1 = outlet_new(&x->x_obj, &s_bang); | |||
x->x_outlet2 = outlet_new(&x->x_obj, &s_bang); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1")); | |||
x->x_msecpertick = 0.; | |||
x->x_f = 0; | |||
threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime); | |||
return (x); | |||
} | |||
/* "set" message to specify thresholds and dead times */ | |||
static void threshold_tilde_set(t_threshold_tilde *x, | |||
t_floatarg hithresh, t_floatarg hideadtime, | |||
t_floatarg lothresh, t_floatarg lodeadtime) | |||
{ | |||
if (lothresh > hithresh) | |||
lothresh = hithresh; | |||
x->x_hithresh = hithresh; | |||
x->x_hideadtime = hideadtime; | |||
x->x_lothresh = lothresh; | |||
x->x_lodeadtime = lodeadtime; | |||
} | |||
/* number in inlet sets state -- note incompatible with JMAX which used | |||
"int" message for this, impossible here because of auto signal conversion */ | |||
static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f) | |||
{ | |||
x->x_state = (f != 0); | |||
x->x_deadwait = 0; | |||
} | |||
static void threshold_tilde_tick(t_threshold_tilde *x) | |||
{ | |||
if (x->x_state) | |||
outlet_bang(x->x_outlet1); | |||
else outlet_bang(x->x_outlet2); | |||
} | |||
static t_int *threshold_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_threshold_tilde *x = (t_threshold_tilde *)(w[2]); | |||
int n = (int)w[3]; | |||
if (x->x_deadwait > 0) | |||
x->x_deadwait -= x->x_msecpertick; | |||
else if (x->x_state) | |||
{ | |||
/* we're high; look for low sample */ | |||
for (; n--; in1++) | |||
{ | |||
if (*in1 < x->x_lothresh) | |||
{ | |||
clock_delay(x->x_clock, 0L); | |||
x->x_state = 0; | |||
x->x_deadwait = x->x_lodeadtime; | |||
goto done; | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
/* we're low; look for high sample */ | |||
for (; n--; in1++) | |||
{ | |||
if (*in1 >= x->x_hithresh) | |||
{ | |||
clock_delay(x->x_clock, 0L); | |||
x->x_state = 1; | |||
x->x_deadwait = x->x_hideadtime; | |||
goto done; | |||
} | |||
} | |||
} | |||
done: | |||
return (w+4); | |||
} | |||
void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp) | |||
{ | |||
x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr; | |||
dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); | |||
} | |||
static void threshold_tilde_ff(t_threshold_tilde *x) | |||
{ | |||
clock_free(x->x_clock); | |||
} | |||
static void threshold_tilde_setup( void) | |||
{ | |||
threshold_tilde_class = class_new(gensym("threshold~"), | |||
(t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff, | |||
sizeof(t_threshold_tilde), 0, | |||
A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f); | |||
class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set, | |||
gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1, | |||
gensym("ft1"), A_FLOAT, 0); | |||
class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------ global setup routine ------------------------- */ | |||
void d_ctl_setup(void) | |||
{ | |||
sig_tilde_setup(); | |||
line_tilde_setup(); | |||
vline_tilde_setup(); | |||
snapshot_tilde_setup(); | |||
vsnapshot_tilde_setup(); | |||
env_tilde_setup(); | |||
threshold_tilde_setup(); | |||
} | |||
@@ -0,0 +1,202 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* The dac~ and adc~ routines. | |||
*/ | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
/* ----------------------------- dac~ --------------------------- */ | |||
static t_class *dac_class; | |||
typedef struct _dac | |||
{ | |||
t_object x_obj; | |||
t_int x_n; | |||
t_int *x_vec; | |||
t_float x_f; | |||
} t_dac; | |||
static void *dac_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_dac *x = (t_dac *)pd_new(dac_class); | |||
t_atom defarg[2], *ap; | |||
int i; | |||
if (!argc) | |||
{ | |||
argv = defarg; | |||
argc = 2; | |||
SETFLOAT(&defarg[0], 1); | |||
SETFLOAT(&defarg[1], 2); | |||
} | |||
x->x_n = argc; | |||
x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec)); | |||
for (i = 0; i < argc; i++) | |||
x->x_vec[i] = atom_getfloatarg(i, argc, argv); | |||
for (i = 1; i < argc; i++) | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static void dac_dsp(t_dac *x, t_signal **sp) | |||
{ | |||
t_int i, *ip; | |||
t_signal **sp2; | |||
for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++) | |||
{ | |||
int ch = (int)(*ip - 1); | |||
if ((*sp2)->s_n != DEFDACBLKSIZE) | |||
error("dac~: bad vector size"); | |||
else if (ch >= 0 && ch < sys_get_outchannels()) | |||
dsp_add(plus_perform, 4, STUFF->st_soundout + DEFDACBLKSIZE*ch, | |||
(*sp2)->s_vec, STUFF->st_soundout + DEFDACBLKSIZE*ch, DEFDACBLKSIZE); | |||
} | |||
} | |||
static void dac_set(t_dac *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
int i; | |||
for (i = 0; i < argc && i < x->x_n; i++) | |||
x->x_vec[i] = atom_getfloatarg(i, argc, argv); | |||
canvas_update_dsp(); | |||
} | |||
static void dac_free(t_dac *x) | |||
{ | |||
freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec)); | |||
} | |||
static void dac_setup(void) | |||
{ | |||
dac_class = class_new(gensym("dac~"), (t_newmethod)dac_new, | |||
(t_method)dac_free, sizeof(t_dac), 0, A_GIMME, 0); | |||
CLASS_MAINSIGNALIN(dac_class, t_dac, x_f); | |||
class_addmethod(dac_class, (t_method)dac_dsp, gensym("dsp"), A_CANT, 0); | |||
class_addmethod(dac_class, (t_method)dac_set, gensym("set"), A_GIMME, 0); | |||
class_sethelpsymbol(dac_class, gensym("adc~_dac~")); | |||
} | |||
/* ----------------------------- adc~ --------------------------- */ | |||
static t_class *adc_class; | |||
typedef struct _adc | |||
{ | |||
t_object x_obj; | |||
t_int x_n; | |||
t_int *x_vec; | |||
} t_adc; | |||
static void *adc_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_adc *x = (t_adc *)pd_new(adc_class); | |||
t_atom defarg[2], *ap; | |||
int i; | |||
if (!argc) | |||
{ | |||
argv = defarg; | |||
argc = 2; | |||
SETFLOAT(&defarg[0], 1); | |||
SETFLOAT(&defarg[1], 2); | |||
} | |||
x->x_n = argc; | |||
x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec)); | |||
for (i = 0; i < argc; i++) | |||
x->x_vec[i] = atom_getfloatarg(i, argc, argv); | |||
for (i = 0; i < argc; i++) | |||
outlet_new(&x->x_obj, &s_signal); | |||
return (x); | |||
} | |||
t_int *copy_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
while (n--) *out++ = *in1++; | |||
return (w+4); | |||
} | |||
static t_int *copy_perf8(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
for (; n; n -= 8, in1 += 8, out += 8) | |||
{ | |||
t_sample f0 = in1[0]; | |||
t_sample f1 = in1[1]; | |||
t_sample f2 = in1[2]; | |||
t_sample f3 = in1[3]; | |||
t_sample f4 = in1[4]; | |||
t_sample f5 = in1[5]; | |||
t_sample f6 = in1[6]; | |||
t_sample f7 = in1[7]; | |||
out[0] = f0; | |||
out[1] = f1; | |||
out[2] = f2; | |||
out[3] = f3; | |||
out[4] = f4; | |||
out[5] = f5; | |||
out[6] = f6; | |||
out[7] = f7; | |||
} | |||
return (w+4); | |||
} | |||
void dsp_add_copy(t_sample *in, t_sample *out, int n) | |||
{ | |||
if (n&7) | |||
dsp_add(copy_perform, 3, in, out, n); | |||
else | |||
dsp_add(copy_perf8, 3, in, out, n); | |||
} | |||
static void adc_dsp(t_adc *x, t_signal **sp) | |||
{ | |||
t_int i, *ip; | |||
t_signal **sp2; | |||
for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++) | |||
{ | |||
int ch = (int)(*ip - 1); | |||
if ((*sp2)->s_n != DEFDACBLKSIZE) | |||
error("adc~: bad vector size"); | |||
else if (ch >= 0 && ch < sys_get_inchannels()) | |||
dsp_add_copy(STUFF->st_soundin + DEFDACBLKSIZE*ch, | |||
(*sp2)->s_vec, DEFDACBLKSIZE); | |||
else dsp_add_zero((*sp2)->s_vec, DEFDACBLKSIZE); | |||
} | |||
} | |||
static void adc_set(t_adc *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
int i; | |||
for (i = 0; i < argc && i < x->x_n; i++) | |||
x->x_vec[i] = atom_getfloatarg(i, argc, argv); | |||
canvas_update_dsp(); | |||
} | |||
static void adc_free(t_adc *x) | |||
{ | |||
freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec)); | |||
} | |||
static void adc_setup(void) | |||
{ | |||
adc_class = class_new(gensym("adc~"), (t_newmethod)adc_new, | |||
(t_method)adc_free, sizeof(t_adc), 0, A_GIMME, 0); | |||
class_addmethod(adc_class, (t_method)adc_dsp, gensym("dsp"), A_CANT, 0); | |||
class_addmethod(adc_class, (t_method)adc_set, gensym("set"), A_GIMME, 0); | |||
class_sethelpsymbol(adc_class, gensym("adc~_dac~")); | |||
} | |||
void d_dac_setup(void) | |||
{ | |||
dac_setup(); | |||
adc_setup(); | |||
} | |||
@@ -0,0 +1,346 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* send~, delread~, throw~, catch~ */ | |||
#include "m_pd.h" | |||
#include <string.h> | |||
extern int ugen_getsortno(void); | |||
#define DEFDELVS 64 /* LATER get this from canvas at DSP time */ | |||
static const int delread_zero = 0; /* four bytes of zero for delread~, vd~*/ | |||
/* ----------------------------- delwrite~ ----------------------------- */ | |||
static t_class *sigdelwrite_class; | |||
typedef struct delwritectl | |||
{ | |||
int c_n; | |||
t_sample *c_vec; | |||
int c_phase; | |||
} t_delwritectl; | |||
typedef struct _sigdelwrite | |||
{ | |||
t_object x_obj; | |||
t_symbol *x_sym; | |||
t_float x_deltime; /* delay in msec (added by Mathieu Bouchard) */ | |||
t_delwritectl x_cspace; | |||
int x_sortno; /* DSP sort number at which this was last put on chain */ | |||
int x_rsortno; /* DSP sort # for first delread or write in chain */ | |||
int x_vecsize; /* vector size for delread~ to use */ | |||
t_float x_f; | |||
} t_sigdelwrite; | |||
#define XTRASAMPS 4 | |||
#define SAMPBLK 4 | |||
static void sigdelwrite_updatesr(t_sigdelwrite *x, t_float sr) /* added by Mathieu Bouchard */ | |||
{ | |||
int nsamps = x->x_deltime * sr * (t_float)(0.001f); | |||
if (nsamps < 1) nsamps = 1; | |||
nsamps += ((- nsamps) & (SAMPBLK - 1)); | |||
nsamps += DEFDELVS; | |||
if (x->x_cspace.c_n != nsamps) | |||
{ | |||
x->x_cspace.c_vec = (t_sample *)resizebytes(x->x_cspace.c_vec, | |||
(x->x_cspace.c_n + XTRASAMPS) * sizeof(t_sample), | |||
(nsamps + XTRASAMPS) * sizeof(t_sample)); | |||
x->x_cspace.c_n = nsamps; | |||
x->x_cspace.c_phase = XTRASAMPS; | |||
} | |||
} | |||
static void sigdelwrite_clear (t_sigdelwrite *x) /* added by Orm Finnendahl */ | |||
{ | |||
if (x->x_cspace.c_n > 0) | |||
memset(x->x_cspace.c_vec, 0, sizeof(t_sample)*(x->x_cspace.c_n + XTRASAMPS)); | |||
} | |||
/* routine to check that all delwrites/delreads/vds have same vecsize */ | |||
static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize) | |||
{ | |||
if (x->x_rsortno != ugen_getsortno()) | |||
{ | |||
x->x_vecsize = vecsize; | |||
x->x_rsortno = ugen_getsortno(); | |||
} | |||
/* | |||
LATER this should really check sample rate and blocking, once that is | |||
supported. Probably we don't actually care about vecsize. | |||
For now just suppress this check. */ | |||
#if 0 | |||
else if (vecsize != x->x_vecsize) | |||
pd_error(x, "delread/delwrite/vd vector size mismatch"); | |||
#endif | |||
} | |||
static void *sigdelwrite_new(t_symbol *s, t_floatarg msec) | |||
{ | |||
t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class); | |||
if (!*s->s_name) s = gensym("delwrite~"); | |||
pd_bind(&x->x_obj.ob_pd, s); | |||
x->x_sym = s; | |||
x->x_deltime = msec; | |||
x->x_cspace.c_n = 0; | |||
x->x_cspace.c_vec = getbytes(XTRASAMPS * sizeof(t_sample)); | |||
x->x_sortno = 0; | |||
x->x_vecsize = 0; | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigdelwrite_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_delwritectl *c = (t_delwritectl *)(w[2]); | |||
int n = (int)(w[3]); | |||
int phase = c->c_phase, nsamps = c->c_n; | |||
t_sample *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS); | |||
phase += n; | |||
while (n--) | |||
{ | |||
t_sample f = *in++; | |||
if (PD_BIGORSMALL(f)) | |||
f = 0; | |||
*bp++ = f; | |||
if (bp == ep) | |||
{ | |||
vp[0] = ep[-4]; | |||
vp[1] = ep[-3]; | |||
vp[2] = ep[-2]; | |||
vp[3] = ep[-1]; | |||
bp = vp + XTRASAMPS; | |||
phase -= nsamps; | |||
} | |||
} | |||
c->c_phase = phase; | |||
return (w+4); | |||
} | |||
static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp) | |||
{ | |||
dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n); | |||
x->x_sortno = ugen_getsortno(); | |||
sigdelwrite_checkvecsize(x, sp[0]->s_n); | |||
sigdelwrite_updatesr(x, sp[0]->s_sr); | |||
} | |||
static void sigdelwrite_free(t_sigdelwrite *x) | |||
{ | |||
pd_unbind(&x->x_obj.ob_pd, x->x_sym); | |||
freebytes(x->x_cspace.c_vec, | |||
(x->x_cspace.c_n + XTRASAMPS) * sizeof(t_sample)); | |||
} | |||
static void sigdelwrite_setup(void) | |||
{ | |||
sigdelwrite_class = class_new(gensym("delwrite~"), | |||
(t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free, | |||
sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f); | |||
class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_clear, | |||
gensym("clear"), 0); | |||
} | |||
/* ----------------------------- delread~ ----------------------------- */ | |||
static t_class *sigdelread_class; | |||
typedef struct _sigdelread | |||
{ | |||
t_object x_obj; | |||
t_symbol *x_sym; | |||
t_float x_deltime; /* delay in msec */ | |||
int x_delsamps; /* delay in samples */ | |||
t_float x_sr; /* samples per msec */ | |||
t_float x_n; /* vector size */ | |||
int x_zerodel; /* 0 or vecsize depending on read/write order */ | |||
} t_sigdelread; | |||
static void sigdelread_float(t_sigdelread *x, t_float f); | |||
static void *sigdelread_new(t_symbol *s, t_floatarg f) | |||
{ | |||
t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class); | |||
x->x_sym = s; | |||
x->x_sr = 1; | |||
x->x_n = 1; | |||
x->x_zerodel = 0; | |||
sigdelread_float(x, f); | |||
outlet_new(&x->x_obj, &s_signal); | |||
return (x); | |||
} | |||
static void sigdelread_float(t_sigdelread *x, t_float f) | |||
{ | |||
int samps; | |||
t_sigdelwrite *delwriter = | |||
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class); | |||
x->x_deltime = f; | |||
if (delwriter) | |||
{ | |||
int delsize = delwriter->x_cspace.c_n; | |||
x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime) | |||
+ x->x_n - x->x_zerodel; | |||
if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n; | |||
else if (x->x_delsamps > delwriter->x_cspace.c_n) | |||
x->x_delsamps = delwriter->x_cspace.c_n; | |||
} | |||
} | |||
static t_int *sigdelread_perform(t_int *w) | |||
{ | |||
t_sample *out = (t_sample *)(w[1]); | |||
t_delwritectl *c = (t_delwritectl *)(w[2]); | |||
int delsamps = *(int *)(w[3]); | |||
int n = (int)(w[4]); | |||
int phase = c->c_phase - delsamps, nsamps = c->c_n; | |||
t_sample *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS); | |||
if (phase < 0) phase += nsamps; | |||
bp = vp + phase; | |||
while (n--) | |||
{ | |||
*out++ = *bp++; | |||
if (bp == ep) bp -= nsamps; | |||
} | |||
return (w+5); | |||
} | |||
static void sigdelread_dsp(t_sigdelread *x, t_signal **sp) | |||
{ | |||
t_sigdelwrite *delwriter = | |||
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class); | |||
x->x_sr = sp[0]->s_sr * 0.001; | |||
x->x_n = sp[0]->s_n; | |||
if (delwriter) | |||
{ | |||
sigdelwrite_updatesr(delwriter, sp[0]->s_sr); | |||
sigdelwrite_checkvecsize(delwriter, sp[0]->s_n); | |||
x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ? | |||
0 : delwriter->x_vecsize); | |||
sigdelread_float(x, x->x_deltime); | |||
dsp_add(sigdelread_perform, 4, | |||
sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n); | |||
} | |||
else if (*x->x_sym->s_name) | |||
error("delread~: %s: no such delwrite~",x->x_sym->s_name); | |||
} | |||
static void sigdelread_setup(void) | |||
{ | |||
sigdelread_class = class_new(gensym("delread~"), | |||
(t_newmethod)sigdelread_new, 0, | |||
sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0); | |||
class_addmethod(sigdelread_class, (t_method)sigdelread_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addfloat(sigdelread_class, (t_method)sigdelread_float); | |||
} | |||
/* ----------------------------- vd~ ----------------------------- */ | |||
static t_class *sigvd_class; | |||
typedef struct _sigvd | |||
{ | |||
t_object x_obj; | |||
t_symbol *x_sym; | |||
t_float x_sr; /* samples per msec */ | |||
int x_zerodel; /* 0 or vecsize depending on read/write order */ | |||
t_float x_f; | |||
} t_sigvd; | |||
static void *sigvd_new(t_symbol *s) | |||
{ | |||
t_sigvd *x = (t_sigvd *)pd_new(sigvd_class); | |||
x->x_sym = s; | |||
x->x_sr = 1; | |||
x->x_zerodel = 0; | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigvd_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
t_delwritectl *ctl = (t_delwritectl *)(w[3]); | |||
t_sigvd *x = (t_sigvd *)(w[4]); | |||
int n = (int)(w[5]); | |||
int nsamps = ctl->c_n; | |||
t_sample limit = nsamps - n; | |||
t_sample fn = n-1; | |||
t_sample *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase; | |||
t_sample zerodel = x->x_zerodel; | |||
while (n--) | |||
{ | |||
t_sample delsamps = x->x_sr * *in++ - zerodel, frac; | |||
int idelsamps; | |||
t_sample a, b, c, d, cminusb; | |||
if (!(delsamps >= 1.00001f)) /* too small or NAN */ | |||
delsamps = 1.00001f; | |||
if (delsamps > limit) /* too big */ | |||
delsamps = limit; | |||
delsamps += fn; | |||
fn = fn - 1.0f; | |||
idelsamps = delsamps; | |||
frac = delsamps - (t_sample)idelsamps; | |||
bp = wp - idelsamps; | |||
if (bp < vp + 4) bp += nsamps; | |||
d = bp[-3]; | |||
c = bp[-2]; | |||
b = bp[-1]; | |||
a = bp[0]; | |||
cminusb = c-b; | |||
*out++ = b + frac * ( | |||
cminusb - 0.1666667f * (1.-frac) * ( | |||
(d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b) | |||
) | |||
); | |||
} | |||
return (w+6); | |||
} | |||
static void sigvd_dsp(t_sigvd *x, t_signal **sp) | |||
{ | |||
t_sigdelwrite *delwriter = | |||
(t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class); | |||
x->x_sr = sp[0]->s_sr * 0.001; | |||
if (delwriter) | |||
{ | |||
sigdelwrite_checkvecsize(delwriter, sp[0]->s_n); | |||
x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ? | |||
0 : delwriter->x_vecsize); | |||
dsp_add(sigvd_perform, 5, | |||
sp[0]->s_vec, sp[1]->s_vec, | |||
&delwriter->x_cspace, x, sp[0]->s_n); | |||
} | |||
else if (*x->x_sym->s_name) | |||
error("vd~: %s: no such delwrite~",x->x_sym->s_name); | |||
} | |||
static void sigvd_setup(void) | |||
{ | |||
sigvd_class = class_new(gensym("delread4~"), (t_newmethod)sigvd_new, 0, | |||
sizeof(t_sigvd), 0, A_DEFSYM, 0); | |||
class_addcreator((t_newmethod)sigvd_new, gensym("vd~"), A_DEFSYM, 0); | |||
class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), A_CANT, 0); | |||
CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f); | |||
} | |||
/* ----------------------- global setup routine ---------------- */ | |||
void d_delay_setup(void) | |||
{ | |||
sigdelwrite_setup(); | |||
sigdelread_setup(); | |||
sigvd_setup(); | |||
} | |||
@@ -0,0 +1,355 @@ | |||
/* Copyright (c) 1997- Miller Puckette and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#include "m_pd.h" | |||
/* This file interfaces to one of the Mayer, Ooura, or fftw FFT packages | |||
to implement the "fft~", etc, Pd objects. If using Mayer, also compile | |||
d_fft_mayer.c; if ooura, use d_fft_fftsg.c instead; if fftw, use d_fft_fftw.c | |||
and also link in the fftw library. You can only have one of these three | |||
linked in. The configure script can be used to select which one. | |||
*/ | |||
/* ---------------- utility functions for DSP chains ---------------------- */ | |||
/* swap two arrays */ | |||
static t_int *sigfft_swap(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
int n = (int)w[3]; | |||
for (;n--; in1++, in2++) | |||
{ | |||
t_sample f = *in1; | |||
*in1 = *in2; | |||
*in2 = f; | |||
} | |||
return (w+4); | |||
} | |||
/* take array1 (supply a pointer to beginning) and copy it, | |||
into decreasing addresses, into array 2 (supply a pointer one past the | |||
end), and negate the sign. */ | |||
static t_int *sigrfft_flip(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)w[3]; | |||
while (n--) | |||
*(--out) = - *in++; | |||
return (w+4); | |||
} | |||
/* ------------------------ fft~ and ifft~ -------------------------------- */ | |||
static t_class *sigfft_class, *sigifft_class; | |||
typedef struct fft | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_sigfft; | |||
static void *sigfft_new(void) | |||
{ | |||
t_sigfft *x = (t_sigfft *)pd_new(sigfft_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static void *sigifft_new(void) | |||
{ | |||
t_sigfft *x = (t_sigfft *)pd_new(sigifft_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigfft_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
int n = (int)w[3]; | |||
mayer_fft(n, in1, in2); | |||
return (w+4); | |||
} | |||
static t_int *sigifft_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
int n = (int)w[3]; | |||
mayer_ifft(n, in1, in2); | |||
return (w+4); | |||
} | |||
static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w)) | |||
{ | |||
int n = sp[0]->s_n; | |||
t_sample *in1 = sp[0]->s_vec; | |||
t_sample *in2 = sp[1]->s_vec; | |||
t_sample *out1 = sp[2]->s_vec; | |||
t_sample *out2 = sp[3]->s_vec; | |||
if (out1 == in2 && out2 == in1) | |||
dsp_add(sigfft_swap, 3, out1, out2, n); | |||
else if (out1 == in2) | |||
{ | |||
dsp_add(copy_perform, 3, in2, out2, n); | |||
dsp_add(copy_perform, 3, in1, out1, n); | |||
} | |||
else | |||
{ | |||
if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n); | |||
if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n); | |||
} | |||
dsp_add(f, 3, sp[2]->s_vec, sp[3]->s_vec, n); | |||
} | |||
static void sigfft_dsp(t_sigfft *x, t_signal **sp) | |||
{ | |||
sigfft_dspx(x, sp, sigfft_perform); | |||
} | |||
static void sigifft_dsp(t_sigfft *x, t_signal **sp) | |||
{ | |||
sigfft_dspx(x, sp, sigifft_perform); | |||
} | |||
static void sigfft_setup(void) | |||
{ | |||
sigfft_class = class_new(gensym("fft~"), sigfft_new, 0, | |||
sizeof(t_sigfft), 0, 0); | |||
CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, x_f); | |||
class_addmethod(sigfft_class, (t_method)sigfft_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
sigifft_class = class_new(gensym("ifft~"), sigifft_new, 0, | |||
sizeof(t_sigfft), 0, 0); | |||
CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, x_f); | |||
class_addmethod(sigifft_class, (t_method)sigifft_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(sigifft_class, gensym("fft~")); | |||
} | |||
/* ----------------------- rfft~ -------------------------------- */ | |||
static t_class *sigrfft_class; | |||
typedef struct rfft | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_sigrfft; | |||
static void *sigrfft_new(void) | |||
{ | |||
t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigrfft_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
int n = (int)w[2]; | |||
mayer_realfft(n, in); | |||
return (w+3); | |||
} | |||
static void sigrfft_dsp(t_sigrfft *x, t_signal **sp) | |||
{ | |||
int n = sp[0]->s_n, n2 = (n>>1); | |||
t_sample *in1 = sp[0]->s_vec; | |||
t_sample *out1 = sp[1]->s_vec; | |||
t_sample *out2 = sp[2]->s_vec; | |||
if (n < 4) | |||
{ | |||
error("fft: minimum 4 points"); | |||
return; | |||
} | |||
if (in1 != out1) | |||
dsp_add(copy_perform, 3, in1, out1, n); | |||
dsp_add(sigrfft_perform, 2, out1, n); | |||
dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1); | |||
dsp_add_zero(out1 + (n2+1), ((n2-1)&(~7))); | |||
dsp_add_zero(out1 + (n2+1) + ((n2-1)&(~7)), ((n2-1)&7)); | |||
dsp_add_zero(out2 + n2, n2); | |||
dsp_add_zero(out2, 1); | |||
} | |||
static void sigrfft_setup(void) | |||
{ | |||
sigrfft_class = class_new(gensym("rfft~"), sigrfft_new, 0, | |||
sizeof(t_sigrfft), 0, 0); | |||
CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, x_f); | |||
class_addmethod(sigrfft_class, (t_method)sigrfft_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(sigrfft_class, gensym("fft~")); | |||
} | |||
/* ----------------------- rifft~ -------------------------------- */ | |||
static t_class *sigrifft_class; | |||
typedef struct rifft | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_sigrifft; | |||
static void *sigrifft_new(void) | |||
{ | |||
t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigrifft_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
int n = (int)w[2]; | |||
mayer_realifft(n, in); | |||
return (w+3); | |||
} | |||
static void sigrifft_dsp(t_sigrifft *x, t_signal **sp) | |||
{ | |||
int n = sp[0]->s_n, n2 = (n>>1); | |||
t_sample *in1 = sp[0]->s_vec; | |||
t_sample *in2 = sp[1]->s_vec; | |||
t_sample *out1 = sp[2]->s_vec; | |||
if (n < 4) | |||
{ | |||
error("fft: minimum 4 points"); | |||
return; | |||
} | |||
if (in2 == out1) | |||
{ | |||
dsp_add(sigrfft_flip, 3, out1+1, out1 + n, n2-1); | |||
dsp_add(copy_perform, 3, in1, out1, n2+1); | |||
} | |||
else | |||
{ | |||
if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2+1); | |||
dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1); | |||
} | |||
dsp_add(sigrifft_perform, 2, out1, n); | |||
} | |||
static void sigrifft_setup(void) | |||
{ | |||
sigrifft_class = class_new(gensym("rifft~"), sigrifft_new, 0, | |||
sizeof(t_sigrifft), 0, 0); | |||
CLASS_MAINSIGNALIN(sigrifft_class, t_sigrifft, x_f); | |||
class_addmethod(sigrifft_class, (t_method)sigrifft_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(sigrifft_class, gensym("fft~")); | |||
} | |||
/* ----------------------- framp~ -------------------------------- */ | |||
static t_class *sigframp_class; | |||
typedef struct framp | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_sigframp; | |||
static void *sigframp_new(void) | |||
{ | |||
t_sigframp *x = (t_sigframp *)pd_new(sigframp_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigframp_perform(t_int *w) | |||
{ | |||
t_sample *inreal = (t_sample *)(w[1]); | |||
t_sample *inimag = (t_sample *)(w[2]); | |||
t_sample *outfreq = (t_sample *)(w[3]); | |||
t_sample *outamp = (t_sample *)(w[4]); | |||
t_sample lastreal = 0, currentreal = inreal[0], nextreal = inreal[1]; | |||
t_sample lastimag = 0, currentimag = inimag[0], nextimag = inimag[1]; | |||
int n = (int)w[5]; | |||
int m = n + 1; | |||
t_sample fbin = 1, oneovern2 = 1.f/((t_sample)n * (t_sample)n); | |||
inreal += 2; | |||
inimag += 2; | |||
*outamp++ = *outfreq++ = 0; | |||
n -= 2; | |||
while (n--) | |||
{ | |||
t_sample re, im, pow, freq; | |||
lastreal = currentreal; | |||
currentreal = nextreal; | |||
nextreal = *inreal++; | |||
lastimag = currentimag; | |||
currentimag = nextimag; | |||
nextimag = *inimag++; | |||
re = currentreal - 0.5f * (lastreal + nextreal); | |||
im = currentimag - 0.5f * (lastimag + nextimag); | |||
pow = re * re + im * im; | |||
if (pow > 1e-19) | |||
{ | |||
t_sample detune = ((lastreal - nextreal) * re + | |||
(lastimag - nextimag) * im) / (2.0f * pow); | |||
if (detune > 2 || detune < -2) freq = pow = 0; | |||
else freq = fbin + detune; | |||
} | |||
else freq = pow = 0; | |||
*outfreq++ = freq; | |||
*outamp++ = oneovern2 * pow; | |||
fbin += 1.0f; | |||
} | |||
while (m--) *outamp++ = *outfreq++ = 0; | |||
return (w+6); | |||
} | |||
t_int *sigsqrt_perform(t_int *w); | |||
static void sigframp_dsp(t_sigframp *x, t_signal **sp) | |||
{ | |||
int n = sp[0]->s_n, n2 = (n>>1); | |||
if (n < 4) | |||
{ | |||
error("framp: minimum 4 points"); | |||
return; | |||
} | |||
dsp_add(sigframp_perform, 5, sp[0]->s_vec, sp[1]->s_vec, | |||
sp[2]->s_vec, sp[3]->s_vec, n2); | |||
dsp_add(sigsqrt_perform, 3, sp[3]->s_vec, sp[3]->s_vec, n2); | |||
} | |||
static void sigframp_setup(void) | |||
{ | |||
sigframp_class = class_new(gensym("framp~"), sigframp_new, 0, | |||
sizeof(t_sigframp), 0, 0); | |||
CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, x_f); | |||
class_addmethod(sigframp_class, (t_method)sigframp_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------ global setup routine ------------------------- */ | |||
void d_fft_setup(void) | |||
{ | |||
sigfft_setup(); | |||
sigrfft_setup(); | |||
sigrifft_setup(); | |||
sigframp_setup(); | |||
} |
@@ -0,0 +1,185 @@ | |||
/* Copyright (c) 1997- Miller Puckette and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* --------- Pd interface to FFTW library; imitate Mayer API ---------- */ | |||
/* changes and additions for FFTW3 by Thomas Grill */ | |||
#include "m_pd.h" | |||
#include <fftw3.h> | |||
int ilog2(int n); | |||
#define MINFFT 0 | |||
#define MAXFFT 30 | |||
/* from the FFTW website: | |||
#include <fftw3.h> | |||
... | |||
{ | |||
fftw_complex *in, *out; | |||
fftw_plan p; | |||
... | |||
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); | |||
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N); | |||
p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE); | |||
... | |||
fftw_execute(p); | |||
... | |||
fftw_destroy_plan(p); | |||
fftw_free(in); fftw_free(out); | |||
} | |||
FFTW_FORWARD or FFTW_BACKWARD, and indicates the direction of the transform you | |||
are interested in. Alternatively, you can use the sign of the exponent in the | |||
transform, -1 or +1, which corresponds to FFTW_FORWARD or FFTW_BACKWARD | |||
respectively. The flags argument is either FFTW_MEASURE | |||
*/ | |||
/* complex stuff */ | |||
typedef struct { | |||
fftwf_plan plan; | |||
fftwf_complex *in,*out; | |||
} cfftw_info; | |||
static cfftw_info cfftw_fwd[MAXFFT+1 - MINFFT],cfftw_bwd[MAXFFT+1 - MINFFT]; | |||
static cfftw_info *cfftw_getplan(int n,int fwd) | |||
{ | |||
cfftw_info *info; | |||
int logn = ilog2(n); | |||
if (logn < MINFFT || logn > MAXFFT) | |||
return (0); | |||
info = (fwd?cfftw_fwd:cfftw_bwd)+(logn-MINFFT); | |||
if (!info->plan) | |||
{ | |||
pd_globallock(); | |||
if (!info->plan) /* recheck in case it got set while we waited */ | |||
{ | |||
info->in = | |||
(fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n); | |||
info->out = | |||
(fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * n); | |||
info->plan = fftwf_plan_dft_1d(n, info->in, info->out, | |||
fwd?FFTW_FORWARD:FFTW_BACKWARD, FFTW_MEASURE); | |||
} | |||
pd_globalunlock(); | |||
} | |||
return info; | |||
} | |||
/* real stuff */ | |||
typedef struct { | |||
fftwf_plan plan; | |||
float *in,*out; | |||
} rfftw_info; | |||
static rfftw_info rfftw_fwd[MAXFFT+1 - MINFFT],rfftw_bwd[MAXFFT+1 - MINFFT]; | |||
static rfftw_info *rfftw_getplan(int n,int fwd) | |||
{ | |||
rfftw_info *info; | |||
int logn = ilog2(n); | |||
if (logn < MINFFT || logn > MAXFFT) | |||
return (0); | |||
info = (fwd?rfftw_fwd:rfftw_bwd)+(logn-MINFFT); | |||
if (!info->plan) | |||
{ | |||
info->in = (float*) fftwf_malloc(sizeof(float) * n); | |||
info->out = (float*) fftwf_malloc(sizeof(float) * n); | |||
info->plan = fftwf_plan_r2r_1d(n, info->in, info->out, fwd?FFTW_R2HC:FFTW_HC2R, FFTW_MEASURE); | |||
} | |||
return info; | |||
} | |||
EXTERN void mayer_fht(float *fz, int n) | |||
{ | |||
post("FHT: not yet implemented"); | |||
} | |||
static void mayer_do_cfft(int n, float *fz1, float *fz2, int fwd) | |||
{ | |||
int i; | |||
float *fz; | |||
cfftw_info *p = cfftw_getplan(n, fwd); | |||
if (!p) | |||
return; | |||
for (i = 0, fz = (float *)p->in; i < n; i++) | |||
fz[i*2] = fz1[i], fz[i*2+1] = fz2[i]; | |||
fftwf_execute(p->plan); | |||
for (i = 0, fz = (float *)p->out; i < n; i++) | |||
fz1[i] = fz[i*2], fz2[i] = fz[i*2+1]; | |||
} | |||
EXTERN void mayer_fft(int n, float *fz1, float *fz2) | |||
{ | |||
mayer_do_cfft(n, fz1, fz2, 1); | |||
} | |||
EXTERN void mayer_ifft(int n, float *fz1, float *fz2) | |||
{ | |||
mayer_do_cfft(n, fz1, fz2, 0); | |||
} | |||
/* | |||
in the following the sign flips are done to | |||
be compatible with the mayer_fft implementation, | |||
but it's probably the mayer_fft that should be corrected... | |||
*/ | |||
EXTERN void mayer_realfft(int n, float *fz) | |||
{ | |||
int i; | |||
rfftw_info *p = rfftw_getplan(n, 1); | |||
if (!p) | |||
return; | |||
for (i = 0; i < n; i++) | |||
p->in[i] = fz[i]; | |||
fftwf_execute(p->plan); | |||
for (i = 0; i < n/2+1; i++) | |||
fz[i] = p->out[i]; | |||
for (; i < n; i++) | |||
fz[i] = -p->out[i]; | |||
} | |||
EXTERN void mayer_realifft(int n, float *fz) | |||
{ | |||
int i; | |||
rfftw_info *p = rfftw_getplan(n, 0); | |||
if (!p) | |||
return; | |||
for (i = 0; i < n/2+1; i++) | |||
p->in[i] = fz[i]; | |||
for (; i < n; i++) | |||
p->in[i] = -fz[i]; | |||
fftwf_execute(p->plan); | |||
for (i = 0; i < n; i++) | |||
fz[i] = p->out[i]; | |||
} | |||
/* ancient ISPW-like version, used in fiddle~ and perhaps other externs | |||
here and there. */ | |||
void pd_fft(t_float *buf, int npoints, int inverse) | |||
{ | |||
cfftw_info *p = cfftw_getplan(npoints, !inverse); | |||
int i; | |||
float *fz; | |||
for (i = 0, fz = (float *)(p->in); i < 2 * npoints; i++) | |||
*fz++ = buf[i]; | |||
fftwf_execute(p->plan); | |||
for (i = 0, fz = (float *)(p->out); i < 2 * npoints; i++) | |||
buf[i] = *fz++; | |||
} | |||
@@ -0,0 +1,361 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* send~, receive~, throw~, catch~ */ | |||
#include "m_pd.h" | |||
#include <string.h> | |||
#define DEFSENDVS 64 /* LATER get send to get this from canvas */ | |||
/* ----------------------------- send~ ----------------------------- */ | |||
static t_class *sigsend_class; | |||
typedef struct _sigsend | |||
{ | |||
t_object x_obj; | |||
t_symbol *x_sym; | |||
int x_n; | |||
t_sample *x_vec; | |||
t_float x_f; | |||
} t_sigsend; | |||
static void *sigsend_new(t_symbol *s) | |||
{ | |||
t_sigsend *x = (t_sigsend *)pd_new(sigsend_class); | |||
pd_bind(&x->x_obj.ob_pd, s); | |||
x->x_sym = s; | |||
x->x_n = DEFSENDVS; | |||
x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample)); | |||
memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample)); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigsend_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
while (n--) | |||
{ | |||
*out = (PD_BIGORSMALL(*in) ? 0 : *in); | |||
out++; | |||
in++; | |||
} | |||
return (w+4); | |||
} | |||
static void sigsend_dsp(t_sigsend *x, t_signal **sp) | |||
{ | |||
if (x->x_n == sp[0]->s_n) | |||
dsp_add(sigsend_perform, 3, sp[0]->s_vec, x->x_vec, sp[0]->s_n); | |||
else error("sigsend %s: unexpected vector size", x->x_sym->s_name); | |||
} | |||
static void sigsend_free(t_sigsend *x) | |||
{ | |||
pd_unbind(&x->x_obj.ob_pd, x->x_sym); | |||
freebytes(x->x_vec, x->x_n * sizeof(t_sample)); | |||
} | |||
static void sigsend_setup(void) | |||
{ | |||
sigsend_class = class_new(gensym("send~"), (t_newmethod)sigsend_new, | |||
(t_method)sigsend_free, sizeof(t_sigsend), 0, A_DEFSYM, 0); | |||
class_addcreator((t_newmethod)sigsend_new, gensym("s~"), A_DEFSYM, 0); | |||
CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, x_f); | |||
class_addmethod(sigsend_class, (t_method)sigsend_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ----------------------------- receive~ ----------------------------- */ | |||
static t_class *sigreceive_class; | |||
typedef struct _sigreceive | |||
{ | |||
t_object x_obj; | |||
t_symbol *x_sym; | |||
t_sample *x_wherefrom; | |||
int x_n; | |||
} t_sigreceive; | |||
static void *sigreceive_new(t_symbol *s) | |||
{ | |||
t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class); | |||
x->x_n = DEFSENDVS; /* LATER find our vector size correctly */ | |||
x->x_sym = s; | |||
x->x_wherefrom = 0; | |||
outlet_new(&x->x_obj, &s_signal); | |||
return (x); | |||
} | |||
static t_int *sigreceive_perform(t_int *w) | |||
{ | |||
t_sigreceive *x = (t_sigreceive *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_sample *in = x->x_wherefrom; | |||
if (in) | |||
{ | |||
while (n--) | |||
*out++ = *in++; | |||
} | |||
else | |||
{ | |||
while (n--) | |||
*out++ = 0; | |||
} | |||
return (w+4); | |||
} | |||
/* tb: vectorized receive function */ | |||
static t_int *sigreceive_perf8(t_int *w) | |||
{ | |||
t_sigreceive *x = (t_sigreceive *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_sample *in = x->x_wherefrom; | |||
if (in) | |||
{ | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; out[3] = in[3]; | |||
out[4] = in[4]; out[5] = in[5]; out[6] = in[6]; out[7] = in[7]; | |||
} | |||
} | |||
else | |||
{ | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 0; | |||
out[4] = 0; out[5] = 0; out[6] = 0; out[7] = 0; | |||
} | |||
} | |||
return (w+4); | |||
} | |||
static void sigreceive_set(t_sigreceive *x, t_symbol *s) | |||
{ | |||
t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->x_sym = s), | |||
sigsend_class); | |||
if (sender) | |||
{ | |||
if (sender->x_n == x->x_n) | |||
x->x_wherefrom = sender->x_vec; | |||
else | |||
{ | |||
pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name); | |||
x->x_wherefrom = 0; | |||
} | |||
} | |||
else | |||
{ | |||
pd_error(x, "receive~ %s: no matching send", x->x_sym->s_name); | |||
x->x_wherefrom = 0; | |||
} | |||
} | |||
static void sigreceive_dsp(t_sigreceive *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n != x->x_n) | |||
{ | |||
pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name); | |||
} | |||
else | |||
{ | |||
sigreceive_set(x, x->x_sym); | |||
if (sp[0]->s_n&7) | |||
dsp_add(sigreceive_perform, 3, | |||
x, sp[0]->s_vec, sp[0]->s_n); | |||
else dsp_add(sigreceive_perf8, 3, | |||
x, sp[0]->s_vec, sp[0]->s_n); | |||
} | |||
} | |||
static void sigreceive_setup(void) | |||
{ | |||
sigreceive_class = class_new(gensym("receive~"), | |||
(t_newmethod)sigreceive_new, 0, | |||
sizeof(t_sigreceive), 0, A_DEFSYM, 0); | |||
class_addcreator((t_newmethod)sigreceive_new, gensym("r~"), A_DEFSYM, 0); | |||
class_addmethod(sigreceive_class, (t_method)sigreceive_set, gensym("set"), | |||
A_SYMBOL, 0); | |||
class_addmethod(sigreceive_class, (t_method)sigreceive_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(sigreceive_class, gensym("send~")); | |||
} | |||
/* ----------------------------- catch~ ----------------------------- */ | |||
static t_class *sigcatch_class; | |||
typedef struct _sigcatch | |||
{ | |||
t_object x_obj; | |||
t_symbol *x_sym; | |||
int x_n; | |||
t_sample *x_vec; | |||
} t_sigcatch; | |||
static void *sigcatch_new(t_symbol *s) | |||
{ | |||
t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class); | |||
pd_bind(&x->x_obj.ob_pd, s); | |||
x->x_sym = s; | |||
x->x_n = DEFSENDVS; | |||
x->x_vec = (t_sample *)getbytes(DEFSENDVS * sizeof(t_sample)); | |||
memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(t_sample)); | |||
outlet_new(&x->x_obj, &s_signal); | |||
return (x); | |||
} | |||
static t_int *sigcatch_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
while (n--) *out++ = *in, *in++ = 0; | |||
return (w+4); | |||
} | |||
/* tb: vectorized catch function */ | |||
static t_int *sigcatch_perf8(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
for (; n; n -= 8, in += 8, out += 8) | |||
{ | |||
out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; out[3] = in[3]; | |||
out[4] = in[4]; out[5] = in[5]; out[6] = in[6]; out[7] = in[7]; | |||
in[0] = 0; in[1] = 0; in[2] = 0; in[3] = 0; | |||
in[4] = 0; in[5] = 0; in[6] = 0; in[7] = 0; | |||
} | |||
return (w+4); | |||
} | |||
static void sigcatch_dsp(t_sigcatch *x, t_signal **sp) | |||
{ | |||
if (x->x_n == sp[0]->s_n) | |||
{ | |||
if(sp[0]->s_n&7) | |||
dsp_add(sigcatch_perform, 3, x->x_vec, sp[0]->s_vec, sp[0]->s_n); | |||
else | |||
dsp_add(sigcatch_perf8, 3, x->x_vec, sp[0]->s_vec, sp[0]->s_n); | |||
} | |||
else error("sigcatch %s: unexpected vector size", x->x_sym->s_name); | |||
} | |||
static void sigcatch_free(t_sigcatch *x) | |||
{ | |||
pd_unbind(&x->x_obj.ob_pd, x->x_sym); | |||
freebytes(x->x_vec, x->x_n * sizeof(t_sample)); | |||
} | |||
static void sigcatch_setup(void) | |||
{ | |||
sigcatch_class = class_new(gensym("catch~"), (t_newmethod)sigcatch_new, | |||
(t_method)sigcatch_free, sizeof(t_sigcatch), CLASS_NOINLET, A_DEFSYM, 0); | |||
class_addmethod(sigcatch_class, (t_method)sigcatch_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(sigcatch_class, gensym("throw~")); | |||
} | |||
/* ----------------------------- throw~ ----------------------------- */ | |||
static t_class *sigthrow_class; | |||
typedef struct _sigthrow | |||
{ | |||
t_object x_obj; | |||
t_symbol *x_sym; | |||
t_sample *x_whereto; | |||
int x_n; | |||
t_float x_f; | |||
} t_sigthrow; | |||
static void *sigthrow_new(t_symbol *s) | |||
{ | |||
t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class); | |||
x->x_sym = s; | |||
x->x_whereto = 0; | |||
x->x_n = DEFSENDVS; | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigthrow_perform(t_int *w) | |||
{ | |||
t_sigthrow *x = (t_sigthrow *)(w[1]); | |||
t_sample *in = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_sample *out = x->x_whereto; | |||
if (out) | |||
{ | |||
while (n--) | |||
{ | |||
*out += (PD_BIGORSMALL(*in) ? 0 : *in); | |||
out++; | |||
in++; | |||
} | |||
} | |||
return (w+4); | |||
} | |||
static void sigthrow_set(t_sigthrow *x, t_symbol *s) | |||
{ | |||
t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass((x->x_sym = s), | |||
sigcatch_class); | |||
if (catcher) | |||
{ | |||
if (catcher->x_n == x->x_n) | |||
x->x_whereto = catcher->x_vec; | |||
else | |||
{ | |||
pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name); | |||
x->x_whereto = 0; | |||
} | |||
} | |||
else | |||
{ | |||
pd_error(x, "throw~ %s: no matching catch", x->x_sym->s_name); | |||
x->x_whereto = 0; | |||
} | |||
} | |||
static void sigthrow_dsp(t_sigthrow *x, t_signal **sp) | |||
{ | |||
if (sp[0]->s_n != x->x_n) | |||
{ | |||
pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name); | |||
} | |||
else | |||
{ | |||
sigthrow_set(x, x->x_sym); | |||
dsp_add(sigthrow_perform, 3, | |||
x, sp[0]->s_vec, sp[0]->s_n); | |||
} | |||
} | |||
static void sigthrow_setup(void) | |||
{ | |||
sigthrow_class = class_new(gensym("throw~"), (t_newmethod)sigthrow_new, 0, | |||
sizeof(t_sigthrow), 0, A_DEFSYM, 0); | |||
class_addmethod(sigthrow_class, (t_method)sigthrow_set, gensym("set"), | |||
A_SYMBOL, 0); | |||
CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, x_f); | |||
class_addmethod(sigthrow_class, (t_method)sigthrow_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ----------------------- global setup routine ---------------- */ | |||
void d_global_setup(void) | |||
{ | |||
sigsend_setup(); | |||
sigreceive_setup(); | |||
sigcatch_setup(); | |||
sigthrow_setup(); | |||
} | |||
@@ -0,0 +1,806 @@ | |||
/* Copyright (c) 1997-2001 Miller Puckette and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* mathematical functions and other transfer functions, including tilde | |||
versions of stuff from x_acoustics.c. | |||
*/ | |||
#include "m_pd.h" | |||
#include <math.h> | |||
#define LOGTEN 2.302585092994 | |||
/* ------------------------- clip~ -------------------------- */ | |||
static t_class *clip_class; | |||
typedef struct _clip | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
t_float x_lo; | |||
t_float x_hi; | |||
} t_clip; | |||
static void *clip_new(t_floatarg lo, t_floatarg hi) | |||
{ | |||
t_clip *x = (t_clip *)pd_new(clip_class); | |||
x->x_lo = lo; | |||
x->x_hi = hi; | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
floatinlet_new(&x->x_obj, &x->x_lo); | |||
floatinlet_new(&x->x_obj, &x->x_hi); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *clip_perform(t_int *w) | |||
{ | |||
t_clip *x = (t_clip *)(w[1]); | |||
t_sample *in = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) | |||
{ | |||
t_sample f = *in++; | |||
if (f < x->x_lo) f = x->x_lo; | |||
if (f > x->x_hi) f = x->x_hi; | |||
*out++ = f; | |||
} | |||
return (w+5); | |||
} | |||
static void clip_dsp(t_clip *x, t_signal **sp) | |||
{ | |||
dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void clip_setup(void) | |||
{ | |||
clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0, | |||
sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(clip_class, t_clip, x_f); | |||
class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), A_CANT, 0); | |||
} | |||
/* sigrsqrt - reciprocal square root good to 8 mantissa bits */ | |||
#define DUMTAB1SIZE 256 | |||
#define DUMTAB2SIZE 1024 | |||
/* These are only written at setup time when there's a global lock in place. */ | |||
static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE]; | |||
static void init_rsqrt(void) | |||
{ | |||
int i; | |||
for (i = 0; i < DUMTAB1SIZE; i++) | |||
{ | |||
union { | |||
float f; | |||
long l; | |||
} u; | |||
int32_t l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23; | |||
u.l = l; | |||
rsqrt_exptab[i] = 1./sqrt(u.f); | |||
} | |||
for (i = 0; i < DUMTAB2SIZE; i++) | |||
{ | |||
float f = 1 + (1./DUMTAB2SIZE) * i; | |||
rsqrt_mantissatab[i] = 1./sqrt(f); | |||
} | |||
} | |||
/* these are used in externs like "bonk" */ | |||
t_float q8_rsqrt(t_float f0) | |||
{ | |||
union { | |||
float f; | |||
long l; | |||
} u; | |||
u.f=f0; | |||
if (u.f < 0) return (0); | |||
else return (rsqrt_exptab[(u.l >> 23) & 0xff] * | |||
rsqrt_mantissatab[(u.l >> 13) & 0x3ff]); | |||
} | |||
t_float q8_sqrt(t_float f0) | |||
{ | |||
union { | |||
float f; | |||
long l; | |||
} u; | |||
u.f=f0; | |||
if (u.f < 0) return (0); | |||
else return (u.f * rsqrt_exptab[(u.l >> 23) & 0xff] * | |||
rsqrt_mantissatab[(u.l >> 13) & 0x3ff]); | |||
} | |||
t_float qsqrt(t_float f) {return (q8_sqrt(f)); } | |||
t_float qrsqrt(t_float f) {return (q8_rsqrt(f)); } | |||
typedef struct sigrsqrt | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_sigrsqrt; | |||
static t_class *sigrsqrt_class; | |||
static void *sigrsqrt_new(void) | |||
{ | |||
t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigrsqrt_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = *(t_int *)(w+3); | |||
while (n--) | |||
{ | |||
t_sample f = *in++; | |||
union { | |||
float f; | |||
long l; | |||
} u; | |||
u.f = f; | |||
if (f < 0) *out++ = 0; | |||
else | |||
{ | |||
t_sample g = rsqrt_exptab[(u.l >> 23) & 0xff] * | |||
rsqrt_mantissatab[(u.l >> 13) & 0x3ff]; | |||
*out++ = 1.5 * g - 0.5 * g * g * g * f; | |||
} | |||
} | |||
return (w + 4); | |||
} | |||
static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp) | |||
{ | |||
dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void sigrsqrt_setup(void) | |||
{ | |||
init_rsqrt(); | |||
sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0, | |||
sizeof(t_sigrsqrt), 0, 0); | |||
/* an old name for it: */ | |||
class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0); | |||
CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f); | |||
class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* sigsqrt - square root good to 8 mantissa bits */ | |||
typedef struct sigsqrt | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_sigsqrt; | |||
static t_class *sigsqrt_class; | |||
static void *sigsqrt_new(void) | |||
{ | |||
t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */ | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = *(t_int *)(w+3); | |||
while (n--) | |||
{ | |||
t_sample f = *in++; | |||
union { | |||
float f; | |||
long l; | |||
} u; | |||
u.f = f; | |||
if (f < 0) *out++ = 0; | |||
else | |||
{ | |||
t_sample g = rsqrt_exptab[(u.l >> 23) & 0xff] * | |||
rsqrt_mantissatab[(u.l >> 13) & 0x3ff]; | |||
*out++ = f * (1.5 * g - 0.5 * g * g * g * f); | |||
} | |||
} | |||
return (w + 4); | |||
} | |||
static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp) | |||
{ | |||
dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void sigsqrt_setup(void) | |||
{ | |||
sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0, | |||
sizeof(t_sigsqrt), 0, 0); | |||
class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */ | |||
CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f); | |||
class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------------ wrap~ -------------------------- */ | |||
typedef struct wrap | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_sigwrap; | |||
t_class *sigwrap_class; | |||
static void *sigwrap_new(void) | |||
{ | |||
t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *sigwrap_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = (t_int)w[3]; | |||
while (n--) | |||
{ | |||
t_sample f = *in++; | |||
int k = f; | |||
if (k <= f) *out++ = f-k; | |||
else *out++ = f - (k-1); | |||
} | |||
return (w + 4); | |||
} | |||
/* old buggy version that sometimes output 1 instead of 0 */ | |||
static t_int *sigwrap_old_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = (t_int)w[3]; | |||
while (n--) | |||
{ | |||
t_sample f = *in++; | |||
int k = f; | |||
if (f > 0) *out++ = f-k; | |||
else *out++ = f - (k-1); | |||
} | |||
return (w + 4); | |||
} | |||
static void sigwrap_dsp(t_sigwrap *x, t_signal **sp) | |||
{ | |||
dsp_add((pd_compatibilitylevel < 48 ? | |||
sigwrap_old_perform : sigwrap_perform), | |||
3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void sigwrap_setup(void) | |||
{ | |||
sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0, | |||
sizeof(t_sigwrap), 0, 0); | |||
CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f); | |||
class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------------ mtof_tilde~ -------------------------- */ | |||
typedef struct mtof_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_mtof_tilde; | |||
t_class *mtof_tilde_class; | |||
static void *mtof_tilde_new(void) | |||
{ | |||
t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *mtof_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = (t_int)w[3]; | |||
for (; n--; in++, out++) | |||
{ | |||
t_sample f = *in; | |||
if (f <= -1500) *out = 0; | |||
else | |||
{ | |||
if (f > 1499) f = 1499; | |||
*out = 8.17579891564 * exp(.0577622650 * f); | |||
} | |||
} | |||
return (w + 4); | |||
} | |||
static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void mtof_tilde_setup(void) | |||
{ | |||
mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0, | |||
sizeof(t_mtof_tilde), 0, 0); | |||
CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f); | |||
class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------------ ftom_tilde~ -------------------------- */ | |||
typedef struct ftom_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_ftom_tilde; | |||
t_class *ftom_tilde_class; | |||
static void *ftom_tilde_new(void) | |||
{ | |||
t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *ftom_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = (t_int)w[3]; | |||
for (; n--; in++, out++) | |||
{ | |||
t_sample f = *in; | |||
*out = (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500); | |||
} | |||
return (w + 4); | |||
} | |||
static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void ftom_tilde_setup(void) | |||
{ | |||
ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0, | |||
sizeof(t_ftom_tilde), 0, 0); | |||
CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f); | |||
class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------------ dbtorms~ -------------------------- */ | |||
typedef struct dbtorms_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_dbtorms_tilde; | |||
t_class *dbtorms_tilde_class; | |||
static void *dbtorms_tilde_new(void) | |||
{ | |||
t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *dbtorms_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = (t_int)w[3]; | |||
for (; n--; in++, out++) | |||
{ | |||
t_sample f = *in; | |||
if (f <= 0) *out = 0; | |||
else | |||
{ | |||
if (f > 485) | |||
f = 485; | |||
*out = exp((LOGTEN * 0.05) * (f-100.)); | |||
} | |||
} | |||
return (w + 4); | |||
} | |||
static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void dbtorms_tilde_setup(void) | |||
{ | |||
dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0, | |||
sizeof(t_dbtorms_tilde), 0, 0); | |||
CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f); | |||
class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------------ rmstodb~ -------------------------- */ | |||
typedef struct rmstodb_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_rmstodb_tilde; | |||
t_class *rmstodb_tilde_class; | |||
static void *rmstodb_tilde_new(void) | |||
{ | |||
t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *rmstodb_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = (t_int)w[3]; | |||
for (; n--; in++, out++) | |||
{ | |||
t_sample f = *in; | |||
if (f <= 0) *out = 0; | |||
else | |||
{ | |||
t_sample g = 100 + 20./LOGTEN * log(f); | |||
*out = (g < 0 ? 0 : g); | |||
} | |||
} | |||
return (w + 4); | |||
} | |||
static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void rmstodb_tilde_setup(void) | |||
{ | |||
rmstodb_tilde_class = class_new(gensym("rmstodb~"), | |||
(t_newmethod)rmstodb_tilde_new, 0, sizeof(t_rmstodb_tilde), 0, 0); | |||
CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f); | |||
class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------------ dbtopow~ -------------------------- */ | |||
typedef struct dbtopow_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_dbtopow_tilde; | |||
t_class *dbtopow_tilde_class; | |||
static void *dbtopow_tilde_new(void) | |||
{ | |||
t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *dbtopow_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = (t_int)w[3]; | |||
for (; n--; in++, out++) | |||
{ | |||
t_sample f = *in; | |||
if (f <= 0) *out = 0; | |||
else | |||
{ | |||
if (f > 870) | |||
f = 870; | |||
*out = exp((LOGTEN * 0.1) * (f-100.)); | |||
} | |||
} | |||
return (w + 4); | |||
} | |||
static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void dbtopow_tilde_setup(void) | |||
{ | |||
dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0, | |||
sizeof(t_dbtopow_tilde), 0, 0); | |||
CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f); | |||
class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------------ powtodb~ -------------------------- */ | |||
typedef struct powtodb_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_powtodb_tilde; | |||
t_class *powtodb_tilde_class; | |||
static void *powtodb_tilde_new(void) | |||
{ | |||
t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *powtodb_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)w[1], *out = (t_sample *)w[2]; | |||
t_int n = (t_int)w[3]; | |||
for (; n--; in++, out++) | |||
{ | |||
t_sample f = *in; | |||
if (f <= 0) *out = 0; | |||
else | |||
{ | |||
t_sample g = 100 + 10./LOGTEN * log(f); | |||
*out = (g < 0 ? 0 : g); | |||
} | |||
} | |||
return (w + 4); | |||
} | |||
static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
void powtodb_tilde_setup(void) | |||
{ | |||
powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0, | |||
sizeof(t_powtodb_tilde), 0, 0); | |||
CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f); | |||
class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ----------------------------- pow ----------------------------- */ | |||
static t_class *pow_tilde_class; | |||
typedef struct _pow_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_pow_tilde; | |||
static void *pow_tilde_new(t_floatarg f) | |||
{ | |||
t_pow_tilde *x = (t_pow_tilde *)pd_new(pow_tilde_class); | |||
signalinlet_new(&x->x_obj, f); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
t_int *pow_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) | |||
{ | |||
float f = *in1++; | |||
if (f > 0) | |||
*out = pow(f, *in2); | |||
else *out = 0; | |||
out++; | |||
in2++; | |||
} | |||
return (w+5); | |||
} | |||
static void pow_tilde_dsp(t_pow_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(pow_tilde_perform, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
} | |||
static void pow_tilde_setup(void) | |||
{ | |||
pow_tilde_class = class_new(gensym("pow~"), (t_newmethod)pow_tilde_new, 0, | |||
sizeof(t_pow_tilde), 0, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(pow_tilde_class, t_pow_tilde, x_f); | |||
class_addmethod(pow_tilde_class, (t_method)pow_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ----------------------------- exp ----------------------------- */ | |||
static t_class *exp_tilde_class; | |||
typedef struct _exp_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_exp_tilde; | |||
static void *exp_tilde_new( void) | |||
{ | |||
t_exp_tilde *x = (t_exp_tilde *)pd_new(exp_tilde_class); | |||
outlet_new(&x->x_obj, &s_signal); | |||
return (x); | |||
} | |||
t_int *exp_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
while (n--) | |||
*out++ = exp(*in1++); | |||
return (w+4); | |||
} | |||
static void exp_tilde_dsp(t_exp_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(exp_tilde_perform, 3, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void exp_tilde_setup(void) | |||
{ | |||
exp_tilde_class = class_new(gensym("exp~"), (t_newmethod)exp_tilde_new, 0, | |||
sizeof(t_exp_tilde), 0, 0); | |||
CLASS_MAINSIGNALIN(exp_tilde_class, t_exp_tilde, x_f); | |||
class_addmethod(exp_tilde_class, (t_method)exp_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ----------------------------- log ----------------------------- */ | |||
static t_class *log_tilde_class; | |||
typedef struct _log_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_log_tilde; | |||
static void *log_tilde_new(t_floatarg f) | |||
{ | |||
t_log_tilde *x = (t_log_tilde *)pd_new(log_tilde_class); | |||
pd_float( | |||
(t_pd *)inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal), f); | |||
outlet_new(&x->x_obj, &s_signal); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
t_int *log_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *in2 = (t_sample *)(w[2]); | |||
t_sample *out = (t_sample *)(w[3]); | |||
int n = (int)(w[4]); | |||
while (n--) | |||
{ | |||
float f = *in1++, g = *in2++; | |||
if (f <= 0) | |||
*out = -1000; /* rather than blow up, output a number << 0 */ | |||
else if (g <= 0) | |||
*out = log(f); | |||
else *out = log(f)/log(g); | |||
out++; | |||
} | |||
return (w+5); | |||
} | |||
static void log_tilde_dsp(t_log_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(log_tilde_perform, 4, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); | |||
} | |||
static void log_tilde_setup(void) | |||
{ | |||
log_tilde_class = class_new(gensym("log~"), (t_newmethod)log_tilde_new, 0, | |||
sizeof(t_log_tilde), 0, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(log_tilde_class, t_log_tilde, x_f); | |||
class_addmethod(log_tilde_class, (t_method)log_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ----------------------------- abs ----------------------------- */ | |||
static t_class *abs_tilde_class; | |||
typedef struct _abs_tilde | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
} t_abs_tilde; | |||
static void *abs_tilde_new( void) | |||
{ | |||
t_abs_tilde *x = (t_abs_tilde *)pd_new(abs_tilde_class); | |||
outlet_new(&x->x_obj, &s_signal); | |||
return (x); | |||
} | |||
t_int *abs_tilde_perform(t_int *w) | |||
{ | |||
t_sample *in1 = (t_sample *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
while (n--) | |||
{ | |||
float f = *in1++; | |||
*out++ = (f >= 0 ? f : -f); | |||
} | |||
return (w+4); | |||
} | |||
static void abs_tilde_dsp(t_abs_tilde *x, t_signal **sp) | |||
{ | |||
dsp_add(abs_tilde_perform, 3, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void abs_tilde_setup(void) | |||
{ | |||
abs_tilde_class = class_new(gensym("abs~"), (t_newmethod)abs_tilde_new, 0, | |||
sizeof(t_abs_tilde), 0, 0); | |||
CLASS_MAINSIGNALIN(abs_tilde_class, t_abs_tilde, x_f); | |||
class_addmethod(abs_tilde_class, (t_method)abs_tilde_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
} | |||
/* ------------------------ global setup routine ------------------------- */ | |||
void d_math_setup(void) | |||
{ | |||
t_symbol *s = gensym("acoustics~.pd"); | |||
clip_setup(); | |||
sigrsqrt_setup(); | |||
sigsqrt_setup(); | |||
sigwrap_setup(); | |||
mtof_tilde_setup(); | |||
ftom_tilde_setup(); | |||
dbtorms_tilde_setup(); | |||
rmstodb_tilde_setup(); | |||
dbtopow_tilde_setup(); | |||
powtodb_tilde_setup(); | |||
pow_tilde_setup(); | |||
exp_tilde_setup(); | |||
log_tilde_setup(); | |||
abs_tilde_setup(); | |||
class_sethelpsymbol(mtof_tilde_class, s); | |||
class_sethelpsymbol(ftom_tilde_class, s); | |||
class_sethelpsymbol(dbtorms_tilde_class, s); | |||
class_sethelpsymbol(rmstodb_tilde_class, s); | |||
class_sethelpsymbol(dbtopow_tilde_class, s); | |||
class_sethelpsymbol(powtodb_tilde_class, s); | |||
} | |||
@@ -0,0 +1,136 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* miscellaneous: print~; more to come. | |||
*/ | |||
#include "m_pd.h" | |||
#include <stdio.h> | |||
#include <string.h> | |||
/* ------------------------- print~ -------------------------- */ | |||
static t_class *print_class; | |||
typedef struct _print | |||
{ | |||
t_object x_obj; | |||
t_float x_f; | |||
t_symbol *x_sym; | |||
int x_count; | |||
} t_print; | |||
static t_int *print_perform(t_int *w) | |||
{ | |||
t_print *x = (t_print *)(w[1]); | |||
t_sample *in = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
if (x->x_count) | |||
{ | |||
int i=0; | |||
startpost("%s:", x->x_sym->s_name); | |||
for(i=0; i<n; i++) { | |||
if(i%8==0)endpost(); | |||
startpost("%.4g ", in[i]); | |||
} | |||
endpost(); | |||
x->x_count--; | |||
} | |||
return (w+4); | |||
} | |||
static void print_dsp(t_print *x, t_signal **sp) | |||
{ | |||
dsp_add(print_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); | |||
} | |||
static void print_float(t_print *x, t_float f) | |||
{ | |||
if (f < 0) f = 0; | |||
x->x_count = f; | |||
} | |||
static void print_bang(t_print *x) | |||
{ | |||
x->x_count = 1; | |||
} | |||
static void *print_new(t_symbol *s) | |||
{ | |||
t_print *x = (t_print *)pd_new(print_class); | |||
x->x_sym = (s->s_name[0]? s : gensym("print~")); | |||
x->x_count = 0; | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static void print_setup(void) | |||
{ | |||
print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0, | |||
sizeof(t_print), 0, A_DEFSYM, 0); | |||
CLASS_MAINSIGNALIN(print_class, t_print, x_f); | |||
class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), A_CANT, 0); | |||
class_addbang(print_class, print_bang); | |||
class_addfloat(print_class, print_float); | |||
} | |||
/* ------------------------ bang~ -------------------------- */ | |||
static t_class *bang_tilde_class; | |||
typedef struct _bang | |||
{ | |||
t_object x_obj; | |||
t_clock *x_clock; | |||
} t_bang; | |||
static t_int *bang_tilde_perform(t_int *w) | |||
{ | |||
t_bang *x = (t_bang *)(w[1]); | |||
clock_delay(x->x_clock, 0); | |||
return (w+2); | |||
} | |||
static void bang_tilde_dsp(t_bang *x, t_signal **sp) | |||
{ | |||
dsp_add(bang_tilde_perform, 1, x); | |||
} | |||
static void bang_tilde_tick(t_bang *x) | |||
{ | |||
outlet_bang(x->x_obj.ob_outlet); | |||
} | |||
static void bang_tilde_free(t_bang *x) | |||
{ | |||
clock_free(x->x_clock); | |||
} | |||
static void *bang_tilde_new(t_symbol *s) | |||
{ | |||
t_bang *x = (t_bang *)pd_new(bang_tilde_class); | |||
x->x_clock = clock_new(x, (t_method)bang_tilde_tick); | |||
outlet_new(&x->x_obj, &s_bang); | |||
return (x); | |||
} | |||
static void bang_tilde_setup(void) | |||
{ | |||
bang_tilde_class = class_new(gensym("bang~"), (t_newmethod)bang_tilde_new, | |||
(t_method)bang_tilde_free, sizeof(t_bang), 0, 0); | |||
class_addmethod(bang_tilde_class, (t_method)bang_tilde_dsp, | |||
gensym("dsp"), 0); | |||
} | |||
/* ------------------------ global setup routine ------------------------- */ | |||
void d_misc_setup(void) | |||
{ | |||
print_setup(); | |||
bang_tilde_setup(); | |||
} | |||
@@ -0,0 +1,521 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c. | |||
*/ | |||
#include "m_pd.h" | |||
#include "math.h" | |||
#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */ | |||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) \ | |||
|| defined(__OpenBSD__) | |||
#include <machine/endian.h> | |||
#endif | |||
#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__) || \ | |||
defined(ANDROID) | |||
#include <endian.h> | |||
#endif | |||
#ifdef __MINGW32__ | |||
#include <sys/param.h> | |||
#endif | |||
#ifdef _MSC_VER | |||
/* _MSVC lacks BYTE_ORDER and LITTLE_ENDIAN */ | |||
#define LITTLE_ENDIAN 0x0001 | |||
#define BYTE_ORDER LITTLE_ENDIAN | |||
#endif | |||
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) | |||
#error No byte order defined | |||
#endif | |||
#if BYTE_ORDER == LITTLE_ENDIAN | |||
# define HIOFFSET 1 | |||
# define LOWOFFSET 0 | |||
#else | |||
# define HIOFFSET 0 /* word offset to find MSB */ | |||
# define LOWOFFSET 1 /* word offset to find LSB */ | |||
#endif | |||
union tabfudge | |||
{ | |||
double tf_d; | |||
int32_t tf_i[2]; | |||
}; | |||
/* -------------------------- phasor~ ------------------------------ */ | |||
static t_class *phasor_class; | |||
#if 1 /* in the style of R. Hoeldrich (ICMC 1995 Banff) */ | |||
typedef struct _phasor | |||
{ | |||
t_object x_obj; | |||
double x_phase; | |||
float x_conv; | |||
float x_f; /* scalar frequency */ | |||
} t_phasor; | |||
static void *phasor_new(t_floatarg f) | |||
{ | |||
t_phasor *x = (t_phasor *)pd_new(phasor_class); | |||
x->x_f = f; | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1")); | |||
x->x_phase = 0; | |||
x->x_conv = 0; | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
return (x); | |||
} | |||
static t_int *phasor_perform(t_int *w) | |||
{ | |||
t_phasor *x = (t_phasor *)(w[1]); | |||
t_float *in = (t_float *)(w[2]); | |||
t_float *out = (t_float *)(w[3]); | |||
int n = (int)(w[4]); | |||
double dphase = x->x_phase + (double)UNITBIT32; | |||
union tabfudge tf; | |||
int normhipart; | |||
float conv = x->x_conv; | |||
tf.tf_d = UNITBIT32; | |||
normhipart = tf.tf_i[HIOFFSET]; | |||
tf.tf_d = dphase; | |||
while (n--) | |||
{ | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
dphase += *in++ * conv; | |||
*out++ = tf.tf_d - UNITBIT32; | |||
tf.tf_d = dphase; | |||
} | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
x->x_phase = tf.tf_d - UNITBIT32; | |||
return (w+5); | |||
} | |||
static void phasor_dsp(t_phasor *x, t_signal **sp) | |||
{ | |||
x->x_conv = 1./sp[0]->s_sr; | |||
dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void phasor_ft1(t_phasor *x, t_float f) | |||
{ | |||
x->x_phase = f; | |||
} | |||
static void phasor_setup(void) | |||
{ | |||
phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0, | |||
sizeof(t_phasor), 0, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f); | |||
class_addmethod(phasor_class, (t_method)phasor_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addmethod(phasor_class, (t_method)phasor_ft1, | |||
gensym("ft1"), A_FLOAT, 0); | |||
} | |||
#endif /* Hoeldrich version */ | |||
/* ------------------------ cos~ ----------------------------- */ | |||
float *cos_table; | |||
static t_class *cos_class; | |||
typedef struct _cos | |||
{ | |||
t_object x_obj; | |||
float x_f; | |||
} t_cos; | |||
static void *cos_new(void) | |||
{ | |||
t_cos *x = (t_cos *)pd_new(cos_class); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static t_int *cos_perform(t_int *w) | |||
{ | |||
t_float *in = (t_float *)(w[1]); | |||
t_float *out = (t_float *)(w[2]); | |||
int n = (int)(w[3]); | |||
float *tab = cos_table, *addr, f1, f2, frac; | |||
double dphase; | |||
int normhipart; | |||
union tabfudge tf; | |||
tf.tf_d = UNITBIT32; | |||
normhipart = tf.tf_i[HIOFFSET]; | |||
#if 0 /* this is the readable version of the code. */ | |||
while (n--) | |||
{ | |||
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32; | |||
tf.tf_d = dphase; | |||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1)); | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
frac = tf.tf_d - UNITBIT32; | |||
f1 = addr[0]; | |||
f2 = addr[1]; | |||
*out++ = f1 + frac * (f2 - f1); | |||
} | |||
#endif | |||
#if 1 /* this is the same, unwrapped by hand. */ | |||
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32; | |||
tf.tf_d = dphase; | |||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1)); | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
while (--n) | |||
{ | |||
dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32; | |||
frac = tf.tf_d - UNITBIT32; | |||
tf.tf_d = dphase; | |||
f1 = addr[0]; | |||
f2 = addr[1]; | |||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1)); | |||
*out++ = f1 + frac * (f2 - f1); | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
} | |||
frac = tf.tf_d - UNITBIT32; | |||
f1 = addr[0]; | |||
f2 = addr[1]; | |||
*out++ = f1 + frac * (f2 - f1); | |||
#endif | |||
return (w+4); | |||
} | |||
static void cos_dsp(t_cos *x, t_signal **sp) | |||
{ | |||
dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void cos_maketable(void) | |||
{ | |||
int i; | |||
float *fp, phase, phsinc = (2. * 3.14159) / COSTABSIZE; | |||
union tabfudge tf; | |||
if (cos_table) return; | |||
cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1)); | |||
for (i = COSTABSIZE + 1, fp = cos_table, phase = 0; i--; | |||
fp++, phase += phsinc) | |||
*fp = cos(phase); | |||
/* here we check at startup whether the byte alignment | |||
is as we declared it. If not, the code has to be | |||
recompiled the other way. */ | |||
tf.tf_d = UNITBIT32 + 0.5; | |||
if ((unsigned)tf.tf_i[LOWOFFSET] != 0x80000000) | |||
bug("cos~: unexpected machine alignment"); | |||
} | |||
static void cos_setup(void) | |||
{ | |||
cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0, | |||
sizeof(t_cos), 0, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(cos_class, t_cos, x_f); | |||
class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), A_CANT, 0); | |||
cos_maketable(); | |||
} | |||
/* ------------------------ osc~ ----------------------------- */ | |||
static t_class *osc_class, *scalarosc_class; | |||
typedef struct _osc | |||
{ | |||
t_object x_obj; | |||
double x_phase; | |||
float x_conv; | |||
float x_f; /* frequency if scalar */ | |||
} t_osc; | |||
static void *osc_new(t_floatarg f) | |||
{ | |||
t_osc *x = (t_osc *)pd_new(osc_class); | |||
x->x_f = f; | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1")); | |||
x->x_phase = 0; | |||
x->x_conv = 0; | |||
return (x); | |||
} | |||
static t_int *osc_perform(t_int *w) | |||
{ | |||
t_osc *x = (t_osc *)(w[1]); | |||
t_float *in = (t_float *)(w[2]); | |||
t_float *out = (t_float *)(w[3]); | |||
int n = (int)(w[4]); | |||
float *tab = cos_table, *addr, f1, f2, frac; | |||
double dphase = x->x_phase + UNITBIT32; | |||
int normhipart; | |||
union tabfudge tf; | |||
float conv = x->x_conv; | |||
tf.tf_d = UNITBIT32; | |||
normhipart = tf.tf_i[HIOFFSET]; | |||
#if 0 | |||
while (n--) | |||
{ | |||
tf.tf_d = dphase; | |||
dphase += *in++ * conv; | |||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1)); | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
frac = tf.tf_d - UNITBIT32; | |||
f1 = addr[0]; | |||
f2 = addr[1]; | |||
*out++ = f1 + frac * (f2 - f1); | |||
} | |||
#endif | |||
#if 1 | |||
tf.tf_d = dphase; | |||
dphase += *in++ * conv; | |||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1)); | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
frac = tf.tf_d - UNITBIT32; | |||
while (--n) | |||
{ | |||
tf.tf_d = dphase; | |||
f1 = addr[0]; | |||
dphase += *in++ * conv; | |||
f2 = addr[1]; | |||
addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1)); | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
*out++ = f1 + frac * (f2 - f1); | |||
frac = tf.tf_d - UNITBIT32; | |||
} | |||
f1 = addr[0]; | |||
f2 = addr[1]; | |||
*out++ = f1 + frac * (f2 - f1); | |||
#endif | |||
tf.tf_d = UNITBIT32 * COSTABSIZE; | |||
normhipart = tf.tf_i[HIOFFSET]; | |||
tf.tf_d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32); | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
x->x_phase = tf.tf_d - UNITBIT32 * COSTABSIZE; | |||
return (w+5); | |||
} | |||
static void osc_dsp(t_osc *x, t_signal **sp) | |||
{ | |||
x->x_conv = COSTABSIZE/sp[0]->s_sr; | |||
dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); | |||
} | |||
static void osc_ft1(t_osc *x, t_float f) | |||
{ | |||
x->x_phase = COSTABSIZE * f; | |||
} | |||
static void osc_setup(void) | |||
{ | |||
osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0, | |||
sizeof(t_osc), 0, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(osc_class, t_osc, x_f); | |||
class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), A_CANT, 0); | |||
class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0); | |||
cos_maketable(); | |||
} | |||
/* ---- vcf~ - resonant filter with audio-rate center frequency input ----- */ | |||
typedef struct vcfctl | |||
{ | |||
float c_re; | |||
float c_im; | |||
float c_q; | |||
float c_isr; | |||
} t_vcfctl; | |||
typedef struct sigvcf | |||
{ | |||
t_object x_obj; | |||
t_vcfctl x_cspace; | |||
t_vcfctl *x_ctl; | |||
float x_f; | |||
} t_sigvcf; | |||
t_class *sigvcf_class; | |||
static void *sigvcf_new(t_floatarg q) | |||
{ | |||
t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
x->x_ctl = &x->x_cspace; | |||
x->x_cspace.c_re = 0; | |||
x->x_cspace.c_im = 0; | |||
x->x_cspace.c_q = q; | |||
x->x_cspace.c_isr = 0; | |||
x->x_f = 0; | |||
return (x); | |||
} | |||
static void sigvcf_ft1(t_sigvcf *x, t_floatarg f) | |||
{ | |||
x->x_ctl->c_q = (f > 0 ? f : 0.f); | |||
} | |||
static t_int *sigvcf_perform(t_int *w) | |||
{ | |||
float *in1 = (float *)(w[1]); | |||
float *in2 = (float *)(w[2]); | |||
float *out1 = (float *)(w[3]); | |||
float *out2 = (float *)(w[4]); | |||
t_vcfctl *c = (t_vcfctl *)(w[5]); | |||
int n = (int)w[6]; | |||
int i; | |||
float re = c->c_re, re2; | |||
float im = c->c_im; | |||
float q = c->c_q; | |||
float qinv = (q > 0? 1.0f/q : 0); | |||
float ampcorrect = 2.0f - 2.0f / (q + 2.0f); | |||
float isr = c->c_isr; | |||
float coefr, coefi; | |||
float *tab = cos_table, *addr, f1, f2, frac; | |||
double dphase; | |||
int normhipart, tabindex; | |||
union tabfudge tf; | |||
tf.tf_d = UNITBIT32; | |||
normhipart = tf.tf_i[HIOFFSET]; | |||
for (i = 0; i < n; i++) | |||
{ | |||
float cf, cfindx, r, oneminusr; | |||
cf = *in2++ * isr; | |||
if (cf < 0) cf = 0; | |||
cfindx = cf * (float)(COSTABSIZE/6.28318f); | |||
r = (qinv > 0 ? 1 - cf * qinv : 0); | |||
if (r < 0) r = 0; | |||
oneminusr = 1.0f - r; | |||
dphase = ((double)(cfindx)) + UNITBIT32; | |||
tf.tf_d = dphase; | |||
tabindex = tf.tf_i[HIOFFSET] & (COSTABSIZE-1); | |||
addr = tab + tabindex; | |||
tf.tf_i[HIOFFSET] = normhipart; | |||
frac = tf.tf_d - UNITBIT32; | |||
f1 = addr[0]; | |||
f2 = addr[1]; | |||
coefr = r * (f1 + frac * (f2 - f1)); | |||
addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1)); | |||
f1 = addr[0]; | |||
f2 = addr[1]; | |||
coefi = r * (f1 + frac * (f2 - f1)); | |||
f1 = *in1++; | |||
re2 = re; | |||
*out1++ = re = ampcorrect * oneminusr * f1 | |||
+ coefr * re2 - coefi * im; | |||
*out2++ = im = coefi * re2 + coefr * im; | |||
} | |||
if (PD_BIGORSMALL(re)) | |||
re = 0; | |||
if (PD_BIGORSMALL(im)) | |||
im = 0; | |||
c->c_re = re; | |||
c->c_im = im; | |||
return (w+7); | |||
} | |||
static void sigvcf_dsp(t_sigvcf *x, t_signal **sp) | |||
{ | |||
x->x_ctl->c_isr = 6.28318f/sp[0]->s_sr; | |||
dsp_add(sigvcf_perform, 6, | |||
sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, | |||
x->x_ctl, sp[0]->s_n); | |||
} | |||
void sigvcf_setup(void) | |||
{ | |||
sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0, | |||
sizeof(t_sigvcf), 0, A_DEFFLOAT, 0); | |||
CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f); | |||
class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addmethod(sigvcf_class, (t_method)sigvcf_ft1, | |||
gensym("ft1"), A_FLOAT, 0); | |||
} | |||
/* -------------------------- noise~ ------------------------------ */ | |||
static t_class *noise_class; | |||
typedef struct _noise | |||
{ | |||
t_object x_obj; | |||
int x_val; | |||
} t_noise; | |||
static void *noise_new(void) | |||
{ | |||
t_noise *x = (t_noise *)pd_new(noise_class); | |||
/* seed each instance differently. Once in a blue moon two threads | |||
could grab the same seed value. We can live with that. */ | |||
static int init = 307; | |||
x->x_val = (init *= 1319); | |||
outlet_new(&x->x_obj, gensym("signal")); | |||
return (x); | |||
} | |||
static t_int *noise_perform(t_int *w) | |||
{ | |||
t_sample *out = (t_sample *)(w[1]); | |||
int *vp = (int *)(w[2]); | |||
int n = (int)(w[3]); | |||
int val = *vp; | |||
while (n--) | |||
{ | |||
*out++ = ((float)((val & 0x7fffffff) - 0x40000000)) * | |||
(float)(1.0 / 0x40000000); | |||
val = val * 435898247 + 382842987; | |||
} | |||
*vp = val; | |||
return (w+4); | |||
} | |||
static void noise_dsp(t_noise *x, t_signal **sp) | |||
{ | |||
dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n); | |||
} | |||
static void noise_float(t_noise *x, t_float f) | |||
{ | |||
/* set the seed */ | |||
x->x_val = (int)f; | |||
} | |||
static void noise_setup(void) | |||
{ | |||
noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0, | |||
sizeof(t_noise), 0, A_DEFFLOAT, 0); | |||
class_addmethod(noise_class, (t_method)noise_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_addmethod(noise_class, (t_method)noise_float, | |||
gensym("seed"), A_FLOAT, 0); | |||
} | |||
/* ----------------------- global setup routine ---------------- */ | |||
void d_osc_setup(void) | |||
{ | |||
phasor_setup(); | |||
cos_setup(); | |||
osc_setup(); | |||
sigvcf_setup(); | |||
noise_setup(); | |||
} |
@@ -0,0 +1,216 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#include "m_pd.h" | |||
/* --------------------- up/down-sampling --------------------- */ | |||
t_int *downsampling_perform_0(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); /* original signal */ | |||
t_sample *out = (t_sample *)(w[2]); /* downsampled signal */ | |||
int down = (int)(w[3]); /* downsampling factor */ | |||
int parent = (int)(w[4]); /* original vectorsize */ | |||
int n=parent/down; | |||
while(n--){ | |||
*out++=*in; | |||
in+=down; | |||
} | |||
return (w+5); | |||
} | |||
t_int *upsampling_perform_0(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); /* original signal */ | |||
t_sample *out = (t_sample *)(w[2]); /* upsampled signal */ | |||
int up = (int)(w[3]); /* upsampling factor */ | |||
int parent = (int)(w[4]); /* original vectorsize */ | |||
int n=parent*up; | |||
t_sample *dummy = out; | |||
while(n--)*out++=0; | |||
n = parent; | |||
out = dummy; | |||
while(n--){ | |||
*out=*in++; | |||
out+=up; | |||
} | |||
return (w+5); | |||
} | |||
t_int *upsampling_perform_hold(t_int *w) | |||
{ | |||
t_sample *in = (t_sample *)(w[1]); /* original signal */ | |||
t_sample *out = (t_sample *)(w[2]); /* upsampled signal */ | |||
int up = (int)(w[3]); /* upsampling factor */ | |||
int parent = (int)(w[4]); /* original vectorsize */ | |||
int i=up; | |||
int n=parent; | |||
t_sample *dum_out = out; | |||
t_sample *dum_in = in; | |||
while (i--) { | |||
n = parent; | |||
out = dum_out+i; | |||
in = dum_in; | |||
while(n--){ | |||
*out=*in++; | |||
out+=up; | |||
} | |||
} | |||
return (w+5); | |||
} | |||
t_int *upsampling_perform_linear(t_int *w) | |||
{ | |||
t_resample *x= (t_resample *)(w[1]); | |||
t_sample *in = (t_sample *)(w[2]); /* original signal */ | |||
t_sample *out = (t_sample *)(w[3]); /* upsampled signal */ | |||
int up = (int)(w[4]); /* upsampling factor */ | |||
int parent = (int)(w[5]); /* original vectorsize */ | |||
int length = parent*up; | |||
int n; | |||
t_sample *fp; | |||
t_sample a=*x->buffer, b=*in; | |||
for (n=0; n<length; n++) { | |||
t_sample findex = (t_sample)(n+1)/up; | |||
int index = findex; | |||
t_sample frac=findex - index; | |||
if (frac==0.)frac=1.; | |||
*out++ = frac * b + (1.-frac) * a; | |||
fp = in+index; | |||
b=*fp; | |||
a=(index)?*(fp-1):a; | |||
} | |||
*x->buffer = a; | |||
return (w+6); | |||
} | |||
/* ----------------------- public -------------------------------- */ | |||
/* utils */ | |||
void resample_init(t_resample *x) | |||
{ | |||
x->method=0; | |||
x->downsample=x->upsample=1; | |||
x->s_n = x->coefsize = x->bufsize = 0; | |||
x->s_vec = x->coeffs = x->buffer = 0; | |||
} | |||
void resample_free(t_resample *x) | |||
{ | |||
if (x->s_n) t_freebytes(x->s_vec, x->s_n*sizeof(*x->s_vec)); | |||
if (x->coefsize) t_freebytes(x->coeffs, x->coefsize*sizeof(*x->coeffs)); | |||
if (x->bufsize) t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer)); | |||
x->s_n = x->coefsize = x->bufsize = 0; | |||
x->s_vec = x->coeffs = x->buffer = 0; | |||
} | |||
/* dsp-adding */ | |||
void resample_dsp(t_resample *x, | |||
t_sample* in, int insize, | |||
t_sample* out, int outsize, | |||
int method) | |||
{ | |||
if (insize == outsize){ | |||
bug("nothing to be done"); | |||
return; | |||
} | |||
if (insize > outsize) { /* downsampling */ | |||
if (insize % outsize) { | |||
error("bad downsampling factor"); | |||
return; | |||
} | |||
switch (method) { | |||
default: | |||
dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize); | |||
} | |||
} else { /* upsampling */ | |||
if (outsize % insize) { | |||
error("bad upsampling factor"); | |||
return; | |||
} | |||
switch (method) { | |||
case 1: | |||
dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize); | |||
break; | |||
case 2: | |||
if (x->bufsize != 1) { | |||
t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer)); | |||
x->bufsize = 1; | |||
x->buffer = t_getbytes(x->bufsize*sizeof(*x->buffer)); | |||
} | |||
dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize); | |||
break; | |||
default: | |||
dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize); | |||
} | |||
} | |||
} | |||
void resamplefrom_dsp(t_resample *x, | |||
t_sample *in, | |||
int insize, int outsize, int method) | |||
{ | |||
if (insize==outsize) { | |||
t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec)); | |||
x->s_n = 0; | |||
x->s_vec = in; | |||
return; | |||
} | |||
if (x->s_n != outsize) { | |||
t_sample *buf=x->s_vec; | |||
t_freebytes(buf, x->s_n * sizeof(*buf)); | |||
buf = (t_sample *)t_getbytes(outsize * sizeof(*buf)); | |||
x->s_vec = buf; | |||
x->s_n = outsize; | |||
} | |||
resample_dsp(x, in, insize, x->s_vec, x->s_n, method); | |||
return; | |||
} | |||
void resampleto_dsp(t_resample *x, | |||
t_sample *out, | |||
int insize, int outsize, int method) | |||
{ | |||
if (insize==outsize) { | |||
if (x->s_n)t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec)); | |||
x->s_n = 0; | |||
x->s_vec = out; | |||
return; | |||
} | |||
if (x->s_n != insize) { | |||
t_sample *buf=x->s_vec; | |||
t_freebytes(buf, x->s_n * sizeof(*buf)); | |||
buf = (t_sample *)t_getbytes(insize * sizeof(*buf)); | |||
x->s_vec = buf; | |||
x->s_n = insize; | |||
} | |||
resample_dsp(x, x->s_vec, x->s_n, out, outsize, method); | |||
return; | |||
} |
@@ -0,0 +1,786 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _MSC_VER | |||
#define snprintf _snprintf | |||
#endif | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
/* #define GGEE_HSLIDER_COMPATIBLE */ | |||
/*------------------ global variables -------------------------*/ | |||
int iemgui_color_hex[]= | |||
{ | |||
16579836, 10526880, 4210752, 16572640, 16572608, | |||
16579784, 14220504, 14220540, 14476540, 16308476, | |||
14737632, 8158332, 2105376, 16525352, 16559172, | |||
15263784, 1370132, 2684148, 3952892, 16003312, | |||
12369084, 6316128, 0, 9177096, 5779456, | |||
7874580, 2641940, 17488, 5256, 5767248 | |||
}; | |||
int iemgui_vu_db2i[]= | |||
{ | |||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, | |||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | |||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | |||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | |||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | |||
9, 9, 9, 9, 9,10,10,10,10,10, | |||
11,11,11,11,11,12,12,12,12,12, | |||
13,13,13,13,14,14,14,14,15,15, | |||
15,15,16,16,16,16,17,17,17,18, | |||
18,18,19,19,19,20,20,20,21,21, | |||
22,22,23,23,24,24,25,26,27,28, | |||
29,30,31,32,33,33,34,34,35,35, | |||
36,36,37,37,37,38,38,38,39,39, | |||
39,39,39,39,40,40 | |||
}; | |||
int iemgui_vu_col[]= | |||
{ | |||
0,17,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, | |||
15,15,15,15,15,15,15,15,15,15,14,14,13,13,13,13,13,13,13,13,13,13,13,19,19,19 | |||
}; | |||
char *iemgui_vu_scale_str[]= | |||
{ | |||
"", | |||
"<-99", | |||
"", | |||
"", | |||
"", | |||
"-50", | |||
"", | |||
"", | |||
"", | |||
"-30", | |||
"", | |||
"", | |||
"", | |||
"-20", | |||
"", | |||
"", | |||
"", | |||
"-12", | |||
"", | |||
"", | |||
"", | |||
"-6", | |||
"", | |||
"", | |||
"", | |||
"-2", | |||
"", | |||
"", | |||
"", | |||
"-0dB", | |||
"", | |||
"", | |||
"", | |||
"+2", | |||
"", | |||
"", | |||
"", | |||
"+6", | |||
"", | |||
"", | |||
"", | |||
">+12", | |||
"", | |||
"", | |||
"", | |||
"", | |||
"", | |||
}; | |||
/*------------------ global functions -------------------------*/ | |||
int iemgui_clip_size(int size) | |||
{ | |||
if(size < IEM_GUI_MINSIZE) | |||
size = IEM_GUI_MINSIZE; | |||
return(size); | |||
} | |||
int iemgui_clip_font(int size) | |||
{ | |||
if(size < IEM_FONT_MINSIZE) | |||
size = IEM_FONT_MINSIZE; | |||
return(size); | |||
} | |||
int iemgui_modulo_color(int col) | |||
{ | |||
while(col >= IEM_GUI_MAX_COLOR) | |||
col -= IEM_GUI_MAX_COLOR; | |||
while(col < 0) | |||
col += IEM_GUI_MAX_COLOR; | |||
return(col); | |||
} | |||
t_symbol *iemgui_dollar2raute(t_symbol *s) | |||
{ | |||
char buf[MAXPDSTRING+1], *s1, *s2; | |||
if (strlen(s->s_name) >= MAXPDSTRING) | |||
return (s); | |||
for (s1 = s->s_name, s2 = buf; ; s1++, s2++) | |||
{ | |||
if (*s1 == '$') | |||
*s2 = '#'; | |||
else if (!(*s2 = *s1)) | |||
break; | |||
} | |||
return(gensym(buf)); | |||
} | |||
t_symbol *iemgui_raute2dollar(t_symbol *s) | |||
{ | |||
char buf[MAXPDSTRING+1], *s1, *s2; | |||
if (strlen(s->s_name) >= MAXPDSTRING) | |||
return (s); | |||
for (s1 = s->s_name, s2 = buf; ; s1++, s2++) | |||
{ | |||
if (*s1 == '#') | |||
*s2 = '$'; | |||
else if (!(*s2 = *s1)) | |||
break; | |||
} | |||
return(gensym(buf)); | |||
} | |||
void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui) | |||
{ | |||
iemgui->x_fsf.x_put_in2out = 1; | |||
if(iemgui->x_fsf.x_snd_able && iemgui->x_fsf.x_rcv_able) | |||
{ | |||
if(!strcmp(iemgui->x_snd->s_name, iemgui->x_rcv->s_name)) | |||
iemgui->x_fsf.x_put_in2out = 0; | |||
} | |||
} | |||
t_symbol *iemgui_new_dogetname(t_iemgui *iemgui, int indx, t_atom *argv) | |||
{ | |||
if (IS_A_SYMBOL(argv, indx)) | |||
return (atom_getsymbolarg(indx, 100000, argv)); | |||
else if (IS_A_FLOAT(argv, indx)) | |||
{ | |||
char str[80]; | |||
sprintf(str, "%d", (int)atom_getfloatarg(indx, 100000, argv)); | |||
return (gensym(str)); | |||
} | |||
else return (gensym("empty")); | |||
} | |||
void iemgui_new_getnames(t_iemgui *iemgui, int indx, t_atom *argv) | |||
{ | |||
if (argv) | |||
{ | |||
iemgui->x_snd = iemgui_new_dogetname(iemgui, indx, argv); | |||
iemgui->x_rcv = iemgui_new_dogetname(iemgui, indx+1, argv); | |||
iemgui->x_lab = iemgui_new_dogetname(iemgui, indx+2, argv); | |||
} | |||
else iemgui->x_snd = iemgui->x_rcv = iemgui->x_lab = gensym("empty"); | |||
iemgui->x_snd_unexpanded = iemgui->x_rcv_unexpanded = | |||
iemgui->x_lab_unexpanded = 0; | |||
iemgui->x_binbufindex = indx; | |||
iemgui->x_labelbindex = indx + 3; | |||
} | |||
/* convert symbols in "$" form to the expanded symbols */ | |||
void iemgui_all_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym) | |||
{ | |||
/* save unexpanded ones for later */ | |||
iemgui->x_snd_unexpanded = srlsym[0]; | |||
iemgui->x_rcv_unexpanded = srlsym[1]; | |||
iemgui->x_lab_unexpanded = srlsym[2]; | |||
srlsym[0] = canvas_realizedollar(iemgui->x_glist, srlsym[0]); | |||
srlsym[1] = canvas_realizedollar(iemgui->x_glist, srlsym[1]); | |||
srlsym[2] = canvas_realizedollar(iemgui->x_glist, srlsym[2]); | |||
} | |||
/* initialize a single symbol in unexpanded form. We reach into the | |||
binbuf to grab them; if there's nothing there, set it to the | |||
fallback; if still nothing, set to "empty". */ | |||
static void iemgui_init_sym2dollararg(t_iemgui *iemgui, t_symbol **symp, | |||
int indx, t_symbol *fallback) | |||
{ | |||
if (!*symp) | |||
{ | |||
t_binbuf *b = iemgui->x_obj.ob_binbuf; | |||
if (binbuf_getnatom(b) > indx) | |||
{ | |||
char buf[80]; | |||
atom_string(binbuf_getvec(b) + indx, buf, 80); | |||
*symp = gensym(buf); | |||
} | |||
else if (fallback) | |||
*symp = fallback; | |||
else *symp = gensym("empty"); | |||
} | |||
} | |||
/* get the unexpanded versions of the symbols; initialize them if | |||
necessary. */ | |||
void iemgui_all_sym2dollararg(t_iemgui *iemgui, t_symbol **srlsym) | |||
{ | |||
iemgui_init_sym2dollararg(iemgui, &iemgui->x_snd_unexpanded, | |||
iemgui->x_binbufindex+1, iemgui->x_snd); | |||
iemgui_init_sym2dollararg(iemgui, &iemgui->x_rcv_unexpanded, | |||
iemgui->x_binbufindex+2, iemgui->x_rcv); | |||
iemgui_init_sym2dollararg(iemgui, &iemgui->x_lab_unexpanded, | |||
iemgui->x_labelbindex, iemgui->x_lab); | |||
srlsym[0] = iemgui->x_snd_unexpanded; | |||
srlsym[1] = iemgui->x_rcv_unexpanded; | |||
srlsym[2] = iemgui->x_lab_unexpanded; | |||
} | |||
static t_symbol* color2symbol(int col) { | |||
const int compat = (pd_compatibilitylevel < 48)?1: | |||
/* FIXXME: for Pd>=0.48, the default compatibility mode should be OFF */ | |||
1; | |||
char colname[MAXPDSTRING]; | |||
colname[0] = colname[MAXPDSTRING-1] = 0; | |||
if (compat) | |||
{ | |||
/* compatibility with Pd<=0.47: saves colors as numbers with limited resolution */ | |||
int col2 = -1 - (((0xfc0000 & col) >> 6)|((0xfc00 & col) >> 4)|((0xfc & col) >> 2)); | |||
snprintf(colname, MAXPDSTRING-1, "%d", col2); | |||
} else { | |||
snprintf(colname, MAXPDSTRING-1, "#%06x", col); | |||
} | |||
return gensym(colname); | |||
} | |||
void iemgui_all_col2save(t_iemgui *iemgui, t_symbol**bflcol) | |||
{ | |||
bflcol[0] = color2symbol(iemgui->x_bcol); | |||
bflcol[1] = color2symbol(iemgui->x_fcol); | |||
bflcol[2] = color2symbol(iemgui->x_lcol); | |||
} | |||
static int iemgui_getcolorarg(int index, int argc, t_atom*argv) | |||
{ | |||
if(index < 0 || index >= argc) | |||
return 0; | |||
if(IS_A_FLOAT(argv,index)) | |||
return atom_getfloatarg(index, argc, argv); | |||
if(IS_A_SYMBOL(argv,index)) | |||
{ | |||
t_symbol*s=atom_getsymbolarg(index, argc, argv); | |||
if ('#' == s->s_name[0]) | |||
return (int)strtol(s->s_name+1, 0, 16); | |||
} | |||
return 0; | |||
} | |||
static int colfromatomload(t_atom*colatom) | |||
{ | |||
int color; | |||
/* old-fashioned color argument, either a number or symbol | |||
evaluating to an integer */ | |||
if (colatom->a_type == A_FLOAT) | |||
color = atom_getfloat(colatom); | |||
else if (colatom->a_type == A_SYMBOL && | |||
(isdigit(colatom->a_w.w_symbol->s_name[0]) || | |||
colatom->a_w.w_symbol->s_name[0] == '-')) | |||
color = atoi(colatom->a_w.w_symbol->s_name); | |||
/* symbolic color */ | |||
else return (iemgui_getcolorarg(0, 1, colatom)); | |||
if (color < 0) | |||
{ | |||
color = -1 - color; | |||
color = ((color & 0x3f000) << 6)|((color & 0xfc0) << 4)| | |||
((color & 0x3f) << 2); | |||
} | |||
else | |||
{ | |||
color = iemgui_modulo_color(color); | |||
color = iemgui_color_hex[color]; | |||
} | |||
return (color); | |||
} | |||
void iemgui_all_loadcolors(t_iemgui *iemgui, t_atom*bcol, t_atom*fcol, t_atom*lcol) | |||
{ | |||
if(bcol)iemgui->x_bcol = colfromatomload(bcol); | |||
if(fcol)iemgui->x_fcol = colfromatomload(fcol); | |||
if(lcol)iemgui->x_lcol = colfromatomload(lcol); | |||
} | |||
int iemgui_compatible_colorarg(int index, int argc, t_atom* argv) | |||
{ | |||
if (index < 0 || index >= argc) | |||
return 0; | |||
if(IS_A_FLOAT(argv,index)) | |||
{ | |||
int col=atom_getfloatarg(index, argc, argv); | |||
if(col >= 0) | |||
{ | |||
int idx = iemgui_modulo_color(col); | |||
return(iemgui_color_hex[(idx)]); | |||
} | |||
else | |||
return((-1 -col)&0xffffff); | |||
} | |||
return iemgui_getcolorarg(index, argc, argv); | |||
} | |||
void iemgui_all_dollar2raute(t_symbol **srlsym) | |||
{ | |||
srlsym[0] = iemgui_dollar2raute(srlsym[0]); | |||
srlsym[1] = iemgui_dollar2raute(srlsym[1]); | |||
srlsym[2] = iemgui_dollar2raute(srlsym[2]); | |||
} | |||
void iemgui_all_raute2dollar(t_symbol **srlsym) | |||
{ | |||
srlsym[0] = iemgui_raute2dollar(srlsym[0]); | |||
srlsym[1] = iemgui_raute2dollar(srlsym[1]); | |||
srlsym[2] = iemgui_raute2dollar(srlsym[2]); | |||
} | |||
void iemgui_send(void *x, t_iemgui *iemgui, t_symbol *s) | |||
{ | |||
t_symbol *snd; | |||
int pargc, tail_len, nth_arg, sndable=1, oldsndrcvable=0; | |||
t_atom *pargv; | |||
if(iemgui->x_fsf.x_rcv_able) | |||
oldsndrcvable += IEM_GUI_OLD_RCV_FLAG; | |||
if(iemgui->x_fsf.x_snd_able) | |||
oldsndrcvable += IEM_GUI_OLD_SND_FLAG; | |||
if(!strcmp(s->s_name, "empty")) sndable = 0; | |||
snd = iemgui_raute2dollar(s); | |||
iemgui->x_snd_unexpanded = snd; | |||
iemgui->x_snd = snd = canvas_realizedollar(iemgui->x_glist, snd); | |||
iemgui->x_fsf.x_snd_able = sndable; | |||
iemgui_verify_snd_ne_rcv(iemgui); | |||
(*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_IO + oldsndrcvable); | |||
} | |||
void iemgui_receive(void *x, t_iemgui *iemgui, t_symbol *s) | |||
{ | |||
t_symbol *rcv; | |||
int pargc, tail_len, nth_arg, rcvable=1, oldsndrcvable=0; | |||
t_atom *pargv; | |||
if(iemgui->x_fsf.x_rcv_able) | |||
oldsndrcvable += IEM_GUI_OLD_RCV_FLAG; | |||
if(iemgui->x_fsf.x_snd_able) | |||
oldsndrcvable += IEM_GUI_OLD_SND_FLAG; | |||
if(!strcmp(s->s_name, "empty")) rcvable = 0; | |||
rcv = iemgui_raute2dollar(s); | |||
iemgui->x_rcv_unexpanded = rcv; | |||
rcv = canvas_realizedollar(iemgui->x_glist, rcv); | |||
if(rcvable) | |||
{ | |||
if(strcmp(rcv->s_name, iemgui->x_rcv->s_name)) | |||
{ | |||
if(iemgui->x_fsf.x_rcv_able) | |||
pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv); | |||
iemgui->x_rcv = rcv; | |||
pd_bind(&iemgui->x_obj.ob_pd, iemgui->x_rcv); | |||
} | |||
} | |||
else if(!rcvable && iemgui->x_fsf.x_rcv_able) | |||
{ | |||
pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv); | |||
iemgui->x_rcv = rcv; | |||
} | |||
iemgui->x_fsf.x_rcv_able = rcvable; | |||
iemgui_verify_snd_ne_rcv(iemgui); | |||
(*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_IO + oldsndrcvable); | |||
} | |||
void iemgui_label(void *x, t_iemgui *iemgui, t_symbol *s) | |||
{ | |||
t_symbol *old; | |||
int pargc, tail_len, nth_arg; | |||
t_atom *pargv; | |||
/* tb: fix for empty label { */ | |||
if (s == gensym("")) | |||
s = gensym("empty"); | |||
/* tb } */ | |||
old = iemgui->x_lab; | |||
iemgui->x_lab_unexpanded = iemgui_raute2dollar(s); | |||
iemgui->x_lab = canvas_realizedollar(iemgui->x_glist, iemgui->x_lab_unexpanded); | |||
if(glist_isvisible(iemgui->x_glist) && iemgui->x_lab != old) | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -text {%s} \n", | |||
glist_getcanvas(iemgui->x_glist), x, | |||
strcmp(s->s_name, "empty")?iemgui->x_lab->s_name:""); | |||
} | |||
void iemgui_label_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
int zoom = glist_getzoom(iemgui->x_glist); | |||
iemgui->x_ldx = (int)atom_getfloatarg(0, ac, av); | |||
iemgui->x_ldy = (int)atom_getfloatarg(1, ac, av); | |||
if(glist_isvisible(iemgui->x_glist)) | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
glist_getcanvas(iemgui->x_glist), x, | |||
text_xpix((t_object *)x, iemgui->x_glist) + iemgui->x_ldx*zoom, | |||
text_ypix((t_object *)x, iemgui->x_glist) + iemgui->x_ldy*zoom); | |||
} | |||
void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
int zoom = glist_getzoom(iemgui->x_glist); | |||
int f = (int)atom_getfloatarg(0, ac, av); | |||
if(f == 1) strcpy(iemgui->x_font, "helvetica"); | |||
else if(f == 2) strcpy(iemgui->x_font, "times"); | |||
else | |||
{ | |||
f = 0; | |||
strcpy(iemgui->x_font, sys_font); | |||
} | |||
iemgui->x_fsf.x_font_style = f; | |||
f = (int)atom_getfloatarg(1, ac, av); | |||
if(f < 4) | |||
f = 4; | |||
iemgui->x_fontsize = f; | |||
if(glist_isvisible(iemgui->x_glist)) | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s}\n", | |||
glist_getcanvas(iemgui->x_glist), x, iemgui->x_font, | |||
iemgui->x_fontsize*zoom, sys_fontweight); | |||
} | |||
void iemgui_size(void *x, t_iemgui *iemgui) | |||
{ | |||
if(glist_isvisible(iemgui->x_glist)) | |||
{ | |||
(*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(iemgui->x_glist, (t_text*)x); | |||
} | |||
} | |||
void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
int zoom = glist_getzoom(iemgui->x_glist); | |||
iemgui->x_obj.te_xpix += (int)atom_getfloatarg(0, ac, av)*zoom; | |||
iemgui->x_obj.te_ypix += (int)atom_getfloatarg(1, ac, av)*zoom; | |||
if(glist_isvisible(iemgui->x_glist)) | |||
{ | |||
(*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(iemgui->x_glist, (t_text*)x); | |||
} | |||
} | |||
void iemgui_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
int zoom = glist_getzoom(iemgui->x_glist); | |||
iemgui->x_obj.te_xpix = (int)atom_getfloatarg(0, ac, av)*zoom; | |||
iemgui->x_obj.te_ypix = (int)atom_getfloatarg(1, ac, av)*zoom; | |||
if(glist_isvisible(iemgui->x_glist)) | |||
{ | |||
(*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(iemgui->x_glist, (t_text*)x); | |||
} | |||
} | |||
void iemgui_color(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
if (ac >= 1) | |||
iemgui->x_bcol = iemgui_compatible_colorarg(0, ac, av); | |||
if (ac == 2 && pd_compatibilitylevel < 47) | |||
/* old versions of Pd updated foreground and label color | |||
if only two args; now we do it more coherently. */ | |||
iemgui->x_lcol = iemgui_compatible_colorarg(1, ac, av); | |||
else if (ac >= 2) | |||
iemgui->x_fcol = iemgui_compatible_colorarg(1, ac, av); | |||
if (ac >= 3) | |||
iemgui->x_lcol = iemgui_compatible_colorarg(2, ac, av); | |||
if(glist_isvisible(iemgui->x_glist)) | |||
(*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
} | |||
void iemgui_displace(t_gobj *z, t_glist *glist, int dx, int dy) | |||
{ | |||
t_iemgui *x = (t_iemgui *)z; | |||
x->x_obj.te_xpix += dx; | |||
x->x_obj.te_ypix += dy; | |||
(*x->x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(glist, (t_text *)z); | |||
} | |||
void iemgui_select(t_gobj *z, t_glist *glist, int selected) | |||
{ | |||
t_iemgui *x = (t_iemgui *)z; | |||
x->x_fsf.x_selected = selected; | |||
(*x->x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_SELECT); | |||
} | |||
void iemgui_delete(t_gobj *z, t_glist *glist) | |||
{ | |||
canvas_deletelinesfor(glist, (t_text *)z); | |||
} | |||
void iemgui_vis(t_gobj *z, t_glist *glist, int vis) | |||
{ | |||
t_iemgui *x = (t_iemgui *)z; | |||
if (vis) | |||
(*x->x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_NEW); | |||
else | |||
{ | |||
(*x->x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_ERASE); | |||
sys_unqueuegui(z); | |||
} | |||
} | |||
void iemgui_save(t_iemgui *iemgui, t_symbol **srl, t_symbol**bflcol) | |||
{ | |||
srl[0] = iemgui->x_snd; | |||
srl[1] = iemgui->x_rcv; | |||
srl[2] = iemgui->x_lab; | |||
iemgui_all_sym2dollararg(iemgui, srl); | |||
iemgui_all_col2save(iemgui, bflcol); | |||
} | |||
/* inform GUIs that glist's zoom is about to change. The glist will | |||
take care of x,y locations but we have to adjust width and height */ | |||
void iemgui_zoom(t_iemgui *iemgui, t_floatarg zoom) | |||
{ | |||
int oldzoom = iemgui->x_glist->gl_zoom; | |||
if (oldzoom < 1) | |||
oldzoom = 1; | |||
iemgui->x_w = (int)(iemgui->x_w)/oldzoom*(int)zoom; | |||
iemgui->x_h = (int)(iemgui->x_h)/oldzoom*(int)zoom; | |||
} | |||
/* when creating a new GUI from menu onto a zoomed canvas, pretend to | |||
change the canvas's zoom so we'll get properly sized */ | |||
void iemgui_newzoom(t_iemgui *iemgui) | |||
{ | |||
if (iemgui->x_glist->gl_zoom != 1) | |||
{ | |||
int newzoom = iemgui->x_glist->gl_zoom; | |||
iemgui->x_glist->gl_zoom = 1; | |||
iemgui_zoom(iemgui, (t_floatarg)newzoom); | |||
iemgui->x_glist->gl_zoom = newzoom; | |||
} | |||
} | |||
void iemgui_properties(t_iemgui *iemgui, t_symbol **srl) | |||
{ | |||
srl[0] = iemgui->x_snd; | |||
srl[1] = iemgui->x_rcv; | |||
srl[2] = iemgui->x_lab; | |||
iemgui_all_sym2dollararg(iemgui, srl); | |||
iemgui_all_dollar2raute(srl); | |||
} | |||
int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv) | |||
{ | |||
char str[144]; | |||
int init = (int)atom_getfloatarg(5, argc, argv); | |||
int ldx = (int)atom_getfloatarg(10, argc, argv); | |||
int ldy = (int)atom_getfloatarg(11, argc, argv); | |||
int f = (int)atom_getfloatarg(12, argc, argv); | |||
int fs = (int)atom_getfloatarg(13, argc, argv); | |||
int bcol = (int)iemgui_getcolorarg(14, argc, argv); | |||
int fcol = (int)iemgui_getcolorarg(15, argc, argv); | |||
int lcol = (int)iemgui_getcolorarg(16, argc, argv); | |||
int sndable=1, rcvable=1, oldsndrcvable=0; | |||
if(iemgui->x_fsf.x_rcv_able) | |||
oldsndrcvable += IEM_GUI_OLD_RCV_FLAG; | |||
if(iemgui->x_fsf.x_snd_able) | |||
oldsndrcvable += IEM_GUI_OLD_SND_FLAG; | |||
if(IS_A_SYMBOL(argv,7)) | |||
srl[0] = atom_getsymbolarg(7, argc, argv); | |||
else if(IS_A_FLOAT(argv,7)) | |||
{ | |||
sprintf(str, "%d", (int)atom_getfloatarg(7, argc, argv)); | |||
srl[0] = gensym(str); | |||
} | |||
if(IS_A_SYMBOL(argv,8)) | |||
srl[1] = atom_getsymbolarg(8, argc, argv); | |||
else if(IS_A_FLOAT(argv,8)) | |||
{ | |||
sprintf(str, "%d", (int)atom_getfloatarg(8, argc, argv)); | |||
srl[1] = gensym(str); | |||
} | |||
if(IS_A_SYMBOL(argv,9)) | |||
srl[2] = atom_getsymbolarg(9, argc, argv); | |||
else if(IS_A_FLOAT(argv,9)) | |||
{ | |||
sprintf(str, "%d", (int)atom_getfloatarg(9, argc, argv)); | |||
srl[2] = gensym(str); | |||
} | |||
if(init != 0) init = 1; | |||
iemgui->x_isa.x_loadinit = init; | |||
if(!strcmp(srl[0]->s_name, "empty")) sndable = 0; | |||
if(!strcmp(srl[1]->s_name, "empty")) rcvable = 0; | |||
iemgui_all_raute2dollar(srl); | |||
iemgui_all_dollararg2sym(iemgui, srl); | |||
if(rcvable) | |||
{ | |||
if(strcmp(srl[1]->s_name, iemgui->x_rcv->s_name)) | |||
{ | |||
if(iemgui->x_fsf.x_rcv_able) | |||
pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv); | |||
iemgui->x_rcv = srl[1]; | |||
pd_bind(&iemgui->x_obj.ob_pd, iemgui->x_rcv); | |||
} | |||
} | |||
else if(!rcvable && iemgui->x_fsf.x_rcv_able) | |||
{ | |||
pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv); | |||
iemgui->x_rcv = srl[1]; | |||
} | |||
iemgui->x_snd = srl[0]; | |||
iemgui->x_fsf.x_snd_able = sndable; | |||
iemgui->x_fsf.x_rcv_able = rcvable; | |||
iemgui->x_lcol = lcol & 0xffffff; | |||
iemgui->x_fcol = fcol & 0xffffff; | |||
iemgui->x_bcol = bcol & 0xffffff; | |||
iemgui->x_lab = srl[2]; | |||
iemgui->x_ldx = ldx; | |||
iemgui->x_ldy = ldy; | |||
if(f == 1) strcpy(iemgui->x_font, "helvetica"); | |||
else if(f == 2) strcpy(iemgui->x_font, "times"); | |||
else | |||
{ | |||
f = 0; | |||
strcpy(iemgui->x_font, sys_font); | |||
} | |||
iemgui->x_fsf.x_font_style = f; | |||
if(fs < 4) | |||
fs = 4; | |||
iemgui->x_fontsize = fs; | |||
iemgui_verify_snd_ne_rcv(iemgui); | |||
canvas_dirty(iemgui->x_glist, 1); | |||
return(oldsndrcvable); | |||
} | |||
/* pre-0.46 the flags were 1 for 'loadinit' and 1<<20 for 'scale'. | |||
Starting in 0.46, take either 1<<20 or 1<<1 for 'scale' and save to both | |||
bits (so that old versions can read files we write). In the future (2015?) | |||
we can stop writing the annoying 1<<20 bit. */ | |||
#define LOADINIT 1 | |||
#define SCALE 2 | |||
#define SCALEBIS (1<<20) | |||
void iem_inttosymargs(t_iem_init_symargs *symargp, int n) | |||
{ | |||
memset(symargp, 0, sizeof(*symargp)); | |||
symargp->x_loadinit = ((n & LOADINIT) != 0); | |||
symargp->x_scale = ((n & SCALE) || (n & SCALEBIS)) ; | |||
symargp->x_flashed = 0; | |||
symargp->x_locked = 0; | |||
} | |||
int iem_symargstoint(t_iem_init_symargs *symargp) | |||
{ | |||
return ((symargp->x_loadinit ? LOADINIT : 0) | | |||
(symargp->x_scale ? (SCALE | SCALEBIS) : 0)); | |||
} | |||
void iem_inttofstyle(t_iem_fstyle_flags *fstylep, int n) | |||
{ | |||
memset(fstylep, 0, sizeof(*fstylep)); | |||
fstylep->x_font_style = (n >> 0); | |||
fstylep->x_shiftdown = 0; | |||
fstylep->x_selected = 0; | |||
fstylep->x_finemoved = 0; | |||
fstylep->x_put_in2out = 0; | |||
fstylep->x_change = 0; | |||
fstylep->x_thick = 0; | |||
fstylep->x_lin0_log1 = 0; | |||
fstylep->x_steady = 0; | |||
} | |||
int iem_fstyletoint(t_iem_fstyle_flags *fstylep) | |||
{ | |||
return ((fstylep->x_font_style << 0) & 63); | |||
} | |||
/* for compatibility with pre-0.47 unofficial IEM GUIS like "knob". */ | |||
void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol) | |||
{ | |||
static int warned; | |||
if (!warned) | |||
{ | |||
post("warning:\ | |||
external GUI object uses obsolete Pd function iemgui_all_colfromload()"); | |||
warned = 1; | |||
} | |||
if(bflcol[0] < 0) | |||
{ | |||
bflcol[0] = -1 - bflcol[0]; | |||
iemgui->x_bcol = ((bflcol[0] & 0x3f000) << 6)|((bflcol[0] & 0xfc0) << 4)| | |||
((bflcol[0] & 0x3f) << 2); | |||
} | |||
else | |||
{ | |||
bflcol[0] = iemgui_modulo_color(bflcol[0]); | |||
iemgui->x_bcol = iemgui_color_hex[bflcol[0]]; | |||
} | |||
if(bflcol[1] < 0) | |||
{ | |||
bflcol[1] = -1 - bflcol[1]; | |||
iemgui->x_fcol = ((bflcol[1] & 0x3f000) << 6)|((bflcol[1] & 0xfc0) << 4)| | |||
((bflcol[1] & 0x3f) << 2); | |||
} | |||
else | |||
{ | |||
bflcol[1] = iemgui_modulo_color(bflcol[1]); | |||
iemgui->x_fcol = iemgui_color_hex[bflcol[1]]; | |||
} | |||
if(bflcol[2] < 0) | |||
{ | |||
bflcol[2] = -1 - bflcol[2]; | |||
iemgui->x_lcol = ((bflcol[2] & 0x3f000) << 6)|((bflcol[2] & 0xfc0) << 4)| | |||
((bflcol[2] & 0x3f) << 2); | |||
} | |||
else | |||
{ | |||
bflcol[2] = iemgui_modulo_color(bflcol[2]); | |||
iemgui->x_lcol = iemgui_color_hex[bflcol[2]]; | |||
} | |||
} | |||
@@ -0,0 +1,324 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.h written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
#define IEM_GUI_COLNR_WHITE 0 | |||
#define IEM_GUI_COLNR_ML_GREY 1 | |||
#define IEM_GUI_COLNR_D_GREY 2 | |||
#define IEM_GUI_COLNR_L_RED 3 | |||
#define IEM_GUI_COLNR_L_ORANGE 4 | |||
#define IEM_GUI_COLNR_L_YELLOW 5 | |||
#define IEM_GUI_COLNR_L_GREEN 6 | |||
#define IEM_GUI_COLNR_L_CYAN 7 | |||
#define IEM_GUI_COLNR_L_BLUE 8 | |||
#define IEM_GUI_COLNR_L_MAGENTA 9 | |||
#define IEM_GUI_COLNR_LL_GREY 10 | |||
#define IEM_GUI_COLNR_M_GREY 11 | |||
#define IEM_GUI_COLNR_DD_GREY 12 | |||
#define IEM_GUI_COLNR_RED 13 | |||
#define IEM_GUI_COLNR_ORANGE 14 | |||
#define IEM_GUI_COLNR_YELLOW 15 | |||
#define IEM_GUI_COLNR_GREEN 16 | |||
#define IEM_GUI_COLNR_CYAN 17 | |||
#define IEM_GUI_COLNR_BLUE 18 | |||
#define IEM_GUI_COLNR_MAGENTA 19 | |||
#define IEM_GUI_COLNR_L_GREY 20 | |||
#define IEM_GUI_COLNR_MD_GREY 21 | |||
#define IEM_GUI_COLNR_BLACK 22 | |||
#define IEM_GUI_COLNR_D_RED 23 | |||
#define IEM_GUI_COLNR_D_ORANGE 24 | |||
#define IEM_GUI_COLNR_D_YELLOW 25 | |||
#define IEM_GUI_COLNR_D_GREEN 26 | |||
#define IEM_GUI_COLNR_D_CYAN 27 | |||
#define IEM_GUI_COLNR_D_BLUE 28 | |||
#define IEM_GUI_COLNR_D_MAGENTA 29 | |||
#define IEM_GUI_COLOR_SELECTED 255 | |||
#define IEM_GUI_COLOR_NORMAL 0 | |||
#define IEM_GUI_MAX_COLOR 30 | |||
#define IEM_GUI_DEFAULTSIZE 15 | |||
#define IEM_GUI_MINSIZE 8 | |||
#define IEM_GUI_MAXSIZE 1000 | |||
#define IEM_SL_DEFAULTSIZE 128 | |||
#define IEM_SL_MINSIZE 2 | |||
#define IEM_FONT_MINSIZE 4 | |||
#define IEM_BNG_DEFAULTHOLDFLASHTIME 250 | |||
#define IEM_BNG_DEFAULTBREAKFLASHTIME 50 | |||
#define IEM_BNG_MINHOLDFLASHTIME 50 | |||
#define IEM_BNG_MINBREAKFLASHTIME 10 | |||
#define IEM_VU_DEFAULTSIZE 3 | |||
#define IEM_VU_LARGESMALL 2 | |||
#define IEM_VU_MINSIZE 2 | |||
#define IEM_VU_MAXSIZE 25 | |||
#define IEM_VU_STEPS 40 | |||
#define IEM_VU_MINDB -99.9 | |||
#define IEM_VU_MAXDB 12.0 | |||
#define IEM_VU_OFFSET 100.0 | |||
#define IEM_RADIO_MAX 128 | |||
#define IEM_SYM_UNIQUE_SND 256 | |||
#define IEM_SYM_UNIQUE_RCV 512 | |||
#define IEM_SYM_UNIQUE_LAB 1024 | |||
#define IEM_SYM_UNIQUE_ALL 1792 | |||
#define IEM_FONT_STYLE_ALL 255 | |||
#define IEM_MAX_SYM_LEN 127 | |||
#define IEM_GUI_DRAW_MODE_UPDATE 0 | |||
#define IEM_GUI_DRAW_MODE_MOVE 1 | |||
#define IEM_GUI_DRAW_MODE_NEW 2 | |||
#define IEM_GUI_DRAW_MODE_SELECT 3 | |||
#define IEM_GUI_DRAW_MODE_ERASE 4 | |||
#define IEM_GUI_DRAW_MODE_CONFIG 5 | |||
#define IEM_GUI_DRAW_MODE_IO 6 | |||
#define IEM_GUI_IOHEIGHT 2 | |||
#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER) | |||
#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT) | |||
#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL) | |||
#define IS_A_DOLLAR(atom,index) ((atom+index)->a_type == A_DOLLAR) | |||
#define IS_A_DOLLSYM(atom,index) ((atom+index)->a_type == A_DOLLSYM) | |||
#define IEM_FSTYLE_FLAGS_ALL 0x007fffff | |||
#define IEM_INIT_ARGS_ALL 0x01ffffff | |||
#define IEM_GUI_OLD_SND_FLAG 1 | |||
#define IEM_GUI_OLD_RCV_FLAG 2 | |||
#define IEM_GUI_COLOR_EDITED 16711680 | |||
#define IEMGUI_MAX_NUM_LEN 32 | |||
#define IEMGUI_ZOOM(x) ((x)->x_gui.x_glist->gl_zoom) | |||
typedef struct _iem_fstyle_flags | |||
{ | |||
unsigned int x_font_style:6; | |||
unsigned int x_rcv_able:1; | |||
unsigned int x_snd_able:1; | |||
unsigned int x_lab_is_unique:1; | |||
unsigned int x_rcv_is_unique:1; | |||
unsigned int x_snd_is_unique:1; | |||
unsigned int x_lab_arg_tail_len:6; | |||
unsigned int x_lab_is_arg_num:6; | |||
unsigned int x_shiftdown:1; | |||
unsigned int x_selected:1; | |||
unsigned int x_finemoved:1; | |||
unsigned int x_put_in2out:1; | |||
unsigned int x_change:1; | |||
unsigned int x_thick:1; | |||
unsigned int x_lin0_log1:1; | |||
unsigned int x_steady:1; | |||
} t_iem_fstyle_flags; | |||
typedef struct _iem_init_symargs | |||
{ | |||
unsigned int x_loadinit:1; | |||
unsigned int x_rcv_arg_tail_len:6; | |||
unsigned int x_snd_arg_tail_len:6; | |||
unsigned int x_rcv_is_arg_num:6; | |||
unsigned int x_snd_is_arg_num:6; | |||
unsigned int x_scale:1; | |||
unsigned int x_flashed:1; | |||
unsigned int x_locked:1; | |||
} t_iem_init_symargs; | |||
typedef void (*t_iemfunptr)(void *x, t_glist *glist, int mode); | |||
typedef struct _iemgui | |||
{ | |||
t_object x_obj; | |||
t_glist *x_glist; | |||
t_iemfunptr x_draw; | |||
int x_h; | |||
int x_w; | |||
int x_ldx; | |||
int x_ldy; | |||
char x_font[MAXPDSTRING]; /* font names can be long! */ | |||
t_iem_fstyle_flags x_fsf; | |||
int x_fontsize; | |||
t_iem_init_symargs x_isa; | |||
int x_fcol; | |||
int x_bcol; | |||
int x_lcol; | |||
t_symbol *x_snd; /* send symbol */ | |||
t_symbol *x_rcv; /* receive */ | |||
t_symbol *x_lab; /* label */ | |||
t_symbol *x_snd_unexpanded; /* same 3, with '$' unexpanded */ | |||
t_symbol *x_rcv_unexpanded; | |||
t_symbol *x_lab_unexpanded; | |||
int x_binbufindex; /* where in binbuf to find these */ | |||
int x_labelbindex; /* where in binbuf to find label */ | |||
} t_iemgui; | |||
typedef struct _bng | |||
{ | |||
t_iemgui x_gui; | |||
int x_flashed; | |||
int x_flashtime_break; | |||
int x_flashtime_hold; | |||
t_clock *x_clock_hld; | |||
t_clock *x_clock_brk; | |||
t_clock *x_clock_lck; | |||
double x_lastflashtime; | |||
} t_bng; | |||
typedef struct _hslider | |||
{ | |||
t_iemgui x_gui; | |||
int x_pos; | |||
int x_val; | |||
int x_lin0_log1; | |||
int x_steady; | |||
double x_min; | |||
double x_max; | |||
double x_k; | |||
t_float x_fval; | |||
} t_hslider; | |||
typedef struct _hdial | |||
{ | |||
t_iemgui x_gui; | |||
int x_on; | |||
int x_on_old; /* LATER delete this; it's used for old version */ | |||
int x_change; | |||
int x_number; | |||
int x_drawn; | |||
t_float x_fval; | |||
t_atom x_at[2]; | |||
} t_hdial; | |||
typedef struct _toggle | |||
{ | |||
t_iemgui x_gui; | |||
t_float x_on; | |||
t_float x_nonzero; | |||
} t_toggle; | |||
typedef struct _my_canvas | |||
{ | |||
t_iemgui x_gui; | |||
t_atom x_at[3]; | |||
int x_vis_w; | |||
int x_vis_h; | |||
} t_my_canvas; | |||
typedef struct _vslider | |||
{ | |||
t_iemgui x_gui; | |||
int x_pos; | |||
int x_val; | |||
int x_lin0_log1; | |||
int x_steady; | |||
double x_min; | |||
double x_max; | |||
double x_k; | |||
t_float x_fval; | |||
} t_vslider; | |||
typedef struct _vu | |||
{ | |||
t_iemgui x_gui; | |||
int x_led_size; | |||
int x_peak; | |||
int x_rms; | |||
t_float x_fp; | |||
t_float x_fr; | |||
int x_scale; | |||
void *x_out_rms; | |||
void *x_out_peak; | |||
unsigned int x_updaterms:1; | |||
unsigned int x_updatepeak:1; | |||
} t_vu; | |||
typedef struct _my_numbox | |||
{ | |||
t_iemgui x_gui; | |||
t_clock *x_clock_reset; | |||
t_clock *x_clock_wait; | |||
double x_val; | |||
double x_min; | |||
double x_max; | |||
double x_k; | |||
int x_lin0_log1; | |||
char x_buf[IEMGUI_MAX_NUM_LEN]; | |||
int x_numwidth; | |||
int x_log_height; | |||
} t_my_numbox; | |||
typedef struct _vdial | |||
{ | |||
t_iemgui x_gui; | |||
int x_on; | |||
int x_on_old; | |||
int x_change; | |||
int x_number; | |||
int x_drawn; | |||
t_float x_fval; | |||
t_atom x_at[2]; | |||
} t_vdial; | |||
#define t_vradio t_vdial | |||
#define t_hradio t_hdial | |||
extern int iemgui_color_hex[]; | |||
extern int iemgui_vu_db2i[]; | |||
extern int iemgui_vu_col[]; | |||
extern char *iemgui_vu_scale_str[]; | |||
EXTERN int iemgui_clip_size(int size); | |||
EXTERN int iemgui_clip_font(int size); | |||
EXTERN t_symbol *iemgui_unique2dollarzero(t_symbol *s, int unique_num, int and_unique_flag); | |||
EXTERN t_symbol *iemgui_sym2dollararg(t_symbol *s, int nth_arg, int tail_len); | |||
EXTERN t_symbol *iemgui_dollarzero2unique(t_symbol *s, int unique_num); | |||
EXTERN t_symbol *iemgui_dollararg2sym(t_symbol *s, int nth_arg, int tail_len, int pargc, t_atom *pargv); | |||
EXTERN int iemgui_is_dollarzero(t_symbol *s); | |||
EXTERN int iemgui_is_dollararg(t_symbol *s, int *tail_len); | |||
EXTERN void iemgui_fetch_unique(t_iemgui *iemgui); | |||
EXTERN void iemgui_fetch_parent_args(t_iemgui *iemgui, int *pargc, t_atom **pargv); | |||
EXTERN void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui); | |||
EXTERN void iemgui_all_unique2dollarzero(t_iemgui *iemgui, t_symbol **srlsym); | |||
EXTERN void iemgui_all_sym2dollararg(t_iemgui *iemgui, t_symbol **srlsym); | |||
EXTERN void iemgui_all_dollarzero2unique(t_iemgui *iemgui, t_symbol **srlsym); | |||
EXTERN t_symbol *iemgui_new_dogetname(t_iemgui *iemgui, int indx, t_atom *argv); | |||
EXTERN void iemgui_new_getnames(t_iemgui *iemgui, int indx, t_atom *argv); | |||
EXTERN void iemgui_all_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym); | |||
EXTERN void iemgui_all_loadcolors(t_iemgui *iemgui, t_atom*bcol, t_atom*fcol, t_atom*lcol); | |||
EXTERN void iemgui_all_dollar2raute(t_symbol **srlsym); | |||
EXTERN void iemgui_all_raute2dollar(t_symbol **srlsym); | |||
EXTERN void iemgui_send(void *x, t_iemgui *iemgui, t_symbol *s); | |||
EXTERN void iemgui_receive(void *x, t_iemgui *iemgui, t_symbol *s); | |||
EXTERN void iemgui_label(void *x, t_iemgui *iemgui, t_symbol *s); | |||
EXTERN void iemgui_label_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av); | |||
EXTERN void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av); | |||
EXTERN void iemgui_size(void *x, t_iemgui *iemgui); | |||
EXTERN void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av); | |||
EXTERN void iemgui_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av); | |||
EXTERN void iemgui_color(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av); | |||
EXTERN int iemgui_list(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av); | |||
EXTERN void iemgui_displace(t_gobj *z, t_glist *glist, int dx, int dy); | |||
EXTERN void iemgui_select(t_gobj *z, t_glist *glist, int selected); | |||
EXTERN void iemgui_delete(t_gobj *z, t_glist *glist); | |||
EXTERN void iemgui_vis(t_gobj *z, t_glist *glist, int vis); | |||
EXTERN void iemgui_save(t_iemgui *iemgui, t_symbol **srl, t_symbol **bflcol); | |||
EXTERN void iemgui_zoom(t_iemgui *iemgui, t_floatarg zoom); | |||
EXTERN void iemgui_newzoom(t_iemgui *iemgui); | |||
EXTERN void iemgui_properties(t_iemgui *iemgui, t_symbol **srl); | |||
EXTERN int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv); | |||
EXTERN int canvas_getdollarzero(void); | |||
EXTERN void canvas_getargs(int *argcp, t_atom **argvp); | |||
EXTERN void iem_inttosymargs(t_iem_init_symargs *symargp, int n); | |||
EXTERN int iem_symargstoint(t_iem_init_symargs *symargp); | |||
EXTERN void iem_inttofstyle(t_iem_fstyle_flags *fstylep, int n); | |||
EXTERN int iem_fstyletoint(t_iem_fstyle_flags *fstylep); |
@@ -0,0 +1,578 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
/* --------------- bng gui-bang ------------------------- */ | |||
t_widgetbehavior bng_widgetbehavior; | |||
static t_class *bng_class; | |||
/* widget helper functions */ | |||
void bng_draw_update(t_bng *x, t_glist *glist) | |||
{ | |||
if(glist_isvisible(glist)) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT -fill #%6.6x\n", | |||
glist_getcanvas(glist), x, | |||
(x->x_flashed ? x->x_gui.x_fcol : x->x_gui.x_bcol)); | |||
} | |||
} | |||
void bng_draw_new(t_bng *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int inset = IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -width %d -fill #%6.6x -tags %lxBASE\n", | |||
canvas, xpos, ypos, | |||
xpos + x->x_gui.x_w, ypos + x->x_gui.x_h, | |||
IEMGUI_ZOOM(x), | |||
x->x_gui.x_bcol, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
sys_vgui(".x%lx.c create oval %d %d %d %d -width %d -fill #%6.6x -tags %lxBUT\n", | |||
canvas, xpos + inset, ypos + inset, | |||
xpos + x->x_gui.x_w - inset, ypos + x->x_gui.x_h - inset, | |||
IEMGUI_ZOOM(x), | |||
(x->x_flashed ? x->x_gui.x_fcol : x->x_gui.x_bcol), x); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%6.6x -tags [list %lxLABEL label text]\n", | |||
canvas, xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
} | |||
void bng_draw_move(t_bng *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int inset = IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c coords %lxBASE %d %d %d %d\n", | |||
canvas, x, xpos, ypos, | |||
xpos + x->x_gui.x_w, ypos + x->x_gui.x_h); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh); | |||
sys_vgui(".x%lx.c coords %lxBUT %d %d %d %d\n", | |||
canvas, x, xpos + inset, ypos + inset, | |||
xpos + x->x_gui.x_w - inset, ypos + x->x_gui.x_h - inset); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT -fill #%6.6x\n", canvas, x, | |||
(x->x_flashed ? x->x_gui.x_fcol : x->x_gui.x_bcol)); | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
} | |||
void bng_draw_erase(t_bng* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxBUT\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
void bng_draw_config(t_bng* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%6.6x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : "")); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT -fill #%6.6x\n", canvas, x, | |||
(x->x_flashed ? x->x_gui.x_fcol : x->x_gui.x_bcol)); | |||
} | |||
void bng_draw_io(t_bng* x, t_glist* glist, int old_snd_rcv_flags) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able) { | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
/* keep above outlet */ | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxOUT%d\n", canvas, x, x, 0); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able) { | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
/* keep above inlet */ | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxIN%d\n", canvas, x, x, 0); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
void bng_draw_select(t_bng* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol); | |||
} | |||
} | |||
void bng_draw(t_bng *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_UPDATE) | |||
bng_draw_update(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
bng_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
bng_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
bng_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
bng_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
bng_draw_config(x, glist); | |||
else if(mode >= IEM_GUI_DRAW_MODE_IO) | |||
bng_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO); | |||
} | |||
/* ------------------------ bng widgetbehaviour----------------------------- */ | |||
static void bng_getrect(t_gobj *z, t_glist *glist, | |||
int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_bng *x = (t_bng *)z; | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist); | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist); | |||
*xp2 = *xp1 + x->x_gui.x_w; | |||
*yp2 = *yp1 + x->x_gui.x_h; | |||
} | |||
static void bng_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_bng *x = (t_bng *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
binbuf_addv(b, "ssiisiiiisssiiiisss", gensym("#X"),gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix, | |||
gensym("bng"), x->x_gui.x_w/IEMGUI_ZOOM(x), | |||
x->x_flashtime_hold, x->x_flashtime_break, | |||
iem_symargstoint(&x->x_gui.x_isa), | |||
srl[0], srl[1], srl[2], | |||
x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[1], bflcol[2]); | |||
binbuf_addv(b, ";"); | |||
} | |||
void bng_check_minmax(t_bng *x, int ftbreak, int fthold) | |||
{ | |||
if(ftbreak > fthold) | |||
{ | |||
int h; | |||
h = ftbreak; | |||
ftbreak = fthold; | |||
fthold = h; | |||
} | |||
if(ftbreak < IEM_BNG_MINBREAKFLASHTIME) | |||
ftbreak = IEM_BNG_MINBREAKFLASHTIME; | |||
if(fthold < IEM_BNG_MINHOLDFLASHTIME) | |||
fthold = IEM_BNG_MINHOLDFLASHTIME; | |||
x->x_flashtime_break = ftbreak; | |||
x->x_flashtime_hold = fthold; | |||
} | |||
static void bng_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_bng *x = (t_bng *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
iemgui_properties(&x->x_gui, srl); | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |bang| \ | |||
----------dimensions(pix):----------- %d %d size: 0 0 empty \ | |||
--------flash-time(ms)(ms):--------- %d intrrpt: %d hold: %d \ | |||
%d empty empty %d %d empty %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x #%06x #%06x\n", | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), IEM_GUI_MINSIZE, | |||
x->x_flashtime_break, x->x_flashtime_hold, 2,/*min_max_schedule+clip*/ | |||
-1, x->x_gui.x_isa.x_loadinit, -1, -1,/*no linlog, no multi*/ | |||
srl[0]->s_name, srl[1]->s_name, | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
static void bng_set(t_bng *x) | |||
{ | |||
int holdtime = x->x_flashtime_hold; | |||
int sincelast = clock_gettimesince(x->x_lastflashtime); | |||
x->x_lastflashtime = clock_getsystime(); | |||
if (sincelast < x->x_flashtime_hold*2) | |||
holdtime = sincelast/2; | |||
if (holdtime < x->x_flashtime_break) | |||
holdtime = x->x_flashtime_break; | |||
x->x_flashed = 1; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
clock_delay(x->x_clock_hld, holdtime); | |||
} | |||
static void bng_bout1(t_bng *x) /*wird nur mehr gesendet, wenn snd != rcv*/ | |||
{ | |||
if(!x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
x->x_gui.x_isa.x_locked = 1; | |||
clock_delay(x->x_clock_lck, 2); | |||
} | |||
outlet_bang(x->x_gui.x_obj.ob_outlet); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing && x->x_gui.x_fsf.x_put_in2out) | |||
pd_bang(x->x_gui.x_snd->s_thing); | |||
} | |||
static void bng_bout2(t_bng *x) /*wird immer gesendet, wenn moeglich*/ | |||
{ | |||
if(!x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
x->x_gui.x_isa.x_locked = 1; | |||
clock_delay(x->x_clock_lck, 2); | |||
} | |||
outlet_bang(x->x_gui.x_obj.ob_outlet); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_bang(x->x_gui.x_snd->s_thing); | |||
} | |||
static void bng_bang(t_bng *x) /*wird nur mehr gesendet, wenn snd != rcv*/ | |||
{ | |||
if(!x->x_gui.x_isa.x_locked) | |||
{ | |||
bng_set(x); | |||
bng_bout1(x); | |||
} | |||
} | |||
static void bng_bang2(t_bng *x) /*wird immer gesendet, wenn moeglich*/ | |||
{ | |||
if(!x->x_gui.x_isa.x_locked) | |||
{ | |||
bng_set(x); | |||
bng_bout2(x); | |||
} | |||
} | |||
static void bng_dialog(t_bng *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int a = (int)atom_getfloatarg(0, argc, argv); | |||
int fthold = (int)atom_getfloatarg(2, argc, argv); | |||
int ftbreak = (int)atom_getfloatarg(3, argc, argv); | |||
int sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
x->x_gui.x_w = iemgui_clip_size(a) * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
bng_check_minmax(x, ftbreak, fthold); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
static void bng_click(t_bng *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | |||
{ | |||
bng_set(x); | |||
bng_bout2(x); | |||
} | |||
static int bng_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit) | |||
{ | |||
if(doit) | |||
bng_click((t_bng *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt); | |||
return (1); | |||
} | |||
static void bng_float(t_bng *x, t_floatarg f) | |||
{bng_bang2(x);} | |||
static void bng_symbol(t_bng *x, t_symbol *s) | |||
{bng_bang2(x);} | |||
static void bng_pointer(t_bng *x, t_gpointer *gp) | |||
{bng_bang2(x);} | |||
static void bng_list(t_bng *x, t_symbol *s, int ac, t_atom *av) | |||
{bng_bang2(x);} | |||
static void bng_anything(t_bng *x, t_symbol *s, int argc, t_atom *argv) | |||
{bng_bang2(x);} | |||
static void bng_loadbang(t_bng *x, t_floatarg action) | |||
{ | |||
if (action == LB_LOAD && x->x_gui.x_isa.x_loadinit) | |||
{ | |||
bng_set(x); | |||
bng_bout2(x); | |||
} | |||
} | |||
static void bng_size(t_bng *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
x->x_gui.x_w = iemgui_clip_size((int)atom_getfloatarg(0, ac, av)) * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
iemgui_size((void *)x, &x->x_gui); | |||
} | |||
static void bng_delta(t_bng *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void bng_pos(t_bng *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void bng_flashtime(t_bng *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
bng_check_minmax(x, (int)atom_getfloatarg(0, ac, av), | |||
(int)atom_getfloatarg(1, ac, av)); | |||
} | |||
static void bng_color(t_bng *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void bng_send(t_bng *x, t_symbol *s) | |||
{iemgui_send(x, &x->x_gui, s);} | |||
static void bng_receive(t_bng *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void bng_label(t_bng *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void bng_label_pos(t_bng *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void bng_label_font(t_bng *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);} | |||
static void bng_init(t_bng *x, t_floatarg f) | |||
{ | |||
x->x_gui.x_isa.x_loadinit = (f == 0.0) ? 0 : 1; | |||
} | |||
static void bng_tick_hld(t_bng *x) | |||
{ | |||
x->x_flashed = 0; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
} | |||
static void bng_tick_lck(t_bng *x) | |||
{ | |||
x->x_gui.x_isa.x_locked = 0; | |||
} | |||
static void *bng_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_bng *x = (t_bng *)pd_new(bng_class); | |||
int a = IEM_GUI_DEFAULTSIZE; | |||
int ldx = 17, ldy = 7; | |||
int fs = 10; | |||
int ftbreak = IEM_BNG_DEFAULTBREAKFLASHTIME, | |||
fthold = IEM_BNG_DEFAULTHOLDFLASHTIME; | |||
char str[144]; | |||
iem_inttosymargs(&x->x_gui.x_isa, 0); | |||
iem_inttofstyle(&x->x_gui.x_fsf, 0); | |||
x->x_gui.x_bcol = 0xFCFCFC; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x00; | |||
if((argc == 14)&&IS_A_FLOAT(argv,0) | |||
&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2) | |||
&&IS_A_FLOAT(argv,3) | |||
&&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4)) | |||
&&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5)) | |||
&&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6)) | |||
&&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8) | |||
&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)) | |||
{ | |||
a = (int)atom_getfloatarg(0, argc, argv); | |||
fthold = (int)atom_getfloatarg(1, argc, argv); | |||
ftbreak = (int)atom_getfloatarg(2, argc, argv); | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(3, argc, argv)); | |||
iemgui_new_getnames(&x->x_gui, 4, argv); | |||
ldx = (int)atom_getfloatarg(7, argc, argv); | |||
ldy = (int)atom_getfloatarg(8, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(9, argc, argv)); | |||
fs = (int)atom_getfloatarg(10, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+11, argv+12, argv+13); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 4, 0); | |||
x->x_gui.x_draw = (t_iemfunptr)bng_draw; | |||
x->x_gui.x_fsf.x_snd_able = 1; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_flashed = 0; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if (!strcmp(x->x_gui.x_snd->s_name, "empty")) | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
if (!strcmp(x->x_gui.x_rcv->s_name, "empty")) | |||
x->x_gui.x_fsf.x_rcv_able = 0; | |||
if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
if (x->x_gui.x_fsf.x_rcv_able) | |||
pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < 4) | |||
fs = 4; | |||
x->x_gui.x_fontsize = fs; | |||
x->x_gui.x_w = iemgui_clip_size(a); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
bng_check_minmax(x, ftbreak, fthold); | |||
x->x_gui.x_isa.x_locked = 0; | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
x->x_lastflashtime = clock_getsystime(); | |||
x->x_clock_hld = clock_new(x, (t_method)bng_tick_hld); | |||
x->x_clock_lck = clock_new(x, (t_method)bng_tick_lck); | |||
iemgui_newzoom(&x->x_gui); | |||
outlet_new(&x->x_gui.x_obj, &s_bang); | |||
return (x); | |||
} | |||
static void bng_ff(t_bng *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
clock_free(x->x_clock_lck); | |||
clock_free(x->x_clock_hld); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_bang_setup(void) | |||
{ | |||
bng_class = class_new(gensym("bng"), (t_newmethod)bng_new, | |||
(t_method)bng_ff, sizeof(t_bng), 0, A_GIMME, 0); | |||
class_addbang(bng_class, bng_bang); | |||
class_addfloat(bng_class, bng_float); | |||
class_addsymbol(bng_class, bng_symbol); | |||
class_addpointer(bng_class, bng_pointer); | |||
class_addlist(bng_class, bng_list); | |||
class_addanything(bng_class, bng_anything); | |||
class_addmethod(bng_class, (t_method)bng_click, | |||
gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(bng_class, (t_method)bng_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(bng_class, (t_method)bng_loadbang, | |||
gensym("loadbang"), A_DEFFLOAT, 0); | |||
class_addmethod(bng_class, (t_method)bng_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(bng_class, (t_method)bng_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(bng_class, (t_method)bng_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(bng_class, (t_method)bng_flashtime, | |||
gensym("flashtime"), A_GIMME, 0); | |||
class_addmethod(bng_class, (t_method)bng_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(bng_class, (t_method)bng_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(bng_class, (t_method)bng_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(bng_class, (t_method)bng_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(bng_class, (t_method)bng_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(bng_class, (t_method)bng_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(bng_class, (t_method)bng_init, | |||
gensym("init"), A_FLOAT, 0); | |||
class_addmethod(bng_class, (t_method)iemgui_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
bng_widgetbehavior.w_getrectfn = bng_getrect; | |||
bng_widgetbehavior.w_displacefn = iemgui_displace; | |||
bng_widgetbehavior.w_selectfn = iemgui_select; | |||
bng_widgetbehavior.w_activatefn = NULL; | |||
bng_widgetbehavior.w_deletefn = iemgui_delete; | |||
bng_widgetbehavior.w_visfn = iemgui_vis; | |||
bng_widgetbehavior.w_clickfn = bng_newclick; | |||
class_setwidget(bng_class, &bng_widgetbehavior); | |||
class_sethelpsymbol(bng_class, gensym("bng")); | |||
class_setsavefn(bng_class, bng_save); | |||
class_setpropertiesfn(bng_class, bng_properties); | |||
} |
@@ -0,0 +1,663 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* this file defines the structure for "glists" and related structures and | |||
functions. "Glists" and "canvases" and "graphs" used to be different | |||
structures until being unified in version 0.35. | |||
A glist occupies its own window if the "gl_havewindow" flag is set. Its | |||
appearance on its "parent", also called "owner", (if it has one) is as a graph | |||
if "gl_isgraph" is set, and otherwise as a text box. | |||
A glist is "root" if it has no owner, i.e., a document window. In this | |||
case "gl_havewindow" is always set. | |||
We maintain a list of root windows, so that we can traverse the whole | |||
collection of everything in a Pd process. | |||
If a glist has a window it may still not be "mapped." Miniaturized | |||
windows aren't mapped, for example, but a window is also not mapped | |||
immediately upon creation. In either case gl_havewindow is true but | |||
gl_mapped is false. | |||
Closing a non-root window makes it invisible; closing a root destroys it. | |||
A glist that's just a text object on its parent is always "toplevel." An | |||
embedded glist can switch back and forth to appear as a toplevel by double- | |||
clicking on it. Single-clicking a text box makes the toplevel become visible | |||
and raises the window it's in. | |||
If a glist shows up as a graph on its parent, the graph is blanked while the | |||
glist has its own window, even if miniaturized. | |||
*/ | |||
/* NOTE: this file describes Pd implementation details which may change | |||
in future releases. The public (stable) API is in m_pd.h. */ | |||
#ifndef G_CANVAS_H | |||
#define G_CANVAS_H | |||
#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) | |||
extern "C" { | |||
#endif | |||
/* --------------------- geometry ---------------------------- */ | |||
#define IOWIDTH 7 /* width of an inlet/outlet in pixels */ | |||
#define IHEIGHT 3 /* height of an inlet in pixels */ | |||
#define OHEIGHT 3 /* height of an outlet in pixels */ | |||
#define IOMIDDLE ((IOWIDTH-1)/2) | |||
#define GLIST_DEFGRAPHWIDTH 200 | |||
#define GLIST_DEFGRAPHHEIGHT 140 | |||
/* ----------------------- data ------------------------------- */ | |||
typedef struct _updateheader | |||
{ | |||
struct _updateheader *upd_next; | |||
unsigned int upd_array:1; /* true if array, false if glist */ | |||
unsigned int upd_queued:1; /* true if we're queued */ | |||
} t_updateheader; | |||
/* types to support glists grabbing mouse motion or keys from parent */ | |||
typedef void (*t_glistmotionfn)(void *z, t_floatarg dx, t_floatarg dy); | |||
typedef void (*t_glistkeyfn)(void *z, t_floatarg key); | |||
EXTERN_STRUCT _rtext; | |||
#define t_rtext struct _rtext | |||
EXTERN_STRUCT _gtemplate; | |||
#define t_gtemplate struct _gtemplate | |||
EXTERN_STRUCT _guiconnect; | |||
#define t_guiconnect struct _guiconnect | |||
EXTERN_STRUCT _tscalar; | |||
#define t_tscalar struct _tscalar | |||
EXTERN_STRUCT _canvasenvironment; | |||
#define t_canvasenvironment struct _canvasenvironment | |||
EXTERN_STRUCT _fielddesc; | |||
#define t_fielddesc struct _fielddesc | |||
typedef struct _selection | |||
{ | |||
t_gobj *sel_what; | |||
struct _selection *sel_next; | |||
} t_selection; | |||
/* this structure is instantiated whenever a glist becomes visible. */ | |||
typedef struct _editor | |||
{ | |||
t_updateheader e_upd; /* update header structure */ | |||
t_selection *e_updlist; /* list of objects to update */ | |||
t_rtext *e_rtext; /* text responder linked list */ | |||
t_selection *e_selection; /* head of the selection list */ | |||
t_rtext *e_textedfor; /* the rtext if any that we are editing */ | |||
t_gobj *e_grab; /* object being "dragged" */ | |||
t_glistmotionfn e_motionfn; /* ... motion callback */ | |||
t_glistkeyfn e_keyfn; /* ... keypress callback */ | |||
t_binbuf *e_connectbuf; /* connections to deleted objects */ | |||
t_binbuf *e_deleted; /* last stuff we deleted */ | |||
t_guiconnect *e_guiconnect; /* GUI connection for filtering messages */ | |||
struct _glist *e_glist; /* glist which owns this */ | |||
int e_xwas; /* xpos on last mousedown or motion event */ | |||
int e_ywas; /* ypos, similarly */ | |||
int e_selectline_index1; /* indices for the selected line if any */ | |||
int e_selectline_outno; /* (only valid if e_selectedline is set) */ | |||
int e_selectline_index2; | |||
int e_selectline_inno; | |||
t_outconnect *e_selectline_tag; | |||
unsigned int e_onmotion: 3; /* action to take on motion */ | |||
unsigned int e_lastmoved: 1; /* one if mouse has moved since click */ | |||
unsigned int e_textdirty: 1; /* one if e_textedfor has changed */ | |||
unsigned int e_selectedline: 1; /* one if a line is selected */ | |||
t_clock *e_clock; /* clock to filter GUI move messages */ | |||
int e_xnew; /* xpos for next move event */ | |||
int e_ynew; /* ypos, similarly */ | |||
} t_editor; | |||
#define MA_NONE 0 /* e_onmotion: do nothing on mouse motion */ | |||
#define MA_MOVE 1 /* drag the selection around */ | |||
#define MA_CONNECT 2 /* make a connection */ | |||
#define MA_REGION 3 /* selection region */ | |||
#define MA_PASSOUT 4 /* send on to e_grab */ | |||
#define MA_DRAGTEXT 5 /* drag in text editor to alter selection */ | |||
#define MA_RESIZE 6 /* drag to resize */ | |||
/* editor structure for "garrays". We don't bother to delete and regenerate | |||
this structure when the "garray" becomes invisible or visible, although we | |||
could do so if the structure gets big (like the "editor" above.) */ | |||
typedef struct _arrayvis | |||
{ | |||
t_updateheader av_upd; /* update header structure */ | |||
t_garray *av_garray; /* owning structure */ | |||
} t_arrayvis; | |||
/* the t_tick structure describes where to draw x and y "ticks" for a glist */ | |||
typedef struct _tick /* where to put ticks on x or y axes */ | |||
{ | |||
t_float k_point; /* one point to draw a big tick at */ | |||
t_float k_inc; /* x or y increment per little tick */ | |||
int k_lperb; /* little ticks per big; 0 if no ticks to draw */ | |||
} t_tick; | |||
/* the t_glist structure, which describes a list of elements that live on an | |||
area of a window. | |||
*/ | |||
struct _glist | |||
{ | |||
t_object gl_obj; /* header in case we're a glist */ | |||
t_gobj *gl_list; /* the actual data */ | |||
struct _gstub *gl_stub; /* safe pointer handler */ | |||
int gl_valid; /* incremented when pointers might be stale */ | |||
struct _glist *gl_owner; /* parent glist, supercanvas, or 0 if none */ | |||
int gl_pixwidth; /* width in pixels (on parent, if a graph) */ | |||
int gl_pixheight; | |||
t_float gl_x1; /* bounding rectangle in our own coordinates */ | |||
t_float gl_y1; | |||
t_float gl_x2; | |||
t_float gl_y2; | |||
int gl_screenx1; /* screen coordinates when toplevel */ | |||
int gl_screeny1; | |||
int gl_screenx2; | |||
int gl_screeny2; | |||
int gl_xmargin; /* origin for GOP rectangle */ | |||
int gl_ymargin; | |||
t_tick gl_xtick; /* ticks marking X values */ | |||
int gl_nxlabels; /* number of X coordinate labels */ | |||
t_symbol **gl_xlabel; /* ... an array to hold them */ | |||
t_float gl_xlabely; /* ... and their Y coordinates */ | |||
t_tick gl_ytick; /* same as above for Y ticks and labels */ | |||
int gl_nylabels; | |||
t_symbol **gl_ylabel; | |||
t_float gl_ylabelx; | |||
t_editor *gl_editor; /* editor structure when visible */ | |||
t_symbol *gl_name; /* symbol bound here */ | |||
int gl_font; /* nominal font size in points, e.g., 10 */ | |||
struct _glist *gl_next; /* link in list of toplevels */ | |||
t_canvasenvironment *gl_env; /* root canvases and abstractions only */ | |||
unsigned int gl_havewindow:1; /* true if we own a window */ | |||
unsigned int gl_mapped:1; /* true if, moreover, it's "mapped" */ | |||
unsigned int gl_dirty:1; /* (root canvas only:) patch has changed */ | |||
unsigned int gl_loading:1; /* am now loading from file */ | |||
unsigned int gl_willvis:1; /* make me visible after loading */ | |||
unsigned int gl_edit:1; /* edit mode */ | |||
unsigned int gl_isdeleting:1; /* we're inside glist_delete -- hack! */ | |||
unsigned int gl_goprect:1; /* draw rectangle for graph-on-parent */ | |||
unsigned int gl_isgraph:1; /* show as graph on parent */ | |||
unsigned int gl_hidetext:1; /* hide object-name + args when doing graph on parent */ | |||
unsigned int gl_private:1; /* private flag used in x_scalar.c */ | |||
unsigned int gl_isclone:1; /* exists as part of a clone object */ | |||
int gl_zoom; /* zoom factor (integer zoom-in only) */ | |||
}; | |||
#define gl_gobj gl_obj.te_g | |||
#define gl_pd gl_gobj.g_pd | |||
/* a data structure to describe a field in a pure datum */ | |||
#define DT_FLOAT 0 | |||
#define DT_SYMBOL 1 | |||
#define DT_TEXT 2 | |||
#define DT_ARRAY 3 | |||
typedef struct _dataslot | |||
{ | |||
int ds_type; | |||
t_symbol *ds_name; | |||
t_symbol *ds_arraytemplate; /* filled in for arrays only */ | |||
} t_dataslot; | |||
typedef struct _template | |||
{ | |||
t_pd t_pdobj; /* header */ | |||
struct _gtemplate *t_list; /* list of "struct"/gtemplate objects */ | |||
t_symbol *t_sym; /* name */ | |||
int t_n; /* number of dataslots (fields) */ | |||
t_dataslot *t_vec; /* array of dataslots */ | |||
} t_template; | |||
struct _array | |||
{ | |||
int a_n; /* number of elements */ | |||
int a_elemsize; /* size in bytes; LATER get this from template */ | |||
char *a_vec; /* array of elements */ | |||
t_symbol *a_templatesym; /* template for elements */ | |||
int a_valid; /* protection against stale pointers into array */ | |||
t_gpointer a_gp; /* pointer to scalar or array element we're in */ | |||
t_gstub *a_stub; /* stub for pointing into this array */ | |||
}; | |||
/* structure for traversing all the connections in a glist */ | |||
typedef struct _linetraverser | |||
{ | |||
t_canvas *tr_x; | |||
t_object *tr_ob; | |||
int tr_nout; | |||
int tr_outno; | |||
t_object *tr_ob2; | |||
t_outlet *tr_outlet; | |||
t_inlet *tr_inlet; | |||
int tr_nin; | |||
int tr_inno; | |||
int tr_x11, tr_y11, tr_x12, tr_y12; | |||
int tr_x21, tr_y21, tr_x22, tr_y22; | |||
int tr_lx1, tr_ly1, tr_lx2, tr_ly2; | |||
t_outconnect *tr_nextoc; | |||
int tr_nextoutno; | |||
} t_linetraverser; | |||
struct _instancecanvas | |||
{ | |||
struct _instanceeditor *i_editor; | |||
struct _instancetemplate *i_template; | |||
t_symbol *i_newfilename; | |||
t_symbol *i_newdirectory; | |||
int i_newargc; | |||
t_atom *i_newargv; | |||
t_glist *i_reloadingabstraction; | |||
int i_dspstate; | |||
int i_dollarzero; | |||
t_float i_graph_lastxpix, i_graph_lastypix; | |||
}; | |||
void g_editor_newpdinstance( void); | |||
void g_template_newpdinstance( void); | |||
void g_editor_freepdinstance( void); | |||
void g_template_freepdinstance( void); | |||
#define THISGUI (pd_this->pd_gui) | |||
#define EDITOR (pd_this->pd_gui->i_editor) | |||
#define TEMPLATE (pd_this->pd_gui->i_template) | |||
/* function types used to define graphical behavior for gobjs, a bit like X | |||
widgets. We don't use Pd methods because Pd's typechecking can't specify the | |||
types of pointer arguments. Also it's more convenient this way, since | |||
every "patchable" object can just get the "text" behaviors. */ | |||
/* Call this to get a gobj's bounding rectangle in pixels */ | |||
typedef void (*t_getrectfn)(t_gobj *x, struct _glist *glist, | |||
int *x1, int *y1, int *x2, int *y2); | |||
/* and this to displace a gobj: */ | |||
typedef void (*t_displacefn)(t_gobj *x, struct _glist *glist, int dx, int dy); | |||
/* change color to show selection: */ | |||
typedef void (*t_selectfn)(t_gobj *x, struct _glist *glist, int state); | |||
/* change appearance to show activation/deactivation: */ | |||
typedef void (*t_activatefn)(t_gobj *x, struct _glist *glist, int state); | |||
/* warn a gobj it's about to be deleted */ | |||
typedef void (*t_deletefn)(t_gobj *x, struct _glist *glist); | |||
/* making visible or invisible */ | |||
typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag); | |||
/* field a mouse click (when not in "edit" mode) */ | |||
typedef int (*t_clickfn)(t_gobj *x, struct _glist *glist, | |||
int xpix, int ypix, int shift, int alt, int dbl, int doit); | |||
/* ... and later, resizing; getting/setting font or color... */ | |||
struct _widgetbehavior | |||
{ | |||
t_getrectfn w_getrectfn; | |||
t_displacefn w_displacefn; | |||
t_selectfn w_selectfn; | |||
t_activatefn w_activatefn; | |||
t_deletefn w_deletefn; | |||
t_visfn w_visfn; | |||
t_clickfn w_clickfn; | |||
}; | |||
/* -------- behaviors for scalars defined by objects in template --------- */ | |||
/* these are set by "drawing commands" in g_template.c which add appearance to | |||
scalars, which live in some other window. If the scalar is just included | |||
in a canvas the "parent" is a misnomer. There is also a text scalar object | |||
which really does draw the scalar on the parent window; see g_scalar.c. */ | |||
/* note how the click function wants the whole scalar, not the "data", so | |||
doesn't work on array elements... LATER reconsider this */ | |||
/* bounding rectangle: */ | |||
typedef void (*t_parentgetrectfn)(t_gobj *x, struct _glist *glist, | |||
t_word *data, t_template *tmpl, t_float basex, t_float basey, | |||
int *x1, int *y1, int *x2, int *y2); | |||
/* displace it */ | |||
typedef void (*t_parentdisplacefn)(t_gobj *x, struct _glist *glist, | |||
t_word *data, t_template *tmpl, t_float basex, t_float basey, | |||
int dx, int dy); | |||
/* change color to show selection */ | |||
typedef void (*t_parentselectfn)(t_gobj *x, struct _glist *glist, | |||
t_word *data, t_template *tmpl, t_float basex, t_float basey, | |||
int state); | |||
/* change appearance to show activation/deactivation: */ | |||
typedef void (*t_parentactivatefn)(t_gobj *x, struct _glist *glist, | |||
t_word *data, t_template *tmpl, t_float basex, t_float basey, | |||
int state); | |||
/* making visible or invisible */ | |||
typedef void (*t_parentvisfn)(t_gobj *x, struct _glist *glist, | |||
t_word *data, t_template *tmpl, t_float basex, t_float basey, | |||
int flag); | |||
/* field a mouse click */ | |||
typedef int (*t_parentclickfn)(t_gobj *x, struct _glist *glist, | |||
t_word *data, t_template *tmpl, t_scalar *sc, t_array *ap, | |||
t_float basex, t_float basey, | |||
int xpix, int ypix, int shift, int alt, int dbl, int doit); | |||
struct _parentwidgetbehavior | |||
{ | |||
t_parentgetrectfn w_parentgetrectfn; | |||
t_parentdisplacefn w_parentdisplacefn; | |||
t_parentselectfn w_parentselectfn; | |||
t_parentactivatefn w_parentactivatefn; | |||
t_parentvisfn w_parentvisfn; | |||
t_parentclickfn w_parentclickfn; | |||
}; | |||
/* cursor definitions; used as return value for t_parentclickfn */ | |||
#define CURSOR_RUNMODE_NOTHING 0 | |||
#define CURSOR_RUNMODE_CLICKME 1 | |||
#define CURSOR_RUNMODE_THICKEN 2 | |||
#define CURSOR_RUNMODE_ADDPOINT 3 | |||
#define CURSOR_EDITMODE_NOTHING 4 | |||
#define CURSOR_EDITMODE_CONNECT 5 | |||
#define CURSOR_EDITMODE_DISCONNECT 6 | |||
#define CURSOR_EDITMODE_RESIZE 7 | |||
EXTERN void canvas_setcursor(t_glist *x, unsigned int cursornum); | |||
extern t_canvas *canvas_whichfind; /* last canvas we did a find in */ | |||
extern t_class *vinlet_class, *voutlet_class; | |||
extern int glist_valid; /* incremented when pointers might be stale */ | |||
#define PLOTSTYLE_POINTS 0 /* plotting styles for arrays */ | |||
#define PLOTSTYLE_POLY 1 | |||
#define PLOTSTYLE_BEZ 2 | |||
/* ------------------- functions on any gobj ----------------------------- */ | |||
EXTERN void gobj_getrect(t_gobj *x, t_glist *owner, int *x1, int *y1, | |||
int *x2, int *y2); | |||
EXTERN void gobj_displace(t_gobj *x, t_glist *owner, int dx, int dy); | |||
EXTERN void gobj_select(t_gobj *x, t_glist *owner, int state); | |||
EXTERN void gobj_activate(t_gobj *x, t_glist *owner, int state); | |||
EXTERN void gobj_delete(t_gobj *x, t_glist *owner); | |||
EXTERN void gobj_vis(t_gobj *x, t_glist *glist, int flag); | |||
EXTERN int gobj_click(t_gobj *x, struct _glist *glist, | |||
int xpix, int ypix, int shift, int alt, int dbl, int doit); | |||
EXTERN void gobj_save(t_gobj *x, t_binbuf *b); | |||
EXTERN void gobj_properties(t_gobj *x, struct _glist *glist); | |||
EXTERN int gobj_shouldvis(t_gobj *x, struct _glist *glist); | |||
/* -------------------- functions on glists --------------------- */ | |||
EXTERN t_glist *glist_new( void); | |||
EXTERN void glist_init(t_glist *x); | |||
EXTERN void glist_add(t_glist *x, t_gobj *g); | |||
EXTERN void glist_clear(t_glist *x); | |||
EXTERN t_canvas *glist_getcanvas(t_glist *x); | |||
EXTERN int glist_isselected(t_glist *x, t_gobj *y); | |||
EXTERN void glist_select(t_glist *x, t_gobj *y); | |||
EXTERN void glist_deselect(t_glist *x, t_gobj *y); | |||
EXTERN void glist_noselect(t_glist *x); | |||
EXTERN void glist_selectall(t_glist *x); | |||
EXTERN void glist_delete(t_glist *x, t_gobj *y); | |||
EXTERN void glist_retext(t_glist *x, t_text *y); | |||
EXTERN void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn, | |||
t_glistkeyfn keyfn, int xpos, int ypos); | |||
EXTERN int glist_isvisible(t_glist *x); | |||
EXTERN int glist_istoplevel(t_glist *x); | |||
EXTERN t_glist *glist_findgraph(t_glist *x); | |||
EXTERN int glist_getfont(t_glist *x); | |||
EXTERN int glist_fontwidth(t_glist *x); | |||
EXTERN int glist_fontheight(t_glist *x); | |||
EXTERN int glist_getzoom(t_glist *x); | |||
EXTERN void glist_sort(t_glist *canvas); | |||
EXTERN void glist_read(t_glist *x, t_symbol *filename, t_symbol *format); | |||
EXTERN void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format); | |||
EXTERN t_float glist_pixelstox(t_glist *x, t_float xpix); | |||
EXTERN t_float glist_pixelstoy(t_glist *x, t_float ypix); | |||
EXTERN t_float glist_xtopixels(t_glist *x, t_float xval); | |||
EXTERN t_float glist_ytopixels(t_glist *x, t_float yval); | |||
EXTERN t_float glist_dpixtodx(t_glist *x, t_float dxpix); | |||
EXTERN t_float glist_dpixtody(t_glist *x, t_float dypix); | |||
EXTERN void glist_getnextxy(t_glist *gl, int *xval, int *yval); | |||
EXTERN void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv); | |||
EXTERN t_glist *glist_addglist(t_glist *g, t_symbol *sym, | |||
t_float x1, t_float y1, t_float x2, t_float y2, | |||
t_float px1, t_float py1, t_float px2, t_float py2); | |||
EXTERN void glist_arraydialog(t_glist *parent, t_symbol *name, | |||
t_floatarg size, t_floatarg saveit, t_floatarg newgraph); | |||
EXTERN t_binbuf *glist_writetobinbuf(t_glist *x, int wholething); | |||
EXTERN int glist_isgraph(t_glist *x); | |||
EXTERN void glist_redraw(t_glist *x); | |||
EXTERN void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime, | |||
char *tag, int x1, int y1, int x2, int y2); | |||
EXTERN void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag); | |||
EXTERN void canvas_create_editor(t_glist *x); | |||
EXTERN void canvas_destroy_editor(t_glist *x); | |||
void canvas_deletelinesforio(t_canvas *x, t_text *text, | |||
t_inlet *inp, t_outlet *outp); | |||
extern int glist_amreloadingabstractions; /* stop GUI changes while reloading */ | |||
/* -------------------- functions on texts ------------------------- */ | |||
EXTERN void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize); | |||
EXTERN void text_drawborder(t_text *x, t_glist *glist, char *tag, | |||
int width, int height, int firsttime); | |||
EXTERN void text_eraseborder(t_text *x, t_glist *glist, char *tag); | |||
EXTERN int text_xpix(t_text *x, t_glist *glist); | |||
EXTERN int text_ypix(t_text *x, t_glist *glist); | |||
extern const t_widgetbehavior text_widgetbehavior; | |||
/* -------------------- functions on rtexts ------------------------- */ | |||
#define RTEXT_DOWN 1 | |||
#define RTEXT_DRAG 2 | |||
#define RTEXT_DBL 3 | |||
#define RTEXT_SHIFT 4 | |||
EXTERN t_rtext *rtext_new(t_glist *glist, t_text *who); | |||
EXTERN t_rtext *glist_findrtext(t_glist *gl, t_text *who); | |||
EXTERN void rtext_draw(t_rtext *x); | |||
EXTERN void rtext_erase(t_rtext *x); | |||
EXTERN t_rtext *rtext_remove(t_rtext *first, t_rtext *x); | |||
EXTERN int rtext_height(t_rtext *x); | |||
EXTERN void rtext_displace(t_rtext *x, int dx, int dy); | |||
EXTERN void rtext_select(t_rtext *x, int state); | |||
EXTERN void rtext_activate(t_rtext *x, int state); | |||
EXTERN void rtext_free(t_rtext *x); | |||
EXTERN void rtext_key(t_rtext *x, int n, t_symbol *s); | |||
EXTERN void rtext_mouse(t_rtext *x, int xval, int yval, int flag); | |||
EXTERN void rtext_retext(t_rtext *x); | |||
EXTERN int rtext_width(t_rtext *x); | |||
EXTERN char *rtext_gettag(t_rtext *x); | |||
EXTERN void rtext_gettext(t_rtext *x, char **buf, int *bufsize); | |||
EXTERN void rtext_getseltext(t_rtext *x, char **buf, int *bufsize); | |||
/* -------------------- functions on canvases ------------------------ */ | |||
EXTERN t_class *canvas_class; | |||
EXTERN t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv); | |||
EXTERN t_symbol *canvas_makebindsym(t_symbol *s); | |||
EXTERN void canvas_vistext(t_canvas *x, t_text *y); | |||
EXTERN void canvas_fixlinesfor(t_canvas *x, t_text *text); | |||
EXTERN void canvas_deletelinesfor(t_canvas *x, t_text *text); | |||
EXTERN void canvas_stowconnections(t_canvas *x); | |||
EXTERN void canvas_restoreconnections(t_canvas *x); | |||
EXTERN void canvas_redraw(t_canvas *x); | |||
EXTERN void canvas_closebang(t_canvas *x); | |||
EXTERN void canvas_initbang(t_canvas *x); | |||
EXTERN t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *sym); | |||
EXTERN void canvas_rminlet(t_canvas *x, t_inlet *ip); | |||
EXTERN t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *sym); | |||
EXTERN void canvas_rmoutlet(t_canvas *x, t_outlet *op); | |||
EXTERN void canvas_redrawallfortemplate(t_template *tmpl, int action); | |||
EXTERN void canvas_redrawallfortemplatecanvas(t_canvas *x, int action); | |||
EXTERN void canvas_zapallfortemplate(t_canvas *tmpl); | |||
EXTERN void canvas_setusedastemplate(t_canvas *x); | |||
EXTERN void canvas_setcurrent(t_canvas *x); | |||
EXTERN void canvas_unsetcurrent(t_canvas *x); | |||
EXTERN t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s); | |||
EXTERN t_canvas *canvas_getrootfor(t_canvas *x); | |||
EXTERN void canvas_dirty(t_canvas *x, t_floatarg n); | |||
EXTERN int canvas_getfont(t_canvas *x); | |||
typedef int (*t_canvasapply)(t_canvas *x, t_int x1, t_int x2, t_int x3); | |||
EXTERN t_int *canvas_recurapply(t_canvas *x, t_canvasapply *fn, | |||
t_int x1, t_int x2, t_int x3); | |||
EXTERN void canvas_resortinlets(t_canvas *x); | |||
EXTERN void canvas_resortoutlets(t_canvas *x); | |||
EXTERN void canvas_free(t_canvas *x); | |||
EXTERN void canvas_updatewindowlist( void); | |||
EXTERN void canvas_editmode(t_canvas *x, t_floatarg state); | |||
EXTERN int canvas_isabstraction(t_canvas *x); | |||
EXTERN int canvas_istable(t_canvas *x); | |||
EXTERN int canvas_showtext(t_canvas *x); | |||
EXTERN void canvas_vis(t_canvas *x, t_floatarg f); | |||
EXTERN t_canvasenvironment *canvas_getenv(t_canvas *x); | |||
EXTERN void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir); | |||
EXTERN void canvas_loadbang(t_canvas *x); | |||
EXTERN int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos, | |||
int *x1p, int *y1p, int *x2p, int *y2p); | |||
EXTERN int canvas_setdeleting(t_canvas *x, int flag); | |||
#define LB_LOAD 0 /* "loadbang" actions - 0 for original meaning */ | |||
#define LB_INIT 1 /* loaded but not yet connected to parent patch */ | |||
#define LB_CLOSE 2 /* about to close */ | |||
/* Pointer to canvas that was saved necessitating a reload of abstractions | |||
of that name. We use as a flag to stop canvases from being marked "dirty" | |||
if we have to touch them to reload; also suppress window list update. | |||
"clone~" uses this to identify which copy NOT to reload */ | |||
EXTERN t_glist *glist_reloadingabstraction; | |||
typedef void (*t_undofn)(t_canvas *canvas, void *buf, | |||
int action); /* a function that does UNDO/REDO */ | |||
#define UNDO_FREE 0 /* free current undo/redo buffer */ | |||
#define UNDO_UNDO 1 /* undo */ | |||
#define UNDO_REDO 2 /* redo */ | |||
EXTERN void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf, | |||
const char *name); | |||
EXTERN void canvas_noundo(t_canvas *x); | |||
EXTERN int canvas_getindex(t_canvas *x, t_gobj *y); | |||
EXTERN void canvas_connect(t_canvas *x, | |||
t_floatarg fwhoout, t_floatarg foutno,t_floatarg fwhoin, t_floatarg finno); | |||
EXTERN void canvas_disconnect(t_canvas *x, | |||
t_float index1, t_float outno, t_float index2, t_float inno); | |||
EXTERN int canvas_isconnected (t_canvas *x, | |||
t_text *ob1, int n1, t_text *ob2, int n2); | |||
EXTERN void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy); | |||
EXTERN t_glist *pd_checkglist(t_pd *x); | |||
typedef int (*t_canvas_path_iterator)(const char *path, void *user_data); | |||
EXTERN int canvas_path_iterate(t_canvas *x, t_canvas_path_iterator fun, | |||
void *user_data); | |||
/* ---- functions on canvasses as objects --------------------- */ | |||
EXTERN void canvas_fattenforscalars(t_canvas *x, | |||
int *x1, int *y1, int *x2, int *y2); | |||
EXTERN void canvas_visforscalars(t_canvas *x, t_glist *glist, int vis); | |||
EXTERN int canvas_clicksub(t_canvas *x, int xpix, int ypix, int shift, | |||
int alt, int dbl, int doit); | |||
EXTERN t_glist *canvas_getglistonsuper(void); | |||
EXTERN void linetraverser_start(t_linetraverser *t, t_canvas *x); | |||
EXTERN t_outconnect *linetraverser_next(t_linetraverser *t); | |||
EXTERN void linetraverser_skipobject(t_linetraverser *t); | |||
/* --------- functions on garrays (graphical arrays) -------------------- */ | |||
EXTERN t_template *garray_template(t_garray *x); | |||
/* -------------------- arrays --------------------- */ | |||
EXTERN t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *tmpl, | |||
t_floatarg f, t_floatarg saveit); | |||
EXTERN t_array *array_new(t_symbol *templatesym, t_gpointer *parent); | |||
EXTERN void array_resize(t_array *x, int n); | |||
EXTERN void array_free(t_array *x); | |||
EXTERN void array_redraw(t_array *a, t_glist *glist); | |||
EXTERN void array_resize_and_redraw(t_array *array, t_glist *glist, int n); | |||
/* --------------------- gpointers and stubs ---------------- */ | |||
EXTERN t_gstub *gstub_new(t_glist *gl, t_array *a); | |||
EXTERN void gstub_cutoff(t_gstub *gs); | |||
EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x); | |||
EXTERN void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w); | |||
/* --------------------- scalars ------------------------- */ | |||
EXTERN void word_init(t_word *wp, t_template *tmpl, t_gpointer *gp); | |||
EXTERN void word_restore(t_word *wp, t_template *tmpl, | |||
int argc, t_atom *argv); | |||
EXTERN t_scalar *scalar_new(t_glist *owner, | |||
t_symbol *templatesym); | |||
EXTERN void word_free(t_word *wp, t_template *tmpl); | |||
EXTERN void scalar_getbasexy(t_scalar *x, t_float *basex, t_float *basey); | |||
EXTERN void scalar_redraw(t_scalar *x, t_glist *glist); | |||
EXTERN void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, | |||
int amarrayelement); | |||
EXTERN int canvas_readscalar(t_glist *x, int natoms, t_atom *vec, | |||
int *p_nextmsg, int selectit); | |||
/* ------helper routines for "garrays" and "plots" -------------- */ | |||
EXTERN void array_getcoordinate(t_glist *glist, | |||
char *elem, int xonset, int yonset, int wonset, int indx, | |||
t_float basex, t_float basey, t_float xinc, | |||
t_fielddesc *xfielddesc, t_fielddesc *yfielddesc, t_fielddesc *wfielddesc, | |||
t_float *xp, t_float *yp, t_float *wp); | |||
EXTERN int array_getfields(t_symbol *elemtemplatesym, | |||
t_canvas **elemtemplatecanvasp, | |||
t_template **elemtemplatep, int *elemsizep, | |||
t_fielddesc *xfielddesc, t_fielddesc *yfielddesc, t_fielddesc *wfielddesc, | |||
int *xonsetp, int *yonsetp, int *wonsetp); | |||
/* --------------------- templates ------------------------- */ | |||
EXTERN t_template *template_new(t_symbol *sym, int argc, t_atom *argv); | |||
EXTERN void template_free(t_template *x); | |||
EXTERN int template_match(t_template *x1, t_template *x2); | |||
EXTERN int template_find_field(t_template *x, t_symbol *name, int *p_onset, | |||
int *p_type, t_symbol **p_arraytype); | |||
EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp, | |||
int loud); | |||
EXTERN void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp, | |||
t_float f, int loud); | |||
EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, | |||
t_word *wp, int loud); | |||
EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname, | |||
t_word *wp, t_symbol *s, int loud); | |||
EXTERN t_template *gtemplate_get(t_gtemplate *x); | |||
EXTERN t_template *template_findbyname(t_symbol *s); | |||
EXTERN t_canvas *template_findcanvas(t_template *tmpl); | |||
EXTERN void template_notify(t_template *tmpl, | |||
t_symbol *s, int argc, t_atom *argv); | |||
EXTERN t_float fielddesc_getcoord(t_fielddesc *f, t_template *tmpl, | |||
t_word *wp, int loud); | |||
EXTERN void fielddesc_setcoord(t_fielddesc *f, t_template *tmpl, | |||
t_word *wp, t_float pix, int loud); | |||
EXTERN t_float fielddesc_cvttocoord(t_fielddesc *f, t_float val); | |||
EXTERN t_float fielddesc_cvtfromcoord(t_fielddesc *f, t_float coord); | |||
/* ----------------------- guiconnects, g_guiconnect.c --------- */ | |||
EXTERN t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym); | |||
EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay); | |||
/* ------------- IEMGUI routines used in other g_ files ---------------- */ | |||
EXTERN t_symbol *iemgui_raute2dollar(t_symbol *s); | |||
EXTERN t_symbol *iemgui_dollar2raute(t_symbol *s); | |||
/*------------- g_clone.c ------------- */ | |||
extern t_class *clone_class; | |||
#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) | |||
} | |||
#endif | |||
#endif // G_CANVAS_H |
@@ -0,0 +1,464 @@ | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "m_imp.h" | |||
#include <string.h> | |||
/* ---------- clone - maintain copies of a patch ----------------- */ | |||
/* OOPS - have to add outlet vector to each copy to disambiguate */ | |||
/* next: feed each instance its serial number */ | |||
/* next next: DSP method */ | |||
#ifdef _WIN32 | |||
# include <malloc.h> /* MSVC or mingw on windows */ | |||
#elif defined(__linux__) || defined(__APPLE__) | |||
# include <alloca.h> /* linux, mac, mingw, cygwin */ | |||
#else | |||
# include <stdlib.h> /* BSDs for example */ | |||
#endif | |||
#define LIST_NGETBYTE 100 /* bigger that this we use alloc, not alloca */ | |||
#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)((n) < LIST_NGETBYTE ? \ | |||
alloca((n) * sizeof(t_atom)) : getbytes((n) * sizeof(t_atom)))) | |||
#define ATOMS_FREEA(x, n) ( \ | |||
((n) < LIST_NGETBYTE || (freebytes((x), (n) * sizeof(t_atom)), 0))) | |||
t_class *clone_class; | |||
static t_class *clone_in_class, *clone_out_class; | |||
typedef struct _copy | |||
{ | |||
t_glist *c_gl; | |||
int c_on; /* DSP running */ | |||
} t_copy; | |||
typedef struct _in | |||
{ | |||
t_class *i_pd; | |||
struct _clone *i_owner; | |||
int i_signal; | |||
int i_n; | |||
} t_in; | |||
typedef struct _out | |||
{ | |||
t_class *o_pd; | |||
t_outlet *o_outlet; | |||
int o_signal; | |||
int o_n; | |||
} t_out; | |||
typedef struct _clone | |||
{ | |||
t_object x_obj; | |||
int x_n; /* number of copies */ | |||
t_copy *x_vec; /* the copies */ | |||
int x_nin; | |||
t_in *x_invec; | |||
int x_nout; | |||
t_out **x_outvec; | |||
t_symbol *x_s; /* name of abstraction */ | |||
int x_argc; /* creation arguments for abstractions */ | |||
t_atom *x_argv; | |||
int x_phase; | |||
int x_startvoice; /* number of first voice, 0 by default */ | |||
int x_suppressvoice; /* suppress voice number as $1 arg */ | |||
} t_clone; | |||
int clone_match(t_pd *z, t_symbol *name, t_symbol *dir) | |||
{ | |||
t_clone *x = (t_clone *)z; | |||
if (!x->x_n) | |||
return (0); | |||
return (x->x_vec[0].c_gl->gl_name == name && | |||
canvas_getdir(x->x_vec[0].c_gl) == dir); | |||
} | |||
void obj_sendinlet(t_object *x, int n, t_symbol *s, int argc, t_atom *argv); | |||
static void clone_in_list(t_in *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
int n; | |||
if (argc < 1 || argv[0].a_type != A_FLOAT) | |||
pd_error(x->i_owner, "clone: no instance number in message"); | |||
else if ((n = argv[0].a_w.w_float - x->i_owner->x_startvoice) < 0 || | |||
n >= x->i_owner->x_n) | |||
pd_error(x->i_owner, "clone: instance number %d out of range", | |||
n + x->i_owner->x_startvoice); | |||
else if (argc > 1 && argv[1].a_type == A_SYMBOL) | |||
obj_sendinlet(&x->i_owner->x_vec[n].c_gl->gl_obj, x->i_n, | |||
argv[1].a_w.w_symbol, argc-2, argv+2); | |||
else obj_sendinlet(&x->i_owner->x_vec[n].c_gl->gl_obj, x->i_n, | |||
&s_list, argc-1, argv+1); | |||
} | |||
static void clone_in_this(t_in *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
int phase = x->i_owner->x_phase; | |||
if (phase < 0 || phase >= x->i_owner->x_n) | |||
phase = 0; | |||
if (argc <= 0) | |||
return; | |||
else if (argv->a_type == A_SYMBOL) | |||
obj_sendinlet(&x->i_owner->x_vec[phase].c_gl->gl_obj, x->i_n, | |||
argv[0].a_w.w_symbol, argc-1, argv+1); | |||
else obj_sendinlet(&x->i_owner->x_vec[phase].c_gl->gl_obj, x->i_n, | |||
&s_list, argc, argv); | |||
} | |||
static void clone_in_next(t_in *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
int phase = x->i_owner->x_phase + 1; | |||
if (phase < 0 || phase >= x->i_owner->x_n) | |||
phase = 0; | |||
x->i_owner->x_phase = phase; | |||
clone_in_this(x, s, argc, argv); | |||
} | |||
static void clone_in_set(t_in *x, t_floatarg f) | |||
{ | |||
int phase = f; | |||
if (phase < 0 || phase >= x->i_owner->x_n) | |||
phase = 0; | |||
x->i_owner->x_phase = phase; | |||
} | |||
static void clone_in_all(t_in *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
int phasewas = x->i_owner->x_phase, i; | |||
for (i = 0; i < x->i_owner->x_n; i++) | |||
{ | |||
x->i_owner->x_phase = i; | |||
clone_in_this(x, s, argc, argv); | |||
} | |||
x->i_owner->x_phase = phasewas; | |||
} | |||
static void clone_in_vis(t_in *x, t_floatarg fn, t_floatarg vis) | |||
{ | |||
int n = fn - x->i_owner->x_startvoice; | |||
if (n < 0) | |||
n = 0; | |||
else if (n >= x->i_owner->x_n) | |||
n = x->i_owner->x_n - 1; | |||
canvas_vis(x->i_owner->x_vec[n].c_gl, (vis != 0)); | |||
} | |||
static void clone_out_anything(t_out *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_atom *outv, *ap; | |||
int first = | |||
1 + (s != &s_list && s != &s_float && s != &s_symbol && s != &s_bang), | |||
outc = argc + first; | |||
ATOMS_ALLOCA(outv, outc); | |||
SETFLOAT(outv, x->o_n); | |||
if (first == 2) | |||
SETSYMBOL(outv + 1, s); | |||
memcpy(outv+first, argv, sizeof(t_atom) * argc); | |||
outlet_list(x->o_outlet, 0, outc, outv); | |||
ATOMS_FREEA(outv, outc); | |||
} | |||
static void clone_free(t_clone *x) | |||
{ | |||
if (x->x_vec) | |||
{ | |||
int i; | |||
for (i = 0; i < x->x_n; i++) | |||
{ | |||
canvas_closebang(x->x_vec[i].c_gl); | |||
pd_free(&x->x_vec[i].c_gl->gl_pd); | |||
t_freebytes(x->x_outvec[i], | |||
x->x_nout * sizeof(*x->x_outvec[i])); | |||
} | |||
t_freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec)); | |||
t_freebytes(x->x_argv, x->x_argc * sizeof(*x->x_argv)); | |||
t_freebytes(x->x_invec, x->x_nin * sizeof(*x->x_invec)); | |||
t_freebytes(x->x_outvec, x->x_n * sizeof(*x->x_outvec)); | |||
} | |||
} | |||
static t_canvas *clone_makeone(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_canvas *retval; | |||
pd_this->pd_newest = 0; | |||
typedmess(&pd_objectmaker, s, argc, argv); | |||
if (pd_this->pd_newest == 0) | |||
{ | |||
error("clone: can't create subpatch '%s'", | |||
s->s_name); | |||
return (0); | |||
} | |||
if (*pd_this->pd_newest != canvas_class) | |||
{ | |||
error("clone: can't clone '%s' because it's not an abstraction", | |||
s->s_name); | |||
pd_free(pd_this->pd_newest); | |||
pd_this->pd_newest = 0; | |||
return (0); | |||
} | |||
retval = (t_canvas *)pd_this->pd_newest; | |||
pd_this->pd_newest = 0; | |||
retval->gl_owner = 0; | |||
retval->gl_isclone = 1; | |||
return (retval); | |||
} | |||
void clone_setn(t_clone *x, t_floatarg f) | |||
{ | |||
int dspstate = canvas_suspend_dsp(); | |||
int nwas = x->x_n, wantn = f, i, j; | |||
if (wantn < 1) | |||
{ | |||
pd_error(x, "can't resize to zero or negative number; setting to 1"); | |||
wantn = 1; | |||
} | |||
if (wantn > nwas) | |||
for (i = nwas; i < wantn; i++) | |||
{ | |||
t_canvas *c; | |||
t_out *outvec; | |||
SETFLOAT(x->x_argv, x->x_startvoice + i); | |||
if (!(c = clone_makeone(x->x_s, x->x_argc - x->x_suppressvoice, | |||
x->x_argv + x->x_suppressvoice))) | |||
{ | |||
pd_error(x, "clone: couldn't create '%s'", x->x_s->s_name); | |||
goto done; | |||
} | |||
x->x_vec = (t_copy *)t_resizebytes(x->x_vec, i * sizeof(t_copy), | |||
(i+1) * sizeof(t_copy)); | |||
x->x_vec[i].c_gl = c; | |||
x->x_vec[i].c_on = 0; | |||
x->x_outvec = (t_out **)t_resizebytes(x->x_outvec, | |||
i * sizeof(*x->x_outvec), (i+1) * sizeof(*x->x_outvec)); | |||
x->x_outvec[i] = outvec = | |||
(t_out *)getbytes(x->x_nout * sizeof(*outvec)); | |||
for (j = 0; j < x->x_nout; j++) | |||
{ | |||
outvec[j].o_pd = clone_out_class; | |||
outvec[j].o_signal = | |||
obj_issignaloutlet(&x->x_vec[0].c_gl->gl_obj, i); | |||
outvec[j].o_n = x->x_startvoice + i; | |||
outvec[j].o_outlet = | |||
x->x_outvec[0][j].o_outlet; | |||
obj_connect(&x->x_vec[i].c_gl->gl_obj, j, | |||
(t_object *)(&outvec[j]), 0); | |||
} | |||
x->x_n++; | |||
} | |||
if (wantn < nwas) | |||
{ | |||
for (i = wantn; i < nwas; i++) | |||
{ | |||
canvas_closebang(x->x_vec[i].c_gl); | |||
pd_free(&x->x_vec[i].c_gl->gl_pd); | |||
} | |||
x->x_vec = (t_copy *)t_resizebytes(x->x_vec, nwas * sizeof(t_copy), | |||
wantn * sizeof(*x->x_vec)); | |||
x->x_n = wantn; | |||
} | |||
done: | |||
canvas_resume_dsp(dspstate); | |||
} | |||
static void clone_click(t_clone *x, t_floatarg xpos, t_floatarg ypos, | |||
t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | |||
{ | |||
if (!x->x_n) | |||
return; | |||
canvas_vis(x->x_vec[0].c_gl, 1); | |||
} | |||
static void clone_loadbang(t_clone *x, t_floatarg f) | |||
{ | |||
int i; | |||
if (f == LB_LOAD) | |||
for (i = 0; i < x->x_n; i++) | |||
canvas_loadbang(x->x_vec[i].c_gl); | |||
else if (f == LB_CLOSE) | |||
for (i = 0; i < x->x_n; i++) | |||
canvas_closebang(x->x_vec[i].c_gl); | |||
} | |||
void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp); | |||
t_signal *signal_newfromcontext(int borrowed); | |||
void signal_makereusable(t_signal *sig); | |||
static void clone_dsp(t_clone *x, t_signal **sp) | |||
{ | |||
int i, j, nin, nout; | |||
t_signal **tempsigs; | |||
if (!x->x_n) | |||
return; | |||
for (i = nin = 0; i < x->x_nin; i++) | |||
if (x->x_invec[i].i_signal) | |||
nin++; | |||
for (i = nout = 0; i < x->x_nout; i++) | |||
if (x->x_outvec[0][i].o_signal) | |||
nout++; | |||
for (j = 0; j < x->x_n; j++) | |||
{ | |||
if (obj_ninlets(&x->x_vec[j].c_gl->gl_obj) != x->x_nin || | |||
obj_noutlets(&x->x_vec[j].c_gl->gl_obj) != x->x_nout || | |||
obj_nsiginlets(&x->x_vec[j].c_gl->gl_obj) != nin || | |||
obj_nsigoutlets(&x->x_vec[j].c_gl->gl_obj) != nout) | |||
{ | |||
pd_error(x, "clone: can't do DSP until edited copy is saved"); | |||
for (i = 0; i < nout; i++) | |||
dsp_add_zero(sp[nin+i]->s_vec, sp[nin+i]->s_n); | |||
return; | |||
} | |||
} | |||
tempsigs = (t_signal **)alloca((nin + 3 * nout) * sizeof(*tempsigs)); | |||
/* load input signals into signal vector to send subpatches */ | |||
for (i = 0; i < nin; i++) | |||
{ | |||
/* we already have one reference "counted" for our presumed | |||
use of this input signal but we must add the others. */ | |||
sp[i]->s_refcount += x->x_n-1; | |||
tempsigs[2 * nout + i] = sp[i]; | |||
} | |||
/* for first copy, write output to first nout temp sigs */ | |||
for (i = 0; i < nout; i++) | |||
tempsigs[i] = tempsigs[2 * nout + nin + i] = signal_newfromcontext(1); | |||
canvas_dodsp(x->x_vec[0].c_gl, 0, tempsigs + 2*nout); | |||
/* for remaining copies, write to second nout temp sigs */ | |||
for (j = 1; j < x->x_n; j++) | |||
{ | |||
for (i = 0; i < nout; i++) | |||
tempsigs[nout+i] = tempsigs[2 * nout + nin + i] = | |||
signal_newfromcontext(1); | |||
canvas_dodsp(x->x_vec[j].c_gl, 0, tempsigs + 2*nout); | |||
for (i = 0; i < nout; i++) | |||
{ | |||
dsp_add_plus(tempsigs[nout + i]->s_vec, tempsigs[i]->s_vec, | |||
tempsigs[i]->s_vec, tempsigs[i]->s_n); | |||
signal_makereusable(tempsigs[nout + i]); | |||
} | |||
} | |||
/* copy to output signsls */ | |||
for (i = 0; i < nout; i++) | |||
{ | |||
dsp_add_copy(tempsigs[i]->s_vec, sp[nin+i]->s_vec, tempsigs[i]->s_n); | |||
signal_makereusable(tempsigs[i]); | |||
} | |||
} | |||
static void *clone_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_clone *x = (t_clone *)pd_new(clone_class); | |||
t_canvas *c; | |||
int wantn, dspstate, i; | |||
t_out *outvec; | |||
x->x_invec = 0; | |||
x->x_outvec = 0; | |||
x->x_startvoice = 0; | |||
x->x_suppressvoice = 0; | |||
if (argc == 0) | |||
{ | |||
x->x_vec = 0; | |||
x->x_n = 0; | |||
return (x); | |||
} | |||
dspstate = canvas_suspend_dsp(); | |||
while (argc > 0 && argv[0].a_type == A_SYMBOL && | |||
argv[0].a_w.w_symbol->s_name[0] == '-') | |||
{ | |||
if (!strcmp(argv[0].a_w.w_symbol->s_name, "-s") && argc > 1 && | |||
argv[1].a_type == A_FLOAT) | |||
{ | |||
x->x_startvoice = argv[1].a_w.w_float; | |||
argc -= 2; argv += 2; | |||
} | |||
else if (!strcmp(argv[0].a_w.w_symbol->s_name, "-x")) | |||
x->x_suppressvoice = 1, argc--, argv++; | |||
else goto usage; | |||
} | |||
if (argc >= 2 && (wantn = atom_getfloatarg(0, argc, argv)) >= 0 | |||
&& argv[1].a_type == A_SYMBOL) | |||
x->x_s = argv[1].a_w.w_symbol; | |||
else if (argc >= 2 && (wantn = atom_getfloatarg(1, argc, argv)) >= 0 | |||
&& argv[0].a_type == A_SYMBOL) | |||
x->x_s = argv[0].a_w.w_symbol; | |||
else goto usage; | |||
/* store a copy of the argmuents with an extra space (argc+1) for | |||
supplying an instance number, which we'll bash as we go. */ | |||
x->x_argc = argc - 1; | |||
x->x_argv = getbytes(x->x_argc * sizeof(*x->x_argv)); | |||
memcpy(x->x_argv, argv+1, x->x_argc * sizeof(*x->x_argv)); | |||
SETFLOAT(x->x_argv, x->x_startvoice); | |||
if (!(c = clone_makeone(x->x_s, x->x_argc - x->x_suppressvoice, | |||
x->x_argv + x->x_suppressvoice))) | |||
goto fail; | |||
x->x_vec = (t_copy *)getbytes(sizeof(*x->x_vec)); | |||
x->x_vec[0].c_gl = c; | |||
x->x_n = 1; | |||
x->x_nin = obj_ninlets(&x->x_vec[0].c_gl->gl_obj); | |||
x->x_invec = (t_in *)getbytes(x->x_nin * sizeof(*x->x_invec)); | |||
for (i = 0; i < x->x_nin; i++) | |||
{ | |||
x->x_invec[i].i_pd = clone_in_class; | |||
x->x_invec[i].i_owner = x; | |||
x->x_invec[i].i_signal = | |||
obj_issignalinlet(&x->x_vec[0].c_gl->gl_obj, i); | |||
x->x_invec[i].i_n = i; | |||
if (x->x_invec[i].i_signal) | |||
signalinlet_new(&x->x_obj, 0); | |||
else inlet_new(&x->x_obj, &x->x_invec[i].i_pd, 0, 0); | |||
} | |||
x->x_nout = obj_noutlets(&x->x_vec[0].c_gl->gl_obj); | |||
x->x_outvec = (t_out **)getbytes(sizeof(*x->x_outvec)); | |||
x->x_outvec[0] = outvec = | |||
(t_out *)getbytes(x->x_nout * sizeof(*outvec)); | |||
for (i = 0; i < x->x_nout; i++) | |||
{ | |||
outvec[i].o_pd = clone_out_class; | |||
outvec[i].o_signal = | |||
obj_issignaloutlet(&x->x_vec[0].c_gl->gl_obj, i); | |||
outvec[i].o_n = x->x_startvoice; | |||
outvec[i].o_outlet = | |||
outlet_new(&x->x_obj, (outvec[i].o_signal ? &s_signal : 0)); | |||
obj_connect(&x->x_vec[0].c_gl->gl_obj, i, | |||
(t_object *)(&outvec[i]), 0); | |||
} | |||
clone_setn(x, (t_floatarg)(wantn)); | |||
x->x_phase = wantn-1; | |||
canvas_resume_dsp(dspstate); | |||
return (x); | |||
usage: | |||
error("usage: clone [-s starting-number] <number> <name> [arguments]"); | |||
fail: | |||
freebytes(x, sizeof(t_clone)); | |||
canvas_resume_dsp(dspstate); | |||
return (0); | |||
} | |||
void clone_setup(void) | |||
{ | |||
clone_class = class_new(gensym("clone"), (t_newmethod)clone_new, | |||
(t_method)clone_free, sizeof(t_clone), CLASS_NOINLET, A_GIMME, 0); | |||
class_addmethod(clone_class, (t_method)clone_click, gensym("click"), | |||
A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(clone_class, (t_method)clone_loadbang, gensym("loadbang"), | |||
A_FLOAT, 0); | |||
class_addmethod(clone_class, (t_method)clone_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
clone_in_class = class_new(gensym("clone-inlet"), 0, 0, | |||
sizeof(t_in), CLASS_PD, 0); | |||
class_addmethod(clone_in_class, (t_method)clone_in_next, gensym("next"), | |||
A_GIMME, 0); | |||
class_addmethod(clone_in_class, (t_method)clone_in_this, gensym("this"), | |||
A_GIMME, 0); | |||
class_addmethod(clone_in_class, (t_method)clone_in_set, gensym("set"), | |||
A_FLOAT, 0); | |||
class_addmethod(clone_in_class, (t_method)clone_in_all, gensym("all"), | |||
A_GIMME, 0); | |||
class_addmethod(clone_in_class, (t_method)clone_in_vis, gensym("vis"), | |||
A_FLOAT, A_FLOAT, 0); | |||
class_addlist(clone_in_class, (t_method)clone_in_list); | |||
clone_out_class = class_new(gensym("clone-outlet"), 0, 0, | |||
sizeof(t_in), CLASS_PD, 0); | |||
class_addanything(clone_out_class, (t_method)clone_out_anything); | |||
} |
@@ -0,0 +1,97 @@ | |||
/* Copyright (c) 1997-2000 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* a thing to forward messages from the GUI, dealing with race conditions | |||
in which the "target" gets deleted while the GUI is sending it something. | |||
See also the gfxstub object that doesn't oblige the owner to keep a pointer | |||
around (so is better suited to one-off dialogs) | |||
*/ | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
struct _guiconnect | |||
{ | |||
t_object x_obj; | |||
t_pd *x_who; | |||
t_symbol *x_sym; | |||
t_clock *x_clock; | |||
}; | |||
static t_class *guiconnect_class; | |||
t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym) | |||
{ | |||
t_guiconnect *x = (t_guiconnect *)pd_new(guiconnect_class); | |||
x->x_who = who; | |||
x->x_sym = sym; | |||
pd_bind(&x->x_obj.ob_pd, sym); | |||
return (x); | |||
} | |||
/* cleanup routine; delete any resources we have */ | |||
static void guiconnect_free(t_guiconnect *x) | |||
{ | |||
if (x->x_sym) | |||
pd_unbind(&x->x_obj.ob_pd, x->x_sym); | |||
if (x->x_clock) | |||
clock_free(x->x_clock); | |||
} | |||
/* this is called when the clock times out to indicate the GUI should | |||
be gone by now. */ | |||
static void guiconnect_tick(t_guiconnect *x) | |||
{ | |||
pd_free(&x->x_obj.ob_pd); | |||
} | |||
/* the target calls this to disconnect. If the gui has "signed off" | |||
we're ready to delete the object; otherwise we wait either for signoff | |||
or for a timeout. */ | |||
void guiconnect_notarget(t_guiconnect *x, double timedelay) | |||
{ | |||
if (!x->x_sym) | |||
pd_free(&x->x_obj.ob_pd); | |||
else | |||
{ | |||
x->x_who = 0; | |||
if (timedelay > 0) | |||
{ | |||
x->x_clock = clock_new(x, (t_method)guiconnect_tick); | |||
clock_delay(x->x_clock, timedelay); | |||
} | |||
} | |||
} | |||
/* the GUI calls this to send messages to the target. */ | |||
static void guiconnect_anything(t_guiconnect *x, | |||
t_symbol *s, int ac, t_atom *av) | |||
{ | |||
if (x->x_who) | |||
typedmess(x->x_who, s, ac, av); | |||
} | |||
/* the GUI calls this when it disappears. (If there's any chance the | |||
GUI will fail to do this, the "target", when it signs off, should specify | |||
a timeout after which the guiconnect will disappear.) */ | |||
static void guiconnect_signoff(t_guiconnect *x) | |||
{ | |||
if (!x->x_who) | |||
pd_free(&x->x_obj.ob_pd); | |||
else | |||
{ | |||
pd_unbind(&x->x_obj.ob_pd, x->x_sym); | |||
x->x_sym = 0; | |||
} | |||
} | |||
void g_guiconnect_setup(void) | |||
{ | |||
guiconnect_class = class_new(gensym("guiconnect"), 0, | |||
(t_method)guiconnect_free, sizeof(t_guiconnect), CLASS_PD, 0); | |||
class_addanything(guiconnect_class, guiconnect_anything); | |||
class_addmethod(guiconnect_class, (t_method)guiconnect_signoff, | |||
gensym("signoff"), 0); | |||
} |
@@ -0,0 +1,775 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */ | |||
/* name change to hradio by MSP and changed to | |||
put out a "float" as in sliders, toggles, etc. */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
/* ------------- hdl gui-horizontal dial ---------------------- */ | |||
t_widgetbehavior hradio_widgetbehavior; | |||
static t_class *hradio_class, *hradio_old_class; | |||
/* widget helper functions */ | |||
void hradio_draw_update(t_gobj *client, t_glist *glist) | |||
{ | |||
t_hradio *x = (t_hradio *)client; | |||
if(glist_isvisible(glist)) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT%d -fill #%06x -outline #%06x\n", | |||
canvas, x, x->x_drawn, | |||
x->x_gui.x_bcol, x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT%d -fill #%06x -outline #%06x\n", | |||
canvas, x, x->x_on, | |||
x->x_gui.x_fcol, x->x_gui.x_fcol); | |||
x->x_drawn = x->x_on; | |||
} | |||
} | |||
void hradio_draw_new(t_hradio *x, t_glist *glist) | |||
{ | |||
int n = x->x_number, i, dx = x->x_gui.x_w, s4 = dx / 4; | |||
int yy11 = text_ypix(&x->x_gui.x_obj, glist), yy12 = yy11 + dx; | |||
int yy21 = yy11 + s4, yy22 = yy12 - s4; | |||
int xx11b = text_xpix(&x->x_gui.x_obj, glist), xx11 = xx11b, xx21 = xx11b + s4; | |||
int xx22 = xx11b + dx - s4; | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -width %d -fill #%06x -tags %lxBASE%d\n", | |||
canvas, xx11, yy11, xx11 + dx, yy12, IEMGUI_ZOOM(x), | |||
x->x_gui.x_bcol, x, i); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill #%06x -outline #%06x -tags %lxBUT%d\n", | |||
canvas, xx21, yy21, xx22, yy22, | |||
(x->x_on == i) ? x->x_gui.x_fcol : x->x_gui.x_bcol, | |||
(x->x_on == i) ? x->x_gui.x_fcol : x->x_gui.x_bcol, x, i); | |||
xx11 += dx; | |||
xx21 += dx; | |||
xx22 += dx; | |||
x->x_drawn = x->x_on; | |||
} | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]\n", | |||
canvas, | |||
xx11b, yy12 + IEMGUI_ZOOM(x) - ioh, | |||
xx11b + iow, yy12, | |||
x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xx11b, yy11, | |||
xx11b + iow, yy11 - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w -font {{%s} -%d %s} -fill #%06x -tags [list %lxLABEL label text]\n", | |||
canvas, xx11b + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
yy11 + x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
} | |||
void hradio_draw_move(t_hradio *x, t_glist *glist) | |||
{ | |||
int n = x->x_number, i, dx = x->x_gui.x_w, s4 = dx / 4; | |||
int yy11 = text_ypix(&x->x_gui.x_obj, glist), yy12 = yy11 + dx; | |||
int yy21 = yy11 + s4, yy22 = yy12 - s4; | |||
int xx11b = text_xpix(&x->x_gui.x_obj, glist), xx11 = xx11b, xx21 = xx11b + s4; | |||
int xx22 = xx11b + dx - s4; | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
xx11 = xx11b; | |||
xx21 = xx11b + s4; | |||
xx22 = xx11b + dx - s4; | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c coords %lxBASE%d %d %d %d %d\n", | |||
canvas, x, i, xx11, yy11, xx11 + dx, yy12); | |||
sys_vgui(".x%lx.c coords %lxBUT%d %d %d %d %d\n", | |||
canvas, x, i, xx21, yy21, xx22, yy22); | |||
xx11 += dx; | |||
xx21 += dx; | |||
xx22 += dx; | |||
} | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, xx11b + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
yy11 + x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xx11b, yy12 + IEMGUI_ZOOM(x) - ioh, | |||
xx11b + iow, yy12); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xx11b, yy11, | |||
xx11b + iow, yy11 - IEMGUI_ZOOM(x) + ioh); | |||
} | |||
void hradio_draw_erase(t_hradio* x, t_glist* glist) | |||
{ | |||
int n = x->x_number, i; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c delete %lxBASE%d\n", canvas, x, i); | |||
sys_vgui(".x%lx.c delete %lxBUT%d\n", canvas, x, i); | |||
} | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
void hradio_draw_config(t_hradio* x, t_glist* glist) | |||
{ | |||
int n = x->x_number, i; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, sys_fontweight, | |||
x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol, | |||
strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""); | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE%d -fill #%06x\n", canvas, x, i, | |||
x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT%d -fill #%06x -outline #%06x\n", canvas, x, i, | |||
(x->x_on == i) ? x->x_gui.x_fcol : x->x_gui.x_bcol, | |||
(x->x_on == i) ? x->x_gui.x_fcol : x->x_gui.x_bcol); | |||
} | |||
} | |||
void hradio_draw_io(t_hradio* x, t_glist* glist, int old_snd_rcv_flags) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
/* keep these above outlet */ | |||
if(x->x_on == 0) { | |||
sys_vgui(".x%lx.c raise %lxBUT%d %lxOUT%d\n", canvas, x, x->x_on, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxBUT%d\n", canvas, x, x, x->x_on); | |||
} | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
/* keep these above inlet */ | |||
if(x->x_on == 0) { | |||
sys_vgui(".x%lx.c raise %lxBUT%d %lxIN%d\n", canvas, x, x->x_on, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxBUT%d\n", canvas, x, x, x->x_on); | |||
} | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
void hradio_draw_select(t_hradio* x, t_glist* glist) | |||
{ | |||
int n = x->x_number, i; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE%d -outline #%06x\n", canvas, x, i, | |||
IEM_GUI_COLOR_SELECTED); | |||
} | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE%d -outline #%06x\n", canvas, x, i, | |||
IEM_GUI_COLOR_NORMAL); | |||
} | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, | |||
x->x_gui.x_lcol); | |||
} | |||
} | |||
void hradio_draw(t_hradio *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_UPDATE) | |||
sys_queuegui(x, glist, hradio_draw_update); | |||
else if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
hradio_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
hradio_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
hradio_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
hradio_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
hradio_draw_config(x, glist); | |||
else if(mode >= IEM_GUI_DRAW_MODE_IO) | |||
hradio_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO); | |||
} | |||
/* ------------------------ hdl widgetbehaviour----------------------------- */ | |||
static void hradio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_hradio *x = (t_hradio *)z; | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist); | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist); | |||
*xp2 = *xp1 + x->x_gui.x_w * x->x_number; | |||
*yp2 = *yp1 + x->x_gui.x_h; | |||
} | |||
static void hradio_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_hradio *x = (t_hradio *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
binbuf_addv(b, "ssiisiiiisssiiiisssf", gensym("#X"),gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix, | |||
(pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class ? | |||
gensym("hdl") : gensym("hradio")), | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), | |||
x->x_change, iem_symargstoint(&x->x_gui.x_isa), x->x_number, | |||
srl[0], srl[1], srl[2], | |||
x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[1], bflcol[2], x->x_fval); | |||
binbuf_addv(b, ";"); | |||
} | |||
static void hradio_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_hradio *x = (t_hradio *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
int hchange = -1; | |||
iemgui_properties(&x->x_gui, srl); | |||
if(pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class) | |||
hchange = x->x_change; | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |hradio| \ | |||
----------dimensions(pix):----------- %d %d size: 0 0 empty \ | |||
empty 0.0 empty 0.0 empty %d \ | |||
%d new-only new&old %d %d number: %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x #%06x #%06x\n", | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), IEM_GUI_MINSIZE, | |||
0,/*no_schedule*/ | |||
hchange, x->x_gui.x_isa.x_loadinit, -1, x->x_number, | |||
srl[0]->s_name, srl[1]->s_name, | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
static void hradio_dialog(t_hradio *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int a = (int)atom_getfloatarg(0, argc, argv); | |||
int chg = (int)atom_getfloatarg(4, argc, argv); | |||
int num = (int)atom_getfloatarg(6, argc, argv); | |||
int sr_flags; | |||
if(chg != 0) chg = 1; | |||
x->x_change = chg; | |||
sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
x->x_gui.x_w = iemgui_clip_size(a) * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
if(x->x_number != num) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE); | |||
x->x_number = num; | |||
if(x->x_on >= x->x_number) | |||
{ | |||
x->x_on = x->x_number - 1; | |||
x->x_on_old = x->x_on; | |||
} | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW); | |||
} | |||
else | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
} | |||
static void hradio_set(t_hradio *x, t_floatarg f) | |||
{ | |||
int i = (int)f; | |||
int old = x->x_on_old; | |||
x->x_fval = f; | |||
if(i < 0) | |||
i = 0; | |||
if(i >= x->x_number) | |||
i = x->x_number - 1; | |||
if(x->x_on != x->x_on_old) | |||
{ | |||
old = x->x_on_old; | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
x->x_on_old = old; | |||
} | |||
else | |||
{ | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
} | |||
} | |||
static void hradio_bang(t_hradio *x) | |||
{ | |||
/* compatibility with earlier "hdial" behavior */ | |||
if(pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class) | |||
{ | |||
if((x->x_change) && (x->x_on != x->x_on_old)) | |||
{ | |||
SETFLOAT(x->x_at, (t_float)x->x_on_old); | |||
SETFLOAT(x->x_at+1, 0.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
x->x_on_old = x->x_on; | |||
SETFLOAT(x->x_at, (t_float)x->x_on); | |||
SETFLOAT(x->x_at+1, 1.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
else | |||
{ | |||
float outval = (pd_compatibilitylevel < 46 ? x->x_on : x->x_fval); | |||
outlet_float(x->x_gui.x_obj.ob_outlet, outval); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, outval); | |||
} | |||
} | |||
static void hradio_fout(t_hradio *x, t_floatarg f) | |||
{ | |||
int i = (int)f; | |||
x->x_fval = f; | |||
if(i < 0) | |||
i = 0; | |||
if(i >= x->x_number) | |||
i = x->x_number - 1; | |||
if(pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class) | |||
{ | |||
if((x->x_change) && (i != x->x_on_old)) | |||
{ | |||
SETFLOAT(x->x_at, (t_float)x->x_on_old); | |||
SETFLOAT(x->x_at+1, 0.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
if(x->x_on != x->x_on_old) | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
x->x_on_old = x->x_on; | |||
SETFLOAT(x->x_at, (t_float)x->x_on); | |||
SETFLOAT(x->x_at+1, 1.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
else | |||
{ | |||
float outval = (pd_compatibilitylevel < 46 ? i : x->x_fval); | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
outlet_float(x->x_gui.x_obj.ob_outlet, outval); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, outval); | |||
} | |||
} | |||
static void hradio_float(t_hradio *x, t_floatarg f) | |||
{ | |||
int i = (int)f; | |||
x->x_fval = f; | |||
if(i < 0) | |||
i = 0; | |||
if(i >= x->x_number) | |||
i = x->x_number - 1; | |||
if(pd_class(&x->x_gui.x_obj.ob_pd) == hradio_old_class) | |||
{ | |||
/* compatibility with earlier "hdial" behavior */ | |||
if((x->x_change) && (i != x->x_on_old)) | |||
{ | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
SETFLOAT(x->x_at, (t_float)x->x_on_old); | |||
SETFLOAT(x->x_at+1, 0.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
} | |||
if(x->x_on != x->x_on_old) | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
x->x_on_old = x->x_on; | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
SETFLOAT(x->x_at, (t_float)x->x_on); | |||
SETFLOAT(x->x_at+1, 1.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
} | |||
else | |||
{ | |||
float outval = (pd_compatibilitylevel < 46 ? i : x->x_fval); | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
outlet_float(x->x_gui.x_obj.ob_outlet, outval); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, outval); | |||
} | |||
} | |||
} | |||
static void hradio_click(t_hradio *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | |||
{ | |||
int xx = (int)xpos - (int)text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist); | |||
hradio_fout(x, (t_float)(xx / x->x_gui.x_w)); | |||
} | |||
static int hradio_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit) | |||
{ | |||
if(doit) | |||
hradio_click((t_hradio *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt); | |||
return (1); | |||
} | |||
static void hradio_loadbang(t_hradio *x, t_floatarg action) | |||
{ | |||
if(action == LB_LOAD && x->x_gui.x_isa.x_loadinit) | |||
hradio_bang(x); | |||
} | |||
static void hradio_number(t_hradio *x, t_floatarg num) | |||
{ | |||
int n = (int)num; | |||
if(n < 1) | |||
n = 1; | |||
if(n > IEM_RADIO_MAX) | |||
n = IEM_RADIO_MAX; | |||
if(n != x->x_number) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE); | |||
x->x_number = n; | |||
if(x->x_on >= x->x_number) | |||
x->x_on = x->x_number - 1; | |||
x->x_on_old = x->x_on; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
} | |||
static void hradio_size(t_hradio *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
x->x_gui.x_w = iemgui_clip_size((int)atom_getfloatarg(0, ac, av)) * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
iemgui_size((void *)x, &x->x_gui); | |||
} | |||
static void hradio_delta(t_hradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void hradio_pos(t_hradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void hradio_color(t_hradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void hradio_send(t_hradio *x, t_symbol *s) | |||
{iemgui_send(x, &x->x_gui, s);} | |||
static void hradio_receive(t_hradio *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void hradio_label(t_hradio *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void hradio_label_pos(t_hradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void hradio_label_font(t_hradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);} | |||
static void hradio_init(t_hradio *x, t_floatarg f) | |||
{x->x_gui.x_isa.x_loadinit = (f == 0.0) ? 0 : 1;} | |||
static void hradio_double_change(t_hradio *x) | |||
{x->x_change = 1;} | |||
static void hradio_single_change(t_hradio *x) | |||
{x->x_change = 0;} | |||
static void *hradio_donew(t_symbol *s, int argc, t_atom *argv, int old) | |||
{ | |||
t_hradio *x = (t_hradio *)pd_new(old ? hradio_old_class : hradio_class); | |||
int a=IEM_GUI_DEFAULTSIZE, on = 0, f = 0; | |||
int ldx = 0, ldy = -8, chg = 1, num = 8; | |||
int fs = 10; | |||
int ftbreak = IEM_BNG_DEFAULTBREAKFLASHTIME, fthold = IEM_BNG_DEFAULTHOLDFLASHTIME; | |||
char str[144]; | |||
float fval = 0; | |||
iem_inttosymargs(&x->x_gui.x_isa, 0); | |||
iem_inttofstyle(&x->x_gui.x_fsf, 0); | |||
x->x_gui.x_bcol = 0xFCFCFC; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x00; | |||
if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2) | |||
&&IS_A_FLOAT(argv,3) | |||
&&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4)) | |||
&&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5)) | |||
&&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6)) | |||
&&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8) | |||
&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,14)) | |||
{ | |||
a = (int)atom_getfloatarg(0, argc, argv); | |||
chg = (int)atom_getfloatarg(1, argc, argv); | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(2, argc, argv)); | |||
num = (int)atom_getfloatarg(3, argc, argv); | |||
iemgui_new_getnames(&x->x_gui, 4, argv); | |||
ldx = (int)atom_getfloatarg(7, argc, argv); | |||
ldy = (int)atom_getfloatarg(8, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(9, argc, argv)); | |||
fs = (int)atom_getfloatarg(10, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+11, argv+12, argv+13); | |||
fval = atom_getfloatarg(14, argc, argv); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 4, 0); | |||
x->x_gui.x_draw = (t_iemfunptr)hradio_draw; | |||
x->x_gui.x_fsf.x_snd_able = 1; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if(!strcmp(x->x_gui.x_snd->s_name, "empty")) | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) | |||
x->x_gui.x_fsf.x_rcv_able = 0; | |||
if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
if(num < 1) | |||
num = 1; | |||
if(num > IEM_RADIO_MAX) | |||
num = IEM_RADIO_MAX; | |||
x->x_number = num; | |||
x->x_fval = fval; | |||
on = fval; | |||
if(on < 0) | |||
on = 0; | |||
if(on >= x->x_number) | |||
on = x->x_number - 1; | |||
if(x->x_gui.x_isa.x_loadinit) | |||
x->x_on = on; | |||
else | |||
x->x_on = 0; | |||
x->x_on_old = x->x_on; | |||
x->x_change = (chg == 0) ? 0 : 1; | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < 4) | |||
fs = 4; | |||
x->x_gui.x_fontsize = fs; | |||
x->x_gui.x_w = iemgui_clip_size(a); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
iemgui_newzoom(&x->x_gui); | |||
outlet_new(&x->x_gui.x_obj, &s_list); | |||
return (x); | |||
} | |||
static void *hradio_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
return (hradio_donew(s, argc, argv, 0)); | |||
} | |||
static void *hdial_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
return (hradio_donew(s, argc, argv, 1)); | |||
} | |||
static void hradio_ff(t_hradio *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_hradio_setup(void) | |||
{ | |||
hradio_class = class_new(gensym("hradio"), (t_newmethod)hradio_new, | |||
(t_method)hradio_ff, sizeof(t_hradio), 0, A_GIMME, 0); | |||
class_addbang(hradio_class, hradio_bang); | |||
class_addfloat(hradio_class, hradio_float); | |||
class_addmethod(hradio_class, (t_method)hradio_click, | |||
gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_loadbang, | |||
gensym("loadbang"), A_DEFFLOAT, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_set, | |||
gensym("set"), A_FLOAT, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_init, | |||
gensym("init"), A_FLOAT, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_number, | |||
gensym("number"), A_FLOAT, 0); | |||
class_addmethod(hradio_class, (t_method)hradio_single_change, | |||
gensym("single_change"), 0); | |||
class_addmethod(hradio_class, (t_method)hradio_double_change, | |||
gensym("double_change"), 0); | |||
class_addmethod(hradio_class, (t_method)iemgui_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
hradio_widgetbehavior.w_getrectfn = hradio_getrect; | |||
hradio_widgetbehavior.w_displacefn = iemgui_displace; | |||
hradio_widgetbehavior.w_selectfn = iemgui_select; | |||
hradio_widgetbehavior.w_activatefn = NULL; | |||
hradio_widgetbehavior.w_deletefn = iemgui_delete; | |||
hradio_widgetbehavior.w_visfn = iemgui_vis; | |||
hradio_widgetbehavior.w_clickfn = hradio_newclick; | |||
class_setwidget(hradio_class, &hradio_widgetbehavior); | |||
class_sethelpsymbol(hradio_class, gensym("hradio")); | |||
class_setsavefn(hradio_class, hradio_save); | |||
class_setpropertiesfn(hradio_class, hradio_properties); | |||
/*obsolete version (0.34-0.35) */ | |||
hradio_old_class = class_new(gensym("hdl"), (t_newmethod)hdial_new, | |||
(t_method)hradio_ff, sizeof(t_hradio), 0, A_GIMME, 0); | |||
class_addcreator((t_newmethod)hradio_new, gensym("rdb"), A_GIMME, 0); | |||
class_addcreator((t_newmethod)hradio_new, gensym("radiobut"), A_GIMME, 0); | |||
class_addcreator((t_newmethod)hradio_new, gensym("radiobutton"), | |||
A_GIMME, 0); | |||
class_addbang(hradio_old_class, hradio_bang); | |||
class_addfloat(hradio_old_class, hradio_float); | |||
class_addmethod(hradio_old_class, (t_method)hradio_click, | |||
gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_loadbang, | |||
gensym("loadbang"), 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_set, | |||
gensym("set"), A_FLOAT, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_init, | |||
gensym("init"), A_FLOAT, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_number, | |||
gensym("number"), A_FLOAT, 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_single_change, | |||
gensym("single_change"), 0); | |||
class_addmethod(hradio_old_class, (t_method)hradio_double_change, | |||
gensym("double_change"), 0); | |||
class_addmethod(hradio_old_class, (t_method)iemgui_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
class_setwidget(hradio_old_class, &hradio_widgetbehavior); | |||
class_sethelpsymbol(hradio_old_class, gensym("hradio")); | |||
} |
@@ -0,0 +1,691 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
#define LMARGIN 3 | |||
#define RMARGIN 2 | |||
/* ------------ hsl gui-horizontal slider ----------------------- */ | |||
t_widgetbehavior hslider_widgetbehavior; | |||
static t_class *hslider_class; | |||
/* widget helper functions */ | |||
static void hslider_draw_update(t_gobj *client, t_glist *glist) | |||
{ | |||
t_hslider *x = (t_hslider *)client; | |||
if (glist_isvisible(glist)) | |||
{ | |||
int r = text_xpix(&x->x_gui.x_obj, glist) + ((x->x_val + 50)/100); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c coords %lxKNOB %d %d %d %d\n", | |||
canvas, x, r, ypos + IEMGUI_ZOOM(x), | |||
r, ypos + x->x_gui.x_h - IEMGUI_ZOOM(x)); | |||
} | |||
} | |||
static void hslider_draw_new(t_hslider *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int lmargin = LMARGIN * IEMGUI_ZOOM(x), rmargin = RMARGIN * IEMGUI_ZOOM(x); | |||
int r = xpos + (x->x_val + 50)/100; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -width %d -fill #%06x -tags %lxBASE\n", | |||
canvas, xpos - lmargin, ypos, | |||
xpos + x->x_gui.x_w + rmargin, ypos + x->x_gui.x_h, | |||
IEMGUI_ZOOM(x), | |||
x->x_gui.x_bcol, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]\n", | |||
canvas, | |||
xpos - lmargin, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos - lmargin + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xpos - lmargin, ypos, | |||
xpos - lmargin + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
sys_vgui(".x%lx.c create line %d %d %d %d -width %d -fill #%06x -tags %lxKNOB\n", | |||
canvas, r, ypos + IEMGUI_ZOOM(x), | |||
r, ypos + x->x_gui.x_h - IEMGUI_ZOOM(x), | |||
1 + 2 * IEMGUI_ZOOM(x), x->x_gui.x_fcol, x); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags [list %lxLABEL label text]\n", | |||
canvas, xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
} | |||
static void hslider_draw_move(t_hslider *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int lmargin = LMARGIN * IEMGUI_ZOOM(x), rmargin = RMARGIN * IEMGUI_ZOOM(x); | |||
int r = xpos + (x->x_val + 50)/100; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c coords %lxBASE %d %d %d %d\n", | |||
canvas, x, | |||
xpos - lmargin, ypos, | |||
xpos + x->x_gui.x_w + rmargin, ypos + x->x_gui.x_h); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos - lmargin, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos - lmargin + iow, ypos + x->x_gui.x_h); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos - lmargin, ypos, | |||
xpos - lmargin + iow, ypos - IEMGUI_ZOOM(x) + ioh); | |||
sys_vgui(".x%lx.c coords %lxKNOB %d %d %d %d\n", | |||
canvas, x, r, ypos + IEMGUI_ZOOM(x), | |||
r, ypos + x->x_gui.x_h - IEMGUI_ZOOM(x)); | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, xpos+x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos+x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
} | |||
static void hslider_draw_erase(t_hslider* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxKNOB\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
static void hslider_draw_config(t_hslider* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : "")); | |||
sys_vgui(".x%lx.c itemconfigure %lxKNOB -fill #%06x\n", canvas, x, x->x_gui.x_fcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -fill #%06x\n", canvas, x, x->x_gui.x_bcol); | |||
} | |||
static void hslider_draw_io(t_hslider* x, t_glist* glist, int old_snd_rcv_flags) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int lmargin = LMARGIN * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos - lmargin, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos - lmargin + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
/* keep these above outlet */ | |||
sys_vgui(".x%lx.c raise %lxKNOB %lxOUT%d\n", canvas, x, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxKNOB\n", canvas, x, x); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos - lmargin, ypos, | |||
xpos - lmargin + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
/* keep these above inlet */ | |||
sys_vgui(".x%lx.c raise %lxKNOB %lxIN%d\n", canvas, x, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxKNOB\n", canvas, x, x); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
static void hslider_draw_select(t_hslider* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_NORMAL); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, x->x_gui.x_lcol); | |||
} | |||
} | |||
void hslider_draw(t_hslider *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_UPDATE) | |||
sys_queuegui(x, glist, hslider_draw_update); | |||
else if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
hslider_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
hslider_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
hslider_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
hslider_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
hslider_draw_config(x, glist); | |||
else if(mode >= IEM_GUI_DRAW_MODE_IO) | |||
hslider_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO); | |||
} | |||
/* ------------------------ hsl widgetbehaviour----------------------------- */ | |||
static void hslider_getrect(t_gobj *z, t_glist *glist, | |||
int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_hslider* x = (t_hslider*)z; | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist) - LMARGIN*glist_getzoom(glist); | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist); | |||
*xp2 = *xp1 + x->x_gui.x_w + (LMARGIN + RMARGIN)*glist_getzoom(glist); | |||
*yp2 = *yp1 + x->x_gui.x_h; | |||
} | |||
static void hslider_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_hslider *x = (t_hslider *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
binbuf_addv(b, "ssiisiiffiisssiiiisssii", gensym("#X"), gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix, | |||
gensym("hsl"), x->x_gui.x_w/IEMGUI_ZOOM(x), x->x_gui.x_h/IEMGUI_ZOOM(x), | |||
(t_float)x->x_min, (t_float)x->x_max, | |||
x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa), | |||
srl[0], srl[1], srl[2], | |||
x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[1], bflcol[2], | |||
x->x_val, x->x_steady); | |||
binbuf_addv(b, ";"); | |||
} | |||
void hslider_check_width(t_hslider *x, int w) | |||
{ | |||
if(w < IEM_SL_MINSIZE * IEMGUI_ZOOM(x)) | |||
w = IEM_SL_MINSIZE * IEMGUI_ZOOM(x); | |||
x->x_gui.x_w = w; | |||
if(x->x_val > (x->x_gui.x_w*100 - 100)) | |||
{ | |||
x->x_pos = x->x_gui.x_w*100 - 100; | |||
x->x_val = x->x_pos; | |||
} | |||
if(x->x_lin0_log1) | |||
x->x_k = log(x->x_max/x->x_min) / (double)(x->x_gui.x_w/IEMGUI_ZOOM(x) - 1); | |||
else | |||
x->x_k = (x->x_max - x->x_min) / (double)(x->x_gui.x_w/IEMGUI_ZOOM(x) - 1); | |||
} | |||
void hslider_check_minmax(t_hslider *x, double min, double max) | |||
{ | |||
if(x->x_lin0_log1) | |||
{ | |||
if((min == 0.0) && (max == 0.0)) | |||
max = 1.0; | |||
if(max > 0.0) | |||
{ | |||
if(min <= 0.0) | |||
min = 0.01*max; | |||
} | |||
else | |||
{ | |||
if(min > 0.0) | |||
max = 0.01*min; | |||
} | |||
} | |||
x->x_min = min; | |||
x->x_max = max; | |||
if(x->x_lin0_log1) | |||
x->x_k = log(x->x_max/x->x_min) / (double)(x->x_gui.x_w/IEMGUI_ZOOM(x) - 1); | |||
else | |||
x->x_k = (x->x_max - x->x_min) / (double)(x->x_gui.x_w/IEMGUI_ZOOM(x) - 1); | |||
} | |||
static void hslider_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_hslider *x = (t_hslider *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
iemgui_properties(&x->x_gui, srl); | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |hsl| \ | |||
--------dimensions(pix)(pix):-------- %d %d width: %d %d height: \ | |||
-----------output-range:----------- %g left: %g right: %g \ | |||
%d lin log %d %d empty %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x #%06x #%06x\n", | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), IEM_SL_MINSIZE, x->x_gui.x_h/IEMGUI_ZOOM(x), IEM_GUI_MINSIZE, | |||
x->x_min, x->x_max, 0.0,/*no_schedule*/ | |||
x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/ | |||
srl[0]->s_name, srl[1]->s_name, | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
static void hslider_set(t_hslider *x, t_floatarg f) /* bugfix */ | |||
{ | |||
int old = x->x_val; | |||
double g; | |||
x->x_fval = f; | |||
if (x->x_min > x->x_max) | |||
{ | |||
if(f > x->x_min) | |||
f = x->x_min; | |||
if(f < x->x_max) | |||
f = x->x_max; | |||
} | |||
else | |||
{ | |||
if(f > x->x_max) | |||
f = x->x_max; | |||
if(f < x->x_min) | |||
f = x->x_min; | |||
} | |||
if(x->x_lin0_log1) | |||
g = log(f/x->x_min) / x->x_k; | |||
else | |||
g = (f - x->x_min) / x->x_k; | |||
x->x_val = IEMGUI_ZOOM(x) * (int)(100.0*g + 0.49999); | |||
x->x_pos = x->x_val; | |||
if(x->x_val != old) | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
} | |||
/* compute numeric value (fval) from pixel location (val) and range */ | |||
static t_float hslider_getfval(t_hslider *x) | |||
{ | |||
t_float fval; | |||
int zoomval = (x->x_gui.x_fsf.x_finemoved) ? | |||
x->x_val/IEMGUI_ZOOM(x) : (x->x_val / (100*IEMGUI_ZOOM(x))) * 100; | |||
if (x->x_lin0_log1) | |||
fval = x->x_min * exp(x->x_k * (double)(zoomval) * 0.01); | |||
else fval = (double)(zoomval) * 0.01 * x->x_k + x->x_min; | |||
if ((fval < 1.0e-10) && (fval > -1.0e-10)) | |||
fval = 0.0; | |||
return (fval); | |||
} | |||
static void hslider_bang(t_hslider *x) | |||
{ | |||
double out; | |||
if (pd_compatibilitylevel < 46) | |||
out = hslider_getfval(x); | |||
else out = x->x_fval; | |||
outlet_float(x->x_gui.x_obj.ob_outlet, out); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, out); | |||
} | |||
static void hslider_dialog(t_hslider *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int w = (int)atom_getfloatarg(0, argc, argv) * IEMGUI_ZOOM(x); | |||
int h = (int)atom_getfloatarg(1, argc, argv); | |||
double min = (double)atom_getfloatarg(2, argc, argv); | |||
double max = (double)atom_getfloatarg(3, argc, argv); | |||
int lilo = (int)atom_getfloatarg(4, argc, argv); | |||
int steady = (int)atom_getfloatarg(17, argc, argv); | |||
int sr_flags; | |||
if(lilo != 0) lilo = 1; | |||
x->x_lin0_log1 = lilo; | |||
if(steady) | |||
x->x_steady = 1; | |||
else | |||
x->x_steady = 0; | |||
sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
x->x_gui.x_h = iemgui_clip_size(h) * IEMGUI_ZOOM(x); | |||
hslider_check_width(x, w); | |||
hslider_check_minmax(x, min, max); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
static void hslider_motion(t_hslider *x, t_floatarg dx, t_floatarg dy) | |||
{ | |||
int old = x->x_val; | |||
if(x->x_gui.x_fsf.x_finemoved) | |||
x->x_pos += (int)dx; | |||
else | |||
x->x_pos += 100 * (int)dx; | |||
x->x_val = x->x_pos; | |||
if(x->x_val > (100*x->x_gui.x_w - 100)) | |||
{ | |||
x->x_val = 100*x->x_gui.x_w - 100; | |||
x->x_pos += 50; | |||
x->x_pos -= x->x_pos % 100; | |||
} | |||
if(x->x_val < 0) | |||
{ | |||
x->x_val = 0; | |||
x->x_pos -= 50; | |||
x->x_pos -= x->x_pos % 100; | |||
} | |||
x->x_fval = hslider_getfval(x); | |||
if (old != x->x_val) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
hslider_bang(x); | |||
} | |||
} | |||
static void hslider_click(t_hslider *x, t_floatarg xpos, t_floatarg ypos, | |||
t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | |||
{ | |||
if(!x->x_steady) | |||
x->x_val = (int)(100.0 * (xpos - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist))); | |||
if(x->x_val > (100*x->x_gui.x_w - 100)) | |||
x->x_val = 100*x->x_gui.x_w - 100; | |||
if(x->x_val < 0) | |||
x->x_val = 0; | |||
x->x_fval = hslider_getfval(x); | |||
x->x_pos = x->x_val; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
hslider_bang(x); | |||
glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, (t_glistmotionfn)hslider_motion, | |||
0, xpos, ypos); | |||
} | |||
static int hslider_newclick(t_gobj *z, struct _glist *glist, | |||
int xpix, int ypix, int shift, int alt, int dbl, int doit) | |||
{ | |||
t_hslider* x = (t_hslider *)z; | |||
if(doit) | |||
{ | |||
hslider_click(x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, | |||
0, (t_floatarg)alt); | |||
if(shift) | |||
x->x_gui.x_fsf.x_finemoved = 1; | |||
else | |||
x->x_gui.x_fsf.x_finemoved = 0; | |||
} | |||
return (1); | |||
} | |||
static void hslider_size(t_hslider *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
hslider_check_width(x, (int)atom_getfloatarg(0, ac, av)*IEMGUI_ZOOM(x)); | |||
if(ac > 1) | |||
x->x_gui.x_h = iemgui_clip_size((int)atom_getfloatarg(1, ac, av))*IEMGUI_ZOOM(x); | |||
iemgui_size((void *)x, &x->x_gui); | |||
} | |||
static void hslider_delta(t_hslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void hslider_pos(t_hslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void hslider_range(t_hslider *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
hslider_check_minmax(x, (double)atom_getfloatarg(0, ac, av), | |||
(double)atom_getfloatarg(1, ac, av)); | |||
} | |||
static void hslider_color(t_hslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void hslider_send(t_hslider *x, t_symbol *s) | |||
{iemgui_send(x, &x->x_gui, s);} | |||
static void hslider_receive(t_hslider *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void hslider_label(t_hslider *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void hslider_label_pos(t_hslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void hslider_label_font(t_hslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);} | |||
static void hslider_log(t_hslider *x) | |||
{ | |||
x->x_lin0_log1 = 1; | |||
hslider_check_minmax(x, x->x_min, x->x_max); | |||
} | |||
static void hslider_lin(t_hslider *x) | |||
{ | |||
x->x_lin0_log1 = 0; | |||
x->x_k = (x->x_max - x->x_min) / (double)(x->x_gui.x_w/IEMGUI_ZOOM(x) - 1); | |||
} | |||
static void hslider_init(t_hslider *x, t_floatarg f) | |||
{ | |||
x->x_gui.x_isa.x_loadinit = (f == 0.0) ? 0 : 1; | |||
} | |||
static void hslider_steady(t_hslider *x, t_floatarg f) | |||
{ | |||
x->x_steady = (f == 0.0) ? 0 : 1; | |||
} | |||
static void hslider_zoom(t_hslider *x, t_floatarg f) | |||
{ | |||
/* scale current pixel value */ | |||
x->x_val = (IEMGUI_ZOOM(x) == 2 ? (x->x_val)/2 : (x->x_val)*2); | |||
x->x_pos = x->x_val; | |||
iemgui_zoom(&x->x_gui, f); | |||
} | |||
static void hslider_float(t_hslider *x, t_floatarg f) | |||
{ | |||
hslider_set(x, f); | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
hslider_bang(x); | |||
} | |||
static void hslider_loadbang(t_hslider *x, t_floatarg action) | |||
{ | |||
if (action == LB_LOAD && x->x_gui.x_isa.x_loadinit) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
hslider_bang(x); | |||
} | |||
} | |||
static void *hslider_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_hslider *x = (t_hslider *)pd_new(hslider_class); | |||
int w = IEM_SL_DEFAULTSIZE, h = IEM_GUI_DEFAULTSIZE; | |||
int lilo = 0, ldx = -2, ldy = -8, f = 0, steady = 1; | |||
int fs = 10; | |||
double min = 0.0, max = (double)(IEM_SL_DEFAULTSIZE-1); | |||
char str[144]; | |||
float v = 0; | |||
iem_inttosymargs(&x->x_gui.x_isa, 0); | |||
iem_inttofstyle(&x->x_gui.x_fsf, 0); | |||
x->x_gui.x_bcol = 0xFCFCFC; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x00; | |||
if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1) | |||
&&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3) | |||
&&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5) | |||
&&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6)) | |||
&&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7)) | |||
&&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8)) | |||
&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10) | |||
&&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,16)) | |||
{ | |||
w = (int)atom_getfloatarg(0, argc, argv); | |||
h = (int)atom_getfloatarg(1, argc, argv); | |||
min = (double)atom_getfloatarg(2, argc, argv); | |||
max = (double)atom_getfloatarg(3, argc, argv); | |||
lilo = (int)atom_getfloatarg(4, argc, argv); | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(5, argc, argv)); | |||
iemgui_new_getnames(&x->x_gui, 6, argv); | |||
ldx = (int)atom_getfloatarg(9, argc, argv); | |||
ldy = (int)atom_getfloatarg(10, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(11, argc, argv)); | |||
fs = (int)atom_getfloatarg(12, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+13, argv+14, argv+15); | |||
v = atom_getfloatarg(16, argc, argv); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 6, 0); | |||
if((argc == 18)&&IS_A_FLOAT(argv,17)) | |||
steady = (int)atom_getfloatarg(17, argc, argv); | |||
x->x_gui.x_draw = (t_iemfunptr)hslider_draw; | |||
x->x_gui.x_fsf.x_snd_able = 1; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if (x->x_gui.x_isa.x_loadinit) | |||
x->x_val = v; | |||
else x->x_val = 0; | |||
x->x_pos = x->x_val; | |||
if(lilo != 0) lilo = 1; | |||
x->x_lin0_log1 = lilo; | |||
if(steady != 0) steady = 1; | |||
x->x_steady = steady; | |||
if (!strcmp(x->x_gui.x_snd->s_name, "empty")) | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
if (!strcmp(x->x_gui.x_rcv->s_name, "empty")) | |||
x->x_gui.x_fsf.x_rcv_able = 0; | |||
if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
if (x->x_gui.x_fsf.x_rcv_able) | |||
pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < 4) | |||
fs = 4; | |||
x->x_gui.x_fontsize = fs; | |||
x->x_gui.x_h = iemgui_clip_size(h); | |||
hslider_check_width(x, w); | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
iemgui_newzoom(&x->x_gui); | |||
hslider_check_minmax(x, min, max); | |||
outlet_new(&x->x_gui.x_obj, &s_float); | |||
x->x_fval = hslider_getfval(x); | |||
return (x); | |||
} | |||
static void hslider_free(t_hslider *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_hslider_setup(void) | |||
{ | |||
hslider_class = class_new(gensym("hsl"), (t_newmethod)hslider_new, | |||
(t_method)hslider_free, sizeof(t_hslider), 0, A_GIMME, 0); | |||
#ifndef GGEE_HSLIDER_COMPATIBLE | |||
class_addcreator((t_newmethod)hslider_new, gensym("hslider"), A_GIMME, 0); | |||
#endif | |||
class_addbang(hslider_class, hslider_bang); | |||
class_addfloat(hslider_class, hslider_float); | |||
class_addmethod(hslider_class, (t_method)hslider_click, | |||
gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_motion, | |||
gensym("motion"), A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_loadbang, | |||
gensym("loadbang"), A_DEFFLOAT, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_set, | |||
gensym("set"), A_FLOAT, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_range, | |||
gensym("range"), A_GIMME, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_log, | |||
gensym("log"), 0); | |||
class_addmethod(hslider_class, (t_method)hslider_lin, | |||
gensym("lin"), 0); | |||
class_addmethod(hslider_class, (t_method)hslider_init, | |||
gensym("init"), A_FLOAT, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_steady, | |||
gensym("steady"), A_FLOAT, 0); | |||
class_addmethod(hslider_class, (t_method)hslider_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
hslider_widgetbehavior.w_getrectfn = hslider_getrect; | |||
hslider_widgetbehavior.w_displacefn = iemgui_displace; | |||
hslider_widgetbehavior.w_selectfn = iemgui_select; | |||
hslider_widgetbehavior.w_activatefn = NULL; | |||
hslider_widgetbehavior.w_deletefn = iemgui_delete; | |||
hslider_widgetbehavior.w_visfn = iemgui_vis; | |||
hslider_widgetbehavior.w_clickfn = hslider_newclick; | |||
class_setwidget(hslider_class, &hslider_widgetbehavior); | |||
class_sethelpsymbol(hslider_class, gensym("hslider")); | |||
class_setsavefn(hslider_class, hslider_save); | |||
class_setpropertiesfn(hslider_class, hslider_properties); | |||
} |
@@ -0,0 +1,599 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* graphical inlets and outlets, both for control and signals. */ | |||
/* This code is highly inefficient; messages actually have to be forwarded | |||
by inlets and outlets. The outlet is in even worse shape than the inlet; | |||
in order to avoid having a "signal" method in the class, the oulet actually | |||
sprouts an inlet, which forwards the message to the "outlet" object, which | |||
sends it on to the outlet proper. Another way to do it would be to have | |||
separate classes for "signal" and "control" outlets, but this would complicate | |||
life elsewhere. */ | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include <string.h> | |||
void signal_setborrowed(t_signal *sig, t_signal *sig2); | |||
void signal_makereusable(t_signal *sig); | |||
/* ------------------------- vinlet -------------------------- */ | |||
t_class *vinlet_class; | |||
typedef struct _vinlet | |||
{ | |||
t_object x_obj; | |||
t_canvas *x_canvas; | |||
t_inlet *x_inlet; | |||
int x_bufsize; | |||
t_float *x_buf; /* signal buffer; zero if not a signal */ | |||
t_float *x_endbuf; | |||
t_float *x_fill; | |||
t_float *x_read; | |||
int x_hop; | |||
/* if not reblocking, the next slot communicates the parent's inlet | |||
signal from the prolog to the DSP routine: */ | |||
t_signal *x_directsignal; | |||
t_resample x_updown; | |||
} t_vinlet; | |||
static void *vinlet_new(t_symbol *s) | |||
{ | |||
t_vinlet *x = (t_vinlet *)pd_new(vinlet_class); | |||
x->x_canvas = canvas_getcurrent(); | |||
x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, 0); | |||
x->x_bufsize = 0; | |||
x->x_buf = 0; | |||
outlet_new(&x->x_obj, 0); | |||
return (x); | |||
} | |||
static void vinlet_bang(t_vinlet *x) | |||
{ | |||
outlet_bang(x->x_obj.ob_outlet); | |||
} | |||
static void vinlet_pointer(t_vinlet *x, t_gpointer *gp) | |||
{ | |||
outlet_pointer(x->x_obj.ob_outlet, gp); | |||
} | |||
static void vinlet_float(t_vinlet *x, t_float f) | |||
{ | |||
outlet_float(x->x_obj.ob_outlet, f); | |||
} | |||
static void vinlet_symbol(t_vinlet *x, t_symbol *s) | |||
{ | |||
outlet_symbol(x->x_obj.ob_outlet, s); | |||
} | |||
static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
outlet_list(x->x_obj.ob_outlet, s, argc, argv); | |||
} | |||
static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
outlet_anything(x->x_obj.ob_outlet, s, argc, argv); | |||
} | |||
static void vinlet_free(t_vinlet *x) | |||
{ | |||
canvas_rminlet(x->x_canvas, x->x_inlet); | |||
if (x->x_buf) | |||
t_freebytes(x->x_buf, x->x_bufsize * sizeof(*x->x_buf)); | |||
resample_free(&x->x_updown); | |||
} | |||
t_inlet *vinlet_getit(t_pd *x) | |||
{ | |||
if (pd_class(x) != vinlet_class) bug("vinlet_getit"); | |||
return (((t_vinlet *)x)->x_inlet); | |||
} | |||
/* ------------------------- signal inlet -------------------------- */ | |||
int vinlet_issignal(t_vinlet *x) | |||
{ | |||
return (x->x_buf != 0); | |||
} | |||
t_int *vinlet_perform(t_int *w) | |||
{ | |||
t_vinlet *x = (t_vinlet *)(w[1]); | |||
t_float *out = (t_float *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_float *in = x->x_read; | |||
while (n--) *out++ = *in++; | |||
if (in == x->x_endbuf) in = x->x_buf; | |||
x->x_read = in; | |||
return (w+4); | |||
} | |||
static void vinlet_dsp(t_vinlet *x, t_signal **sp) | |||
{ | |||
t_signal *outsig; | |||
/* no buffer means we're not a signal inlet */ | |||
if (!x->x_buf) | |||
return; | |||
outsig = sp[0]; | |||
if (x->x_directsignal) | |||
{ | |||
signal_setborrowed(sp[0], x->x_directsignal); | |||
} | |||
else | |||
{ | |||
dsp_add(vinlet_perform, 3, x, outsig->s_vec, outsig->s_vecsize); | |||
x->x_read = x->x_buf; | |||
} | |||
} | |||
/* prolog code: loads buffer from parent patch */ | |||
t_int *vinlet_doprolog(t_int *w) | |||
{ | |||
t_vinlet *x = (t_vinlet *)(w[1]); | |||
t_float *in = (t_float *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_float *out = x->x_fill; | |||
if (out == x->x_endbuf) | |||
{ | |||
t_float *f1 = x->x_buf, *f2 = x->x_buf + x->x_hop; | |||
int nshift = x->x_bufsize - x->x_hop; | |||
out -= x->x_hop; | |||
while (nshift--) *f1++ = *f2++; | |||
} | |||
while (n--) *out++ = *in++; | |||
x->x_fill = out; | |||
return (w+4); | |||
} | |||
int inlet_getsignalindex(t_inlet *x); | |||
/* set up prolog DSP code */ | |||
void vinlet_dspprolog(struct _vinlet *x, t_signal **parentsigs, | |||
int myvecsize, int calcsize, int phase, int period, int frequency, | |||
int downsample, int upsample, int reblock, int switched) | |||
{ | |||
t_signal *insig, *outsig; | |||
/* no buffer means we're not a signal inlet */ | |||
if (!x->x_buf) | |||
return; | |||
x->x_updown.downsample = downsample; | |||
x->x_updown.upsample = upsample; | |||
/* if the "reblock" flag is set, arrange to copy data in from the | |||
parent. */ | |||
if (reblock) | |||
{ | |||
int parentvecsize, bufsize, oldbufsize, prologphase; | |||
int re_parentvecsize; /* resampled parentvectorsize */ | |||
/* this should never happen: */ | |||
if (!x->x_buf) return; | |||
/* the prolog code counts from 0 to period-1; the | |||
phase is backed up by one so that AFTER the prolog code | |||
runs, the "x_fill" phase is in sync with the "x_read" phase. */ | |||
prologphase = (phase - 1) & (period - 1); | |||
if (parentsigs) | |||
{ | |||
insig = parentsigs[inlet_getsignalindex(x->x_inlet)]; | |||
parentvecsize = insig->s_vecsize; | |||
re_parentvecsize = parentvecsize * upsample / downsample; | |||
} | |||
else | |||
{ | |||
insig = 0; | |||
parentvecsize = 1; | |||
re_parentvecsize = 1; | |||
} | |||
bufsize = re_parentvecsize; | |||
if (bufsize < myvecsize) bufsize = myvecsize; | |||
if (bufsize != (oldbufsize = x->x_bufsize)) | |||
{ | |||
t_float *buf = x->x_buf; | |||
t_freebytes(buf, oldbufsize * sizeof(*buf)); | |||
buf = (t_float *)t_getbytes(bufsize * sizeof(*buf)); | |||
memset((char *)buf, 0, bufsize * sizeof(*buf)); | |||
x->x_bufsize = bufsize; | |||
x->x_endbuf = buf + bufsize; | |||
x->x_buf = buf; | |||
} | |||
if (parentsigs) | |||
{ | |||
x->x_hop = period * re_parentvecsize; | |||
x->x_fill = x->x_endbuf - | |||
(x->x_hop - prologphase * re_parentvecsize); | |||
if (upsample * downsample == 1) | |||
dsp_add(vinlet_doprolog, 3, x, insig->s_vec, | |||
re_parentvecsize); | |||
else { | |||
int method = (x->x_updown.method == 3? | |||
(pd_compatibilitylevel < 44 ? 0 : 1) : x->x_updown.method); | |||
resamplefrom_dsp(&x->x_updown, insig->s_vec, parentvecsize, | |||
re_parentvecsize, method); | |||
dsp_add(vinlet_doprolog, 3, x, x->x_updown.s_vec, | |||
re_parentvecsize); | |||
} | |||
/* if the input signal's reference count is zero, we have | |||
to free it here because we didn't in ugen_doit(). */ | |||
if (!insig->s_refcount) | |||
signal_makereusable(insig); | |||
} | |||
else memset((char *)(x->x_buf), 0, bufsize * sizeof(*x->x_buf)); | |||
x->x_directsignal = 0; | |||
} | |||
else | |||
{ | |||
/* no reblocking; in this case our output signal is "borrowed" | |||
and merely needs to be pointed to the real one. */ | |||
x->x_directsignal = parentsigs[inlet_getsignalindex(x->x_inlet)]; | |||
} | |||
} | |||
static void *vinlet_newsig(t_symbol *s) | |||
{ | |||
t_vinlet *x = (t_vinlet *)pd_new(vinlet_class); | |||
x->x_canvas = canvas_getcurrent(); | |||
x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal); | |||
x->x_endbuf = x->x_buf = (t_float *)getbytes(0); | |||
x->x_bufsize = 0; | |||
x->x_directsignal = 0; | |||
outlet_new(&x->x_obj, &s_signal); | |||
resample_init(&x->x_updown); | |||
/* this should be though over: | |||
* it might prove hard to provide consistency between labeled up- & downsampling methods | |||
* maybe indices would be better... | |||
* | |||
* up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) | |||
*/ | |||
if (s == gensym("hold")) | |||
x->x_updown.method=1; /* up: sample and hold */ | |||
else if (s == gensym("lin") || s == gensym("linear")) | |||
x->x_updown.method=2; /* up: linear interpolation */ | |||
else if (s == gensym("pad")) | |||
x->x_updown.method=0; /* up: zero-padding */ | |||
else x->x_updown.method=3; /* sample/hold unless version<0.44 */ | |||
return (x); | |||
} | |||
static void vinlet_setup(void) | |||
{ | |||
vinlet_class = class_new(gensym("inlet"), (t_newmethod)vinlet_new, | |||
(t_method)vinlet_free, sizeof(t_vinlet), CLASS_NOINLET, A_DEFSYM, 0); | |||
class_addcreator((t_newmethod)vinlet_newsig, gensym("inlet~"), A_DEFSYM, 0); | |||
class_addbang(vinlet_class, vinlet_bang); | |||
class_addpointer(vinlet_class, vinlet_pointer); | |||
class_addfloat(vinlet_class, vinlet_float); | |||
class_addsymbol(vinlet_class, vinlet_symbol); | |||
class_addlist(vinlet_class, vinlet_list); | |||
class_addanything(vinlet_class, vinlet_anything); | |||
class_addmethod(vinlet_class, (t_method)vinlet_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(vinlet_class, gensym("pd")); | |||
} | |||
/* ------------------------- voutlet -------------------------- */ | |||
t_class *voutlet_class; | |||
typedef struct _voutlet | |||
{ | |||
t_object x_obj; | |||
t_canvas *x_canvas; | |||
t_outlet *x_parentoutlet; | |||
int x_bufsize; | |||
t_sample *x_buf; /* signal buffer; zero if not a signal */ | |||
t_sample *x_endbuf; | |||
t_sample *x_empty; /* next to read out of buffer in epilog code */ | |||
t_sample *x_write; /* next to write in to buffer */ | |||
int x_hop; /* hopsize */ | |||
/* vice versa from the inlet, if we don't block, this holds the | |||
parent's outlet signal, valid between the prolog and the dsp setup | |||
routines. */ | |||
t_signal *x_directsignal; | |||
/* and here's a flag indicating that we aren't blocked but have to | |||
do a copy (because we're switched). */ | |||
char x_justcopyout; | |||
t_resample x_updown; | |||
} t_voutlet; | |||
static void *voutlet_new(t_symbol *s) | |||
{ | |||
t_voutlet *x = (t_voutlet *)pd_new(voutlet_class); | |||
x->x_canvas = canvas_getcurrent(); | |||
x->x_parentoutlet = canvas_addoutlet(x->x_canvas, &x->x_obj.ob_pd, 0); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, 0, 0); | |||
x->x_bufsize = 0; | |||
x->x_buf = 0; | |||
return (x); | |||
} | |||
static void voutlet_bang(t_voutlet *x) | |||
{ | |||
outlet_bang(x->x_parentoutlet); | |||
} | |||
static void voutlet_pointer(t_voutlet *x, t_gpointer *gp) | |||
{ | |||
outlet_pointer(x->x_parentoutlet, gp); | |||
} | |||
static void voutlet_float(t_voutlet *x, t_float f) | |||
{ | |||
outlet_float(x->x_parentoutlet, f); | |||
} | |||
static void voutlet_symbol(t_voutlet *x, t_symbol *s) | |||
{ | |||
outlet_symbol(x->x_parentoutlet, s); | |||
} | |||
static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
outlet_list(x->x_parentoutlet, s, argc, argv); | |||
} | |||
static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
outlet_anything(x->x_parentoutlet, s, argc, argv); | |||
} | |||
static void voutlet_free(t_voutlet *x) | |||
{ | |||
canvas_rmoutlet(x->x_canvas, x->x_parentoutlet); | |||
if (x->x_buf) | |||
t_freebytes(x->x_buf, x->x_bufsize * sizeof(*x->x_buf)); | |||
resample_free(&x->x_updown); | |||
} | |||
t_outlet *voutlet_getit(t_pd *x) | |||
{ | |||
if (pd_class(x) != voutlet_class) bug("voutlet_getit"); | |||
return (((t_voutlet *)x)->x_parentoutlet); | |||
} | |||
/* ------------------------- signal outlet -------------------------- */ | |||
int voutlet_issignal(t_voutlet *x) | |||
{ | |||
return (x->x_buf != 0); | |||
} | |||
/* LATER optimize for non-overlapped case where the "+=" isn't needed */ | |||
t_int *voutlet_perform(t_int *w) | |||
{ | |||
t_voutlet *x = (t_voutlet *)(w[1]); | |||
t_float *in = (t_float *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_sample *out = x->x_write, *outwas = out; | |||
while (n--) | |||
{ | |||
*out++ += *in++; | |||
if (out == x->x_endbuf) out = x->x_buf; | |||
} | |||
outwas += x->x_hop; | |||
if (outwas >= x->x_endbuf) outwas = x->x_buf; | |||
x->x_write = outwas; | |||
return (w+4); | |||
} | |||
/* epilog code for blocking: write buffer to parent patch */ | |||
static t_int *voutlet_doepilog(t_int *w) | |||
{ | |||
t_voutlet *x = (t_voutlet *)(w[1]); | |||
t_sample *out = (t_sample *)(w[2]); | |||
int n = (int)(w[3]); | |||
t_sample *in = x->x_empty; | |||
if (x->x_updown.downsample != x->x_updown.upsample) | |||
out = x->x_updown.s_vec; | |||
for (; n--; in++) *out++ = *in, *in = 0; | |||
if (in == x->x_endbuf) in = x->x_buf; | |||
x->x_empty = in; | |||
return (w+4); | |||
} | |||
static t_int *voutlet_doepilog_resampling(t_int *w) | |||
{ | |||
t_voutlet *x = (t_voutlet *)(w[1]); | |||
int n = (int)(w[2]); | |||
t_sample *in = x->x_empty; | |||
t_sample *out = x->x_updown.s_vec; | |||
for (; n--; in++) *out++ = *in, *in = 0; | |||
if (in == x->x_endbuf) in = x->x_buf; | |||
x->x_empty = in; | |||
return (w+3); | |||
} | |||
int outlet_getsignalindex(t_outlet *x); | |||
/* prolog for outlets -- store pointer to the outlet on the | |||
parent, which, if "reblock" is false, will want to refer | |||
back to whatever we see on our input during the "dsp" method | |||
called later. */ | |||
void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs, | |||
int myvecsize, int calcsize, int phase, int period, int frequency, | |||
int downsample, int upsample, int reblock, int switched) | |||
{ | |||
/* no buffer means we're not a signal outlet */ | |||
if (!x->x_buf) | |||
return; | |||
x->x_updown.downsample=downsample; | |||
x->x_updown.upsample=upsample; | |||
x->x_justcopyout = (switched && !reblock); | |||
if (reblock) | |||
{ | |||
x->x_directsignal = 0; | |||
} | |||
else | |||
{ | |||
if (!parentsigs) bug("voutlet_dspprolog"); | |||
x->x_directsignal = | |||
parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | |||
} | |||
} | |||
static void voutlet_dsp(t_voutlet *x, t_signal **sp) | |||
{ | |||
t_signal *insig; | |||
if (!x->x_buf) return; | |||
insig = sp[0]; | |||
if (x->x_justcopyout) | |||
dsp_add_copy(insig->s_vec, x->x_directsignal->s_vec, insig->s_n); | |||
else if (x->x_directsignal) | |||
{ | |||
/* if we're just going to make the signal available on the | |||
parent patch, hand it off to the parent signal. */ | |||
/* this is done elsewhere--> sp[0]->s_refcount++; */ | |||
signal_setborrowed(x->x_directsignal, sp[0]); | |||
} | |||
else | |||
dsp_add(voutlet_perform, 3, x, insig->s_vec, insig->s_n); | |||
} | |||
/* set up epilog DSP code. If we're reblocking, this is the | |||
time to copy the samples out to the containing object's outlets. | |||
If we aren't reblocking, there's nothing to do here. */ | |||
void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs, | |||
int myvecsize, int calcsize, int phase, int period, int frequency, | |||
int downsample, int upsample, int reblock, int switched) | |||
{ | |||
if (!x->x_buf) return; /* this shouldn't be necesssary... */ | |||
x->x_updown.downsample=downsample; | |||
x->x_updown.upsample=upsample; | |||
if (reblock) | |||
{ | |||
t_signal *insig, *outsig; | |||
int parentvecsize, bufsize, oldbufsize; | |||
int re_parentvecsize; | |||
int bigperiod, epilogphase, blockphase; | |||
if (parentsigs) | |||
{ | |||
outsig = parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | |||
parentvecsize = outsig->s_vecsize; | |||
re_parentvecsize = parentvecsize * upsample / downsample; | |||
} | |||
else | |||
{ | |||
outsig = 0; | |||
parentvecsize = 1; | |||
re_parentvecsize = 1; | |||
} | |||
bigperiod = myvecsize/re_parentvecsize; | |||
if (!bigperiod) bigperiod = 1; | |||
epilogphase = phase & (bigperiod - 1); | |||
blockphase = (phase + period - 1) & (bigperiod - 1) & (- period); | |||
bufsize = re_parentvecsize; | |||
if (bufsize < myvecsize) bufsize = myvecsize; | |||
if (bufsize != (oldbufsize = x->x_bufsize)) | |||
{ | |||
t_sample *buf = x->x_buf; | |||
t_freebytes(buf, oldbufsize * sizeof(*buf)); | |||
buf = (t_sample *)t_getbytes(bufsize * sizeof(*buf)); | |||
memset((char *)buf, 0, bufsize * sizeof(*buf)); | |||
x->x_bufsize = bufsize; | |||
x->x_endbuf = buf + bufsize; | |||
x->x_buf = buf; | |||
} | |||
if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog"); | |||
x->x_write = x->x_buf + re_parentvecsize * blockphase; | |||
if (x->x_write == x->x_endbuf) x->x_write = x->x_buf; | |||
if (period == 1 && frequency > 1) | |||
x->x_hop = re_parentvecsize / frequency; | |||
else x->x_hop = period * re_parentvecsize; | |||
/* post("phase %d, block %d, parent %d", phase & 63, | |||
parentvecsize * blockphase, parentvecsize * epilogphase); */ | |||
if (parentsigs) | |||
{ | |||
/* set epilog pointer and schedule it */ | |||
x->x_empty = x->x_buf + re_parentvecsize * epilogphase; | |||
if (upsample * downsample == 1) | |||
dsp_add(voutlet_doepilog, 3, x, outsig->s_vec, | |||
re_parentvecsize); | |||
else | |||
{ | |||
int method = (x->x_updown.method == 3? | |||
(pd_compatibilitylevel < 44 ? 0 : 1) : x->x_updown.method); | |||
dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize); | |||
resampleto_dsp(&x->x_updown, outsig->s_vec, re_parentvecsize, | |||
parentvecsize, method); | |||
} | |||
} | |||
} | |||
/* if we aren't blocked but we are switched, the epilog code just | |||
copies zeros to the output. In this case the blocking code actually | |||
jumps over the epilog if the block is running. */ | |||
else if (switched) | |||
{ | |||
if (parentsigs) | |||
{ | |||
t_signal *outsig = | |||
parentsigs[outlet_getsignalindex(x->x_parentoutlet)]; | |||
dsp_add_zero(outsig->s_vec, outsig->s_n); | |||
} | |||
} | |||
} | |||
static void *voutlet_newsig(t_symbol *s) | |||
{ | |||
t_voutlet *x = (t_voutlet *)pd_new(voutlet_class); | |||
x->x_canvas = canvas_getcurrent(); | |||
x->x_parentoutlet = canvas_addoutlet(x->x_canvas, | |||
&x->x_obj.ob_pd, &s_signal); | |||
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); | |||
x->x_endbuf = x->x_buf = (t_sample *)getbytes(0); | |||
x->x_bufsize = 0; | |||
resample_init(&x->x_updown); | |||
/* this should be though over: | |||
* it might prove hard to provide consistency between labeled up- & downsampling methods | |||
* maybe indices would be better... | |||
* | |||
* up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) | |||
*/ | |||
if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */ | |||
else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */ | |||
else if (s == gensym("linear"))x->x_updown.method=2; /* up: linear interpolation */ | |||
else if (s == gensym("pad"))x->x_updown.method=0; /* up: zero pad */ | |||
else x->x_updown.method=3; /* up: zero-padding; down: ignore samples inbetween */ | |||
return (x); | |||
} | |||
static void voutlet_setup(void) | |||
{ | |||
voutlet_class = class_new(gensym("outlet"), (t_newmethod)voutlet_new, | |||
(t_method)voutlet_free, sizeof(t_voutlet), CLASS_NOINLET, A_DEFSYM, 0); | |||
class_addcreator((t_newmethod)voutlet_newsig, gensym("outlet~"), A_DEFSYM, 0); | |||
class_addbang(voutlet_class, voutlet_bang); | |||
class_addpointer(voutlet_class, voutlet_pointer); | |||
class_addfloat(voutlet_class, (t_method)voutlet_float); | |||
class_addsymbol(voutlet_class, voutlet_symbol); | |||
class_addlist(voutlet_class, voutlet_list); | |||
class_addanything(voutlet_class, voutlet_anything); | |||
class_addmethod(voutlet_class, (t_method)voutlet_dsp, | |||
gensym("dsp"), A_CANT, 0); | |||
class_sethelpsymbol(voutlet_class, gensym("pd")); | |||
} | |||
/* ---------------------------- overall setup ----------------------------- */ | |||
void g_io_setup(void) | |||
{ | |||
vinlet_setup(); | |||
voutlet_setup(); | |||
} |
@@ -0,0 +1,406 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
/* ---------- cnv my gui-canvas for a window ---------------- */ | |||
t_widgetbehavior my_canvas_widgetbehavior; | |||
static t_class *my_canvas_class; | |||
/* widget helper functions */ | |||
void my_canvas_draw_new(t_my_canvas *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int offset = (IEMGUI_ZOOM(x) > 1 ? IEMGUI_ZOOM(x) : 0); /* keep zoomed border inside visible area */ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill #%06x -outline #%06x -tags %lxRECT\n", | |||
canvas, xpos, ypos, | |||
xpos + x->x_vis_w * IEMGUI_ZOOM(x), | |||
ypos + x->x_vis_h * IEMGUI_ZOOM(x), | |||
x->x_gui.x_bcol, x->x_gui.x_bcol, x); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -width %d -outline #%06x -tags %lxBASE\n", | |||
canvas, xpos + offset, ypos + offset, | |||
xpos + offset + x->x_gui.x_w, ypos + offset + x->x_gui.x_h, | |||
IEMGUI_ZOOM(x), x->x_gui.x_bcol, x); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags [list %lxLABEL label text]\n", | |||
canvas, | |||
xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
} | |||
void my_canvas_draw_move(t_my_canvas *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int offset = (IEMGUI_ZOOM(x) > 1 ? IEMGUI_ZOOM(x) : 0); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c coords %lxRECT %d %d %d %d\n", | |||
canvas, x, xpos, ypos, | |||
xpos + x->x_vis_w * IEMGUI_ZOOM(x), | |||
ypos + x->x_vis_h * IEMGUI_ZOOM(x)); | |||
sys_vgui(".x%lx.c coords %lxBASE %d %d %d %d\n", | |||
canvas, x, xpos + offset, ypos + offset, | |||
xpos + offset + x->x_gui.x_w, ypos + offset + x->x_gui.x_h); | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
} | |||
void my_canvas_draw_erase(t_my_canvas* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxRECT\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
} | |||
void my_canvas_draw_config(t_my_canvas* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxRECT -fill #%06x -outline #%06x\n", canvas, x, | |||
x->x_gui.x_bcol, x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_bcol)); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : "")); | |||
} | |||
void my_canvas_draw_select(t_my_canvas* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, x->x_gui.x_bcol); | |||
} | |||
} | |||
void my_canvas_draw(t_my_canvas *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
my_canvas_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
my_canvas_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
my_canvas_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
my_canvas_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
my_canvas_draw_config(x, glist); | |||
} | |||
/* ------------------------ cnv widgetbehaviour----------------------------- */ | |||
static void my_canvas_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_my_canvas *x = (t_my_canvas *)z; | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist); | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist); | |||
*xp2 = *xp1 + x->x_gui.x_w; | |||
*yp2 = *yp1 + x->x_gui.x_h; | |||
} | |||
static void my_canvas_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_my_canvas *x = (t_my_canvas *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
binbuf_addv(b, "ssiisiiisssiiiissi", gensym("#X"),gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix, | |||
gensym("cnv"), x->x_gui.x_w/IEMGUI_ZOOM(x), x->x_vis_w, x->x_vis_h, | |||
srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[2], iem_symargstoint(&x->x_gui.x_isa)); | |||
binbuf_addv(b, ";"); | |||
} | |||
static void my_canvas_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_my_canvas *x = (t_my_canvas *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
iemgui_properties(&x->x_gui, srl); | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |cnv| \ | |||
------selectable_dimensions(pix):------ %d %d size: 0.0 0.0 empty \ | |||
------visible_rectangle(pix)(pix):------ %d width: %d height: %d \ | |||
%d empty empty %d %d empty %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x none #%06x\n", | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), 1, | |||
x->x_vis_w, x->x_vis_h, 0,/*no_schedule*/ | |||
-1, -1, -1, -1,/*no linlog, no init, no multi*/ | |||
srl[0]->s_name, srl[1]->s_name, | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
static void my_canvas_get_pos(t_my_canvas *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
{ | |||
x->x_at[0].a_w.w_float = text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)/IEMGUI_ZOOM(x); | |||
x->x_at[1].a_w.w_float = text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)/IEMGUI_ZOOM(x); | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
} | |||
static void my_canvas_dialog(t_my_canvas *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int a = atom_getfloatarg(0, argc, argv); | |||
int w = atom_getfloatarg(2, argc, argv); | |||
int h = atom_getfloatarg(3, argc, argv); | |||
int sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
x->x_gui.x_isa.x_loadinit = 0; | |||
if(a < 1) | |||
a = 1; | |||
x->x_gui.x_w = a * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
if(w < 1) | |||
w = 1; | |||
x->x_vis_w = w; | |||
if(h < 1) | |||
h = 1; | |||
x->x_vis_h = h; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
} | |||
static void my_canvas_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
int i = atom_getfloatarg(0, ac, av); | |||
if(i < 1) | |||
i = 1; | |||
x->x_gui.x_w = i*IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
iemgui_size((void *)x, &x->x_gui); | |||
} | |||
static void my_canvas_delta(t_my_canvas *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void my_canvas_pos(t_my_canvas *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void my_canvas_vis_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
int i; | |||
i = atom_getfloatarg(0, ac, av); | |||
if(i < 1) | |||
i = 1; | |||
x->x_vis_w = i; | |||
if(ac > 1) | |||
{ | |||
i = atom_getfloatarg(1, ac, av); | |||
if(i < 1) | |||
i = 1; | |||
} | |||
x->x_vis_h = i; | |||
if(glist_isvisible(x->x_gui.x_glist)) | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
} | |||
static void my_canvas_color(t_my_canvas *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void my_canvas_send(t_my_canvas *x, t_symbol *s) | |||
{iemgui_send(x, &x->x_gui, s);} | |||
static void my_canvas_receive(t_my_canvas *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void my_canvas_label(t_my_canvas *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void my_canvas_label_pos(t_my_canvas *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void my_canvas_label_font(t_my_canvas *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);} | |||
static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_my_canvas *x = (t_my_canvas *)pd_new(my_canvas_class); | |||
int a = IEM_GUI_DEFAULTSIZE, w = 100, h = 60; | |||
int ldx = 20, ldy = 12, f = 2, i = 0; | |||
int fs = 14; | |||
char str[144]; | |||
iem_inttosymargs(&x->x_gui.x_isa, 0); | |||
iem_inttofstyle(&x->x_gui.x_fsf, 0); | |||
x->x_gui.x_bcol = 0xE0E0E0; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x404040; | |||
if(((argc >= 10)&&(argc <= 13)) | |||
&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)) | |||
{ | |||
a = atom_getfloatarg(0, argc, argv); | |||
w = atom_getfloatarg(1, argc, argv); | |||
h = atom_getfloatarg(2, argc, argv); | |||
} | |||
if((argc >= 12)&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))&&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))) | |||
{ | |||
i = 2; | |||
iemgui_new_getnames(&x->x_gui, 3, argv); | |||
} | |||
else if((argc == 11)&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))) | |||
{ | |||
i = 1; | |||
iemgui_new_getnames(&x->x_gui, 3, argv); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 3, 0); | |||
if(((argc >= 10)&&(argc <= 13)) | |||
&&(IS_A_SYMBOL(argv,i+3)||IS_A_FLOAT(argv,i+3))&&IS_A_FLOAT(argv,i+4) | |||
&&IS_A_FLOAT(argv,i+5)&&IS_A_FLOAT(argv,i+6) | |||
&&IS_A_FLOAT(argv,i+7)) | |||
{ | |||
/* disastrously, the "label" sits in a different part of the | |||
message. So we have to track its location separately (in | |||
the slot x_labelbindex) and initialize it specially here. */ | |||
iemgui_new_dogetname(&x->x_gui, i+3, argv); | |||
x->x_gui.x_labelbindex = i+4; | |||
ldx = atom_getfloatarg(i+4, argc, argv); | |||
ldy = atom_getfloatarg(i+5, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(i+6, argc, argv)); | |||
fs = atom_getfloatarg(i+7, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+i+8, 0, argv+i+9); | |||
} | |||
if((argc == 13)&&IS_A_FLOAT(argv,i+10)) | |||
{ | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(i+10, argc, argv)); | |||
} | |||
x->x_gui.x_draw = (t_iemfunptr)my_canvas_draw; | |||
x->x_gui.x_fsf.x_snd_able = 1; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if (!strcmp(x->x_gui.x_snd->s_name, "empty")) | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
if (!strcmp(x->x_gui.x_rcv->s_name, "empty")) | |||
x->x_gui.x_fsf.x_rcv_able = 0; | |||
if(a < 1) | |||
a = 1; | |||
x->x_gui.x_w = a; | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
if(w < 1) | |||
w = 1; | |||
x->x_vis_w = w; | |||
if(h < 1) | |||
h = 1; | |||
x->x_vis_h = h; | |||
if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
if (x->x_gui.x_fsf.x_rcv_able) | |||
pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < 4) | |||
fs = 4; | |||
x->x_gui.x_fontsize = fs; | |||
x->x_at[0].a_type = A_FLOAT; | |||
x->x_at[1].a_type = A_FLOAT; | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
iemgui_newzoom(&x->x_gui); | |||
return (x); | |||
} | |||
static void my_canvas_ff(t_my_canvas *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_mycanvas_setup(void) | |||
{ | |||
my_canvas_class = class_new(gensym("cnv"), (t_newmethod)my_canvas_new, | |||
(t_method)my_canvas_ff, sizeof(t_my_canvas), CLASS_NOINLET, A_GIMME, 0); | |||
class_addcreator((t_newmethod)my_canvas_new, gensym("my_canvas"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_vis_size, | |||
gensym("vis_size"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(my_canvas_class, (t_method)my_canvas_get_pos, | |||
gensym("get_pos"), 0); | |||
class_addmethod(my_canvas_class, (t_method)iemgui_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
my_canvas_widgetbehavior.w_getrectfn = my_canvas_getrect; | |||
my_canvas_widgetbehavior.w_displacefn = iemgui_displace; | |||
my_canvas_widgetbehavior.w_selectfn = iemgui_select; | |||
my_canvas_widgetbehavior.w_activatefn = NULL; | |||
my_canvas_widgetbehavior.w_deletefn = iemgui_delete; | |||
my_canvas_widgetbehavior.w_visfn = iemgui_vis; | |||
my_canvas_widgetbehavior.w_clickfn = NULL; | |||
class_setwidget(my_canvas_class, &my_canvas_widgetbehavior); | |||
class_sethelpsymbol(my_canvas_class, gensym("my_canvas")); | |||
class_setsavefn(my_canvas_class, my_canvas_save); | |||
class_setpropertiesfn(my_canvas_class, my_canvas_properties); | |||
} |
@@ -0,0 +1,926 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* my_numbox.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
#define MINDIGITS 1 | |||
#define MINFONT 4 | |||
/*------------------ global functions -------------------------*/ | |||
static void my_numbox_key(void *z, t_floatarg fkey); | |||
static void my_numbox_draw_update(t_gobj *client, t_glist *glist); | |||
/* ------------ nbx gui-my number box ----------------------- */ | |||
t_widgetbehavior my_numbox_widgetbehavior; | |||
static t_class *my_numbox_class; | |||
/* widget helper functions */ | |||
static void my_numbox_tick_reset(t_my_numbox *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_change && x->x_gui.x_glist) | |||
{ | |||
x->x_gui.x_fsf.x_change = 0; | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
} | |||
static void my_numbox_tick_wait(t_my_numbox *x) | |||
{ | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
void my_numbox_clip(t_my_numbox *x) | |||
{ | |||
if(x->x_val < x->x_min) | |||
x->x_val = x->x_min; | |||
if(x->x_val > x->x_max) | |||
x->x_val = x->x_max; | |||
} | |||
void my_numbox_calc_fontwidth(t_my_numbox *x) | |||
{ | |||
int w, f = 31; | |||
if(x->x_gui.x_fsf.x_font_style == 1) | |||
f = 27; | |||
else if(x->x_gui.x_fsf.x_font_style == 2) | |||
f = 25; | |||
w = x->x_gui.x_fontsize * f * x->x_numwidth; | |||
w /= 36; | |||
x->x_gui.x_w = (w + (x->x_gui.x_h/2)/IEMGUI_ZOOM(x) + 4) * IEMGUI_ZOOM(x); | |||
} | |||
void my_numbox_ftoa(t_my_numbox *x) | |||
{ | |||
double f = x->x_val; | |||
int bufsize, is_exp = 0, i, idecimal; | |||
sprintf(x->x_buf, "%g", f); | |||
bufsize = (int)strlen(x->x_buf); | |||
if(bufsize >= 5)/* if it is in exponential mode */ | |||
{ | |||
i = bufsize - 4; | |||
if((x->x_buf[i] == 'e') || (x->x_buf[i] == 'E')) | |||
is_exp = 1; | |||
} | |||
if(bufsize > x->x_numwidth)/* if to reduce */ | |||
{ | |||
if(is_exp) | |||
{ | |||
if(x->x_numwidth <= 5) | |||
{ | |||
x->x_buf[0] = (f < 0.0 ? '-' : '+'); | |||
x->x_buf[1] = 0; | |||
} | |||
i = bufsize - 4; | |||
for(idecimal = 0; idecimal < i; idecimal++) | |||
if(x->x_buf[idecimal] == '.') | |||
break; | |||
if(idecimal > (x->x_numwidth - 4)) | |||
{ | |||
x->x_buf[0] = (f < 0.0 ? '-' : '+'); | |||
x->x_buf[1] = 0; | |||
} | |||
else | |||
{ | |||
int new_exp_index = x->x_numwidth - 4; | |||
int old_exp_index = bufsize - 4; | |||
for(i = 0; i < 4; i++, new_exp_index++, old_exp_index++) | |||
x->x_buf[new_exp_index] = x->x_buf[old_exp_index]; | |||
x->x_buf[x->x_numwidth] = 0; | |||
} | |||
} | |||
else | |||
{ | |||
for(idecimal = 0; idecimal < bufsize; idecimal++) | |||
if(x->x_buf[idecimal] == '.') | |||
break; | |||
if(idecimal > x->x_numwidth) | |||
{ | |||
x->x_buf[0] = (f < 0.0 ? '-' : '+'); | |||
x->x_buf[1] = 0; | |||
} | |||
else | |||
x->x_buf[x->x_numwidth] = 0; | |||
} | |||
} | |||
} | |||
static void my_numbox_draw_update(t_gobj *client, t_glist *glist) | |||
{ | |||
t_my_numbox *x = (t_my_numbox *)client; | |||
if(glist_isvisible(glist)) | |||
{ | |||
if(x->x_gui.x_fsf.x_change) | |||
{ | |||
if(x->x_buf[0]) | |||
{ | |||
char *cp = x->x_buf; | |||
int sl = (int)strlen(x->x_buf); | |||
x->x_buf[sl] = '>'; | |||
x->x_buf[sl+1] = 0; | |||
if(sl >= x->x_numwidth) | |||
cp += sl - x->x_numwidth + 1; | |||
sys_vgui(".x%lx.c itemconfigure %lxNUMBER -fill #%06x -text {%s} \n", | |||
glist_getcanvas(glist), x, | |||
IEM_GUI_COLOR_EDITED, cp); | |||
x->x_buf[sl] = 0; | |||
} | |||
else | |||
{ | |||
my_numbox_ftoa(x); | |||
sys_vgui(".x%lx.c itemconfigure %lxNUMBER -fill #%06x -text {%s} \n", | |||
glist_getcanvas(glist), x, | |||
IEM_GUI_COLOR_EDITED, x->x_buf); | |||
x->x_buf[0] = 0; | |||
} | |||
} | |||
else | |||
{ | |||
my_numbox_ftoa(x); | |||
sys_vgui(".x%lx.c itemconfigure %lxNUMBER -fill #%06x -text {%s} \n", | |||
glist_getcanvas(glist), x, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_fcol), | |||
x->x_buf); | |||
x->x_buf[0] = 0; | |||
} | |||
} | |||
} | |||
static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int w = x->x_gui.x_w, half = x->x_gui.x_h/2; | |||
int d = IEMGUI_ZOOM(x) + x->x_gui.x_h/(34*IEMGUI_ZOOM(x)); | |||
int corner = x->x_gui.x_h/4; | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c create polygon %d %d %d %d %d %d %d %d %d %d %d %d " | |||
"-width %d -outline #%06x -fill #%06x -tags %lxBASE1\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + w - corner, ypos, | |||
xpos + w, ypos + corner, | |||
xpos + w, ypos + x->x_gui.x_h, | |||
xpos, ypos + x->x_gui.x_h, | |||
xpos, ypos, | |||
IEMGUI_ZOOM(x), IEM_GUI_COLOR_NORMAL, x->x_gui.x_bcol, x); | |||
sys_vgui(".x%lx.c create line %d %d %d %d %d %d -width %d -fill #%06x -tags %lxBASE2\n", | |||
canvas, | |||
xpos + IEMGUI_ZOOM(x), ypos + IEMGUI_ZOOM(x), | |||
xpos + half, ypos + half, | |||
xpos + IEMGUI_ZOOM(x), ypos + x->x_gui.x_h - IEMGUI_ZOOM(x), | |||
IEMGUI_ZOOM(x), x->x_gui.x_fcol, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
my_numbox_ftoa(x); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w -font {{%s} -%d %s} -fill #%06x -tags %lxNUMBER\n", | |||
canvas, xpos + half + 2*IEMGUI_ZOOM(x), ypos + half + d, | |||
x->x_buf, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), | |||
sys_fontweight, (x->x_gui.x_fsf.x_change ? IEM_GUI_COLOR_EDITED : x->x_gui.x_fcol), x); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w -font {{%s} -%d %s} -fill #%06x -tags [list %lxLABEL label text]\n", | |||
canvas, xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
} | |||
static void my_numbox_draw_move(t_my_numbox *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int w = x->x_gui.x_w, half = x->x_gui.x_h/2; | |||
int d = IEMGUI_ZOOM(x) + x->x_gui.x_h / (34 * IEMGUI_ZOOM(x)); | |||
int corner = x->x_gui.x_h/4; | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c coords %lxBASE1 %d %d %d %d %d %d %d %d %d %d %d %d\n", | |||
canvas, x, | |||
xpos, ypos, | |||
xpos + w - corner, ypos, | |||
xpos + w, ypos + corner, | |||
xpos + w, ypos + x->x_gui.x_h, | |||
xpos, ypos + x->x_gui.x_h, | |||
xpos, ypos); | |||
sys_vgui(".x%lx.c coords %lxBASE2 %d %d %d %d %d %d\n", | |||
canvas, x, | |||
xpos + IEMGUI_ZOOM(x), ypos + IEMGUI_ZOOM(x), | |||
xpos + half, ypos + half, | |||
xpos + IEMGUI_ZOOM(x), ypos + x->x_gui.x_h - IEMGUI_ZOOM(x)); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh); | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, | |||
xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
sys_vgui(".x%lx.c coords %lxNUMBER %d %d\n", | |||
canvas, x, xpos + half + 2*IEMGUI_ZOOM(x), ypos + half + d); | |||
} | |||
static void my_numbox_draw_erase(t_my_numbox* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c delete %lxBASE1\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxBASE2\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxNUMBER\n", canvas, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
static void my_numbox_draw_config(t_my_numbox* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol), | |||
strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name:""); | |||
sys_vgui(".x%lx.c itemconfigure %lxNUMBER -font {{%s} -%d %s} -fill #%06x \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_fcol)); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE1 -fill #%06x\n", canvas, | |||
x, x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE2 -fill #%06x\n", canvas, x, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_fcol)); | |||
} | |||
static void my_numbox_draw_io(t_my_numbox* x,t_glist* glist, int old_snd_rcv_flags) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able) { | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
/* keep these above outlet */ | |||
sys_vgui(".x%lx.c raise %lxNUMBER %lxOUT%d\n", canvas, x, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxNUMBER\n", canvas, x, x); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able) { | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
/* keep these above inlet */ | |||
sys_vgui(".x%lx.c raise %lxNUMBER %lxIN%d\n", canvas, x, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxNUMBER\n", canvas, x, x); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
if(x->x_gui.x_fsf.x_change) | |||
{ | |||
x->x_gui.x_fsf.x_change = 0; | |||
clock_unset(x->x_clock_reset); | |||
x->x_buf[0] = 0; | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE1 -outline #%06x\n", | |||
canvas, x, IEM_GUI_COLOR_SELECTED); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE2 -fill #%06x\n", | |||
canvas, x, IEM_GUI_COLOR_SELECTED); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", | |||
canvas, x, IEM_GUI_COLOR_SELECTED); | |||
sys_vgui(".x%lx.c itemconfigure %lxNUMBER -fill #%06x\n", | |||
canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE1 -outline #%06x\n", | |||
canvas, x, IEM_GUI_COLOR_NORMAL); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE2 -fill #%06x\n", | |||
canvas, x, x->x_gui.x_fcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", | |||
canvas, x, x->x_gui.x_lcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxNUMBER -fill #%06x\n", | |||
canvas, x, x->x_gui.x_fcol); | |||
} | |||
} | |||
void my_numbox_draw(t_my_numbox *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_UPDATE) | |||
sys_queuegui(x, glist, my_numbox_draw_update); | |||
else if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
my_numbox_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
my_numbox_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
my_numbox_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
my_numbox_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
my_numbox_draw_config(x, glist); | |||
else if(mode >= IEM_GUI_DRAW_MODE_IO) | |||
my_numbox_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO); | |||
} | |||
/* ------------------------ nbx widgetbehaviour----------------------------- */ | |||
static void my_numbox_getrect(t_gobj *z, t_glist *glist, | |||
int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_my_numbox* x = (t_my_numbox*)z; | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist); | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist); | |||
*xp2 = *xp1 + x->x_gui.x_w; | |||
*yp2 = *yp1 + x->x_gui.x_h; | |||
} | |||
static void my_numbox_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_my_numbox *x = (t_my_numbox *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
if(x->x_gui.x_fsf.x_change) | |||
{ | |||
x->x_gui.x_fsf.x_change = 0; | |||
clock_unset(x->x_clock_reset); | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
binbuf_addv(b, "ssiisiiffiisssiiiisssfi", gensym("#X"), gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix, | |||
gensym("nbx"), x->x_numwidth, x->x_gui.x_h/IEMGUI_ZOOM(x), | |||
(t_float)x->x_min, (t_float)x->x_max, | |||
x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa), | |||
srl[0], srl[1], srl[2], | |||
x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[1], bflcol[2], | |||
x->x_val, x->x_log_height); | |||
binbuf_addv(b, ";"); | |||
} | |||
int my_numbox_check_minmax(t_my_numbox *x, double min, double max) | |||
{ | |||
int ret = 0; | |||
if(x->x_lin0_log1) | |||
{ | |||
if((min == 0.0) && (max == 0.0)) | |||
max = 1.0; | |||
if(max > 0.0) | |||
{ | |||
if(min <= 0.0) | |||
min = 0.01 * max; | |||
} | |||
else | |||
{ | |||
if(min > 0.0) | |||
max = 0.01 * min; | |||
} | |||
} | |||
x->x_min = min; | |||
x->x_max = max; | |||
if(x->x_val < x->x_min) | |||
{ | |||
x->x_val = x->x_min; | |||
ret = 1; | |||
} | |||
if(x->x_val > x->x_max) | |||
{ | |||
x->x_val = x->x_max; | |||
ret = 1; | |||
} | |||
if(x->x_lin0_log1) | |||
x->x_k = exp(log(x->x_max/x->x_min) / (double)(x->x_log_height)); | |||
else | |||
x->x_k = 1.0; | |||
return(ret); | |||
} | |||
static void my_numbox_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_my_numbox *x = (t_my_numbox *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
iemgui_properties(&x->x_gui, srl); | |||
if(x->x_gui.x_fsf.x_change) | |||
{ | |||
x->x_gui.x_fsf.x_change = 0; | |||
clock_unset(x->x_clock_reset); | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |nbx| \ | |||
-------dimensions(digits)(pix):------- %d %d width: %d %d height: \ | |||
-----------output-range:----------- %g min: %g max: %d \ | |||
%d lin log %d %d log-height: %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x #%06x #%06x\n", | |||
x->x_numwidth, MINDIGITS, x->x_gui.x_h/IEMGUI_ZOOM(x), IEM_GUI_MINSIZE, | |||
x->x_min, x->x_max, 0,/*no_schedule*/ | |||
x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, -1, | |||
x->x_log_height, /*no multi, but iem-characteristic*/ | |||
srl[0]->s_name, srl[1]->s_name, | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, | |||
0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
static void my_numbox_bang(t_my_numbox *x) | |||
{ | |||
outlet_float(x->x_gui.x_obj.ob_outlet, x->x_val); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, x->x_val); | |||
} | |||
static void my_numbox_dialog(t_my_numbox *x, t_symbol *s, int argc, | |||
t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int w = (int)atom_getfloatarg(0, argc, argv); | |||
int h = (int)atom_getfloatarg(1, argc, argv); | |||
double min = (double)atom_getfloatarg(2, argc, argv); | |||
double max = (double)atom_getfloatarg(3, argc, argv); | |||
int lilo = (int)atom_getfloatarg(4, argc, argv); | |||
int log_height = (int)atom_getfloatarg(6, argc, argv); | |||
int sr_flags; | |||
if(lilo != 0) lilo = 1; | |||
x->x_lin0_log1 = lilo; | |||
sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
if(w < MINDIGITS) | |||
w = MINDIGITS; | |||
x->x_numwidth = w; | |||
if(h < IEM_GUI_MINSIZE) | |||
h = IEM_GUI_MINSIZE; | |||
x->x_gui.x_h = h * IEMGUI_ZOOM(x); | |||
if(log_height < 10) | |||
log_height = 10; | |||
x->x_log_height = log_height; | |||
my_numbox_calc_fontwidth(x); | |||
/*if(my_numbox_check_minmax(x, min, max)) | |||
my_numbox_bang(x);*/ | |||
my_numbox_check_minmax(x, min, max); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
static void my_numbox_motion(t_my_numbox *x, t_floatarg dx, t_floatarg dy) | |||
{ | |||
double k2 = 1.0; | |||
if(x->x_gui.x_fsf.x_finemoved) | |||
k2 = 0.01; | |||
if(x->x_lin0_log1) | |||
x->x_val *= pow(x->x_k, -k2*dy); | |||
else | |||
x->x_val -= k2*dy; | |||
my_numbox_clip(x); | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
my_numbox_bang(x); | |||
clock_unset(x->x_clock_reset); | |||
} | |||
static void my_numbox_click(t_my_numbox *x, t_floatarg xpos, t_floatarg ypos, | |||
t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | |||
{ | |||
glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, | |||
(t_glistmotionfn)my_numbox_motion, my_numbox_key, xpos, ypos); | |||
} | |||
static int my_numbox_newclick(t_gobj *z, struct _glist *glist, | |||
int xpix, int ypix, int shift, int alt, int dbl, int doit) | |||
{ | |||
t_my_numbox* x = (t_my_numbox *)z; | |||
if(doit) | |||
{ | |||
my_numbox_click( x, (t_floatarg)xpix, (t_floatarg)ypix, | |||
(t_floatarg)shift, 0, (t_floatarg)alt); | |||
if(shift) | |||
x->x_gui.x_fsf.x_finemoved = 1; | |||
else | |||
x->x_gui.x_fsf.x_finemoved = 0; | |||
if(!x->x_gui.x_fsf.x_change) | |||
{ | |||
clock_delay(x->x_clock_wait, 50); | |||
x->x_gui.x_fsf.x_change = 1; | |||
clock_delay(x->x_clock_reset, 3000); | |||
x->x_buf[0] = 0; | |||
} | |||
else | |||
{ | |||
x->x_gui.x_fsf.x_change = 0; | |||
clock_unset(x->x_clock_reset); | |||
x->x_buf[0] = 0; | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
} | |||
return (1); | |||
} | |||
static void my_numbox_set(t_my_numbox *x, t_floatarg f) | |||
{ | |||
if(x->x_val != f) | |||
{ | |||
x->x_val = f; | |||
my_numbox_clip(x); | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
} | |||
static void my_numbox_log_height(t_my_numbox *x, t_floatarg lh) | |||
{ | |||
if(lh < 10.0) | |||
lh = 10.0; | |||
x->x_log_height = (int)lh; | |||
if(x->x_lin0_log1) | |||
x->x_k = exp(log(x->x_max/x->x_min)/(double)(x->x_log_height)); | |||
else | |||
x->x_k = 1.0; | |||
} | |||
static void my_numbox_float(t_my_numbox *x, t_floatarg f) | |||
{ | |||
my_numbox_set(x, f); | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
my_numbox_bang(x); | |||
} | |||
static void my_numbox_size(t_my_numbox *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
int h, w; | |||
w = (int)atom_getfloatarg(0, ac, av); | |||
if(w < MINDIGITS) | |||
w = MINDIGITS; | |||
x->x_numwidth = w; | |||
if(ac > 1) | |||
{ | |||
h = (int)atom_getfloatarg(1, ac, av); | |||
if(h < IEM_GUI_MINSIZE) | |||
h = IEM_GUI_MINSIZE; | |||
x->x_gui.x_h = h * IEMGUI_ZOOM(x); | |||
} | |||
my_numbox_calc_fontwidth(x); | |||
iemgui_size((void *)x, &x->x_gui); | |||
} | |||
static void my_numbox_delta(t_my_numbox *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void my_numbox_pos(t_my_numbox *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void my_numbox_range(t_my_numbox *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
if(my_numbox_check_minmax(x, (double)atom_getfloatarg(0, ac, av), | |||
(double)atom_getfloatarg(1, ac, av))) | |||
{ | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
/*my_numbox_bang(x);*/ | |||
} | |||
} | |||
static void my_numbox_color(t_my_numbox *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void my_numbox_send(t_my_numbox *x, t_symbol *s) | |||
{iemgui_send(x, &x->x_gui, s);} | |||
static void my_numbox_receive(t_my_numbox *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void my_numbox_label(t_my_numbox *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void my_numbox_label_pos(t_my_numbox *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void my_numbox_label_font(t_my_numbox *x, | |||
t_symbol *s, int ac, t_atom *av) | |||
{ | |||
int f = (int)atom_getfloatarg(1, ac, av); | |||
if(f < 4) | |||
f = 4; | |||
x->x_gui.x_fontsize = f; | |||
f = (int)atom_getfloatarg(0, ac, av); | |||
if((f < 0) || (f > 2)) | |||
f = 0; | |||
x->x_gui.x_fsf.x_font_style = f; | |||
my_numbox_calc_fontwidth(x); | |||
iemgui_label_font((void *)x, &x->x_gui, s, ac, av); | |||
} | |||
static void my_numbox_log(t_my_numbox *x) | |||
{ | |||
x->x_lin0_log1 = 1; | |||
if(my_numbox_check_minmax(x, x->x_min, x->x_max)) | |||
{ | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
/*my_numbox_bang(x);*/ | |||
} | |||
} | |||
static void my_numbox_lin(t_my_numbox *x) | |||
{ | |||
x->x_lin0_log1 = 0; | |||
} | |||
static void my_numbox_init(t_my_numbox *x, t_floatarg f) | |||
{ | |||
x->x_gui.x_isa.x_loadinit = (f == 0.0) ? 0 : 1; | |||
} | |||
static void my_numbox_loadbang(t_my_numbox *x, t_floatarg action) | |||
{ | |||
if(action == LB_LOAD && x->x_gui.x_isa.x_loadinit) | |||
{ | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
my_numbox_bang(x); | |||
} | |||
} | |||
static void my_numbox_key(void *z, t_floatarg fkey) | |||
{ | |||
t_my_numbox *x = z; | |||
char c = fkey; | |||
char buf[3]; | |||
buf[1] = 0; | |||
if(c == 0) | |||
{ | |||
x->x_gui.x_fsf.x_change = 0; | |||
clock_unset(x->x_clock_reset); | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
return; | |||
} | |||
if(((c >= '0') && (c <= '9')) || (c == '.') || (c == '-') || | |||
(c == 'e') || (c == '+') || (c == 'E')) | |||
{ | |||
if(strlen(x->x_buf) < (IEMGUI_MAX_NUM_LEN-2)) | |||
{ | |||
buf[0] = c; | |||
strcat(x->x_buf, buf); | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
} | |||
else if((c == '\b') || (c == 127)) | |||
{ | |||
int sl = (int)strlen(x->x_buf) - 1; | |||
if(sl < 0) | |||
sl = 0; | |||
x->x_buf[sl] = 0; | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
else if((c == '\n') || (c == 13)) | |||
{ | |||
x->x_val = atof(x->x_buf); | |||
x->x_buf[0] = 0; | |||
x->x_gui.x_fsf.x_change = 0; | |||
clock_unset(x->x_clock_reset); | |||
my_numbox_clip(x); | |||
my_numbox_bang(x); | |||
sys_queuegui(x, x->x_gui.x_glist, my_numbox_draw_update); | |||
} | |||
clock_delay(x->x_clock_reset, 3000); | |||
} | |||
static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
if(!ac) { | |||
my_numbox_bang(x); | |||
} | |||
else if(IS_A_FLOAT(av, 0)) | |||
{ | |||
my_numbox_set(x, atom_getfloatarg(0, ac, av)); | |||
my_numbox_bang(x); | |||
} | |||
} | |||
static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_my_numbox *x = (t_my_numbox *)pd_new(my_numbox_class); | |||
int w = 5, h = 14; | |||
int lilo = 0, f = 0, ldx = 0, ldy = -8; | |||
int fs = 10; | |||
int log_height = 256; | |||
double min = -1.0e+37, max = 1.0e+37, v = 0.0; | |||
char str[144]; | |||
x->x_gui.x_bcol = 0xFCFCFC; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x00; | |||
if((argc >= 17)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1) | |||
&&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3) | |||
&&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5) | |||
&&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6)) | |||
&&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7)) | |||
&&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8)) | |||
&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10) | |||
&&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,16)) | |||
{ | |||
w = (int)atom_getfloatarg(0, argc, argv); | |||
h = (int)atom_getfloatarg(1, argc, argv); | |||
min = (double)atom_getfloatarg(2, argc, argv); | |||
max = (double)atom_getfloatarg(3, argc, argv); | |||
lilo = (int)atom_getfloatarg(4, argc, argv); | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(5, argc, argv)); | |||
iemgui_new_getnames(&x->x_gui, 6, argv); | |||
ldx = (int)atom_getfloatarg(9, argc, argv); | |||
ldy = (int)atom_getfloatarg(10, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(11, argc, argv)); | |||
fs = (int)atom_getfloatarg(12, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+13, argv+14, argv+15); | |||
v = atom_getfloatarg(16, argc, argv); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 6, 0); | |||
if((argc == 18)&&IS_A_FLOAT(argv,17)) | |||
{ | |||
log_height = (int)atom_getfloatarg(17, argc, argv); | |||
} | |||
x->x_gui.x_draw = (t_iemfunptr)my_numbox_draw; | |||
x->x_gui.x_fsf.x_snd_able = 1; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if(x->x_gui.x_isa.x_loadinit) | |||
x->x_val = v; | |||
else | |||
x->x_val = 0.0; | |||
if(lilo != 0) lilo = 1; | |||
x->x_lin0_log1 = lilo; | |||
if(log_height < 10) | |||
log_height = 10; | |||
x->x_log_height = log_height; | |||
if(!strcmp(x->x_gui.x_snd->s_name, "empty")) | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) | |||
x->x_gui.x_fsf.x_rcv_able = 0; | |||
if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < MINFONT) | |||
fs = MINFONT; | |||
x->x_gui.x_fontsize = fs; | |||
if(w < MINDIGITS) | |||
w = MINDIGITS; | |||
x->x_numwidth = w; | |||
if(h < IEM_GUI_MINSIZE) | |||
h = IEM_GUI_MINSIZE; | |||
x->x_gui.x_h = h; | |||
x->x_buf[0] = 0; | |||
my_numbox_check_minmax(x, min, max); | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
x->x_clock_reset = clock_new(x, (t_method)my_numbox_tick_reset); | |||
x->x_clock_wait = clock_new(x, (t_method)my_numbox_tick_wait); | |||
x->x_gui.x_fsf.x_change = 0; | |||
iemgui_newzoom(&x->x_gui); | |||
my_numbox_calc_fontwidth(x); | |||
outlet_new(&x->x_gui.x_obj, &s_float); | |||
return (x); | |||
} | |||
static void my_numbox_free(t_my_numbox *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
clock_free(x->x_clock_reset); | |||
clock_free(x->x_clock_wait); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_numbox_setup(void) | |||
{ | |||
my_numbox_class = class_new(gensym("nbx"), (t_newmethod)my_numbox_new, | |||
(t_method)my_numbox_free, sizeof(t_my_numbox), 0, A_GIMME, 0); | |||
class_addcreator((t_newmethod)my_numbox_new, gensym("my_numbox"), A_GIMME, 0); | |||
class_addbang(my_numbox_class, my_numbox_bang); | |||
class_addfloat(my_numbox_class, my_numbox_float); | |||
class_addlist(my_numbox_class, my_numbox_list); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_click, | |||
gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_motion, | |||
gensym("motion"), A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_loadbang, | |||
gensym("loadbang"), A_DEFFLOAT, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_set, | |||
gensym("set"), A_FLOAT, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_range, | |||
gensym("range"), A_GIMME, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_log, | |||
gensym("log"), 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_lin, | |||
gensym("lin"), 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_init, | |||
gensym("init"), A_FLOAT, 0); | |||
class_addmethod(my_numbox_class, (t_method)my_numbox_log_height, | |||
gensym("log_height"), A_FLOAT, 0); | |||
class_addmethod(my_numbox_class, (t_method)iemgui_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
my_numbox_widgetbehavior.w_getrectfn = my_numbox_getrect; | |||
my_numbox_widgetbehavior.w_displacefn = iemgui_displace; | |||
my_numbox_widgetbehavior.w_selectfn = iemgui_select; | |||
my_numbox_widgetbehavior.w_activatefn = NULL; | |||
my_numbox_widgetbehavior.w_deletefn = iemgui_delete; | |||
my_numbox_widgetbehavior.w_visfn = iemgui_vis; | |||
my_numbox_widgetbehavior.w_clickfn = my_numbox_newclick; | |||
class_setwidget(my_numbox_class, &my_numbox_widgetbehavior); | |||
class_sethelpsymbol(my_numbox_class, gensym("numbox2")); | |||
class_setsavefn(my_numbox_class, my_numbox_save); | |||
class_setpropertiesfn(my_numbox_class, my_numbox_properties); | |||
} |
@@ -0,0 +1,811 @@ | |||
/* Copyright (c) 1997-2002 Miller Puckette and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* | |||
Routines to read and write canvases to files: | |||
canvas_savetofile() writes a root canvas to a "pd" file. (Reading "pd" files | |||
is done simply by passing the contents to the pd message interpreter.) | |||
Alternatively, the glist_read() and glist_write() routines read and write | |||
"data" from and to files (reading reads into an existing canvas), using a | |||
file format as in the dialog window for data. | |||
*/ | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include <string.h> | |||
static t_class *declare_class; | |||
void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b); | |||
/* the following routines read "scalars" from a file into a canvas. */ | |||
static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout, | |||
int *p_next) | |||
{ | |||
int i, j; | |||
int indexwas = *p_next; | |||
*p_indexout = indexwas; | |||
if (indexwas >= natoms) | |||
return (0); | |||
for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++) | |||
; | |||
if (i >= natoms) | |||
*p_next = i; | |||
else *p_next = i + 1; | |||
return (i - indexwas); | |||
} | |||
int canvas_readscalar(t_glist *x, int natoms, t_atom *vec, | |||
int *p_nextmsg, int selectit); | |||
static void canvas_readerror(int natoms, t_atom *vec, int message, | |||
int nline, char *s) | |||
{ | |||
error("%s", s); | |||
startpost("line was:"); | |||
postatom(nline, vec + message); | |||
endpost(); | |||
} | |||
/* fill in the contents of the scalar into the vector w. */ | |||
static void glist_readatoms(t_glist *x, int natoms, t_atom *vec, | |||
int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv) | |||
{ | |||
int message, nline, n, i; | |||
t_template *template = template_findbyname(templatesym); | |||
if (!template) | |||
{ | |||
error("%s: no such template", templatesym->s_name); | |||
*p_nextmsg = natoms; | |||
return; | |||
} | |||
word_restore(w, template, argc, argv); | |||
n = template->t_n; | |||
for (i = 0; i < n; i++) | |||
{ | |||
if (template->t_vec[i].ds_type == DT_ARRAY) | |||
{ | |||
int j; | |||
t_array *a = w[i].w_array; | |||
int elemsize = a->a_elemsize, nitems = 0; | |||
t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate; | |||
t_template *arraytemplate = | |||
template_findbyname(arraytemplatesym); | |||
if (!arraytemplate) | |||
{ | |||
error("%s: no such template", arraytemplatesym->s_name); | |||
} | |||
else while (1) | |||
{ | |||
t_word *element; | |||
int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); | |||
/* empty line terminates array */ | |||
if (!nline) | |||
break; | |||
array_resize(a, nitems + 1); | |||
element = (t_word *)(((char *)a->a_vec) + | |||
nitems * elemsize); | |||
glist_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym, | |||
element, nline, vec + message); | |||
nitems++; | |||
} | |||
} | |||
else if (template->t_vec[i].ds_type == DT_TEXT) | |||
{ | |||
t_binbuf *z = binbuf_new(); | |||
int first = *p_nextmsg, last; | |||
for (last = first; last < natoms && vec[last].a_type != A_SEMI; | |||
last++); | |||
binbuf_restore(z, last-first, vec+first); | |||
binbuf_add(w[i].w_binbuf, binbuf_getnatom(z), binbuf_getvec(z)); | |||
binbuf_free(z); | |||
last++; | |||
if (last > natoms) last = natoms; | |||
*p_nextmsg = last; | |||
} | |||
} | |||
} | |||
int canvas_readscalar(t_glist *x, int natoms, t_atom *vec, | |||
int *p_nextmsg, int selectit) | |||
{ | |||
int message, i, j, nline; | |||
t_template *template; | |||
t_symbol *templatesym; | |||
t_scalar *sc; | |||
int nextmsg = *p_nextmsg; | |||
int wasvis = glist_isvisible(x); | |||
if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL) | |||
{ | |||
if (nextmsg < natoms) | |||
post("stopping early: type %d", vec[nextmsg].a_type); | |||
*p_nextmsg = natoms; | |||
return (0); | |||
} | |||
templatesym = canvas_makebindsym(vec[nextmsg].a_w.w_symbol); | |||
*p_nextmsg = nextmsg + 1; | |||
if (!(template = template_findbyname(templatesym))) | |||
{ | |||
error("canvas_read: %s: no such template", templatesym->s_name); | |||
*p_nextmsg = natoms; | |||
return (0); | |||
} | |||
sc = scalar_new(x, templatesym); | |||
if (!sc) | |||
{ | |||
error("couldn't create scalar \"%s\"", templatesym->s_name); | |||
*p_nextmsg = natoms; | |||
return (0); | |||
} | |||
if (wasvis) | |||
{ | |||
/* temporarily lie about vis flag while this is built */ | |||
glist_getcanvas(x)->gl_mapped = 0; | |||
} | |||
glist_add(x, &sc->sc_gobj); | |||
nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg); | |||
glist_readatoms(x, natoms, vec, p_nextmsg, templatesym, sc->sc_vec, | |||
nline, vec + message); | |||
if (wasvis) | |||
{ | |||
/* reset vis flag as before */ | |||
glist_getcanvas(x)->gl_mapped = 1; | |||
gobj_vis(&sc->sc_gobj, x, 1); | |||
} | |||
if (selectit) | |||
{ | |||
glist_select(x, &sc->sc_gobj); | |||
} | |||
return (1); | |||
} | |||
void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(x); | |||
int cr = 0, natoms, nline, message, nextmsg = 0, i, j, nitems; | |||
t_atom *vec; | |||
t_gobj *gobj; | |||
natoms = binbuf_getnatom(b); | |||
vec = binbuf_getvec(b); | |||
/* check for file type */ | |||
nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | |||
if (nline != 1 && vec[message].a_type != A_SYMBOL && | |||
strcmp(vec[message].a_w.w_symbol->s_name, "data")) | |||
{ | |||
pd_error(x, "%s: file apparently of wrong type", filename); | |||
return; | |||
} | |||
/* read in templates and check for consistency */ | |||
while (1) | |||
{ | |||
t_template *newtemplate, *existtemplate; | |||
t_symbol *templatesym; | |||
t_atom *templateargs = getbytes(0); | |||
int ntemplateargs = 0, newnargs; | |||
nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | |||
if (nline < 2) | |||
{ | |||
t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs); | |||
break; | |||
} | |||
else if (nline > 2) | |||
canvas_readerror(natoms, vec, message, nline, | |||
"extra items ignored"); | |||
else if (vec[message].a_type != A_SYMBOL || | |||
strcmp(vec[message].a_w.w_symbol->s_name, "template") || | |||
vec[message + 1].a_type != A_SYMBOL) | |||
{ | |||
canvas_readerror(natoms, vec, message, nline, | |||
"bad template header"); | |||
continue; | |||
} | |||
templatesym = canvas_makebindsym(vec[message + 1].a_w.w_symbol); | |||
while (1) | |||
{ | |||
nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg); | |||
if (nline != 2 && nline != 3) | |||
break; | |||
newnargs = ntemplateargs + nline; | |||
templateargs = (t_atom *)t_resizebytes(templateargs, | |||
sizeof(*templateargs) * ntemplateargs, | |||
sizeof(*templateargs) * newnargs); | |||
templateargs[ntemplateargs] = vec[message]; | |||
templateargs[ntemplateargs + 1] = vec[message + 1]; | |||
if (nline == 3) | |||
templateargs[ntemplateargs + 2] = vec[message + 2]; | |||
ntemplateargs = newnargs; | |||
} | |||
if (!(existtemplate = template_findbyname(templatesym))) | |||
{ | |||
error("%s: template not found in current patch", | |||
templatesym->s_name); | |||
t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs); | |||
return; | |||
} | |||
newtemplate = template_new(templatesym, ntemplateargs, templateargs); | |||
t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs); | |||
if (!template_match(existtemplate, newtemplate)) | |||
{ | |||
error("%s: template doesn't match current one", | |||
templatesym->s_name); | |||
pd_free(&newtemplate->t_pdobj); | |||
return; | |||
} | |||
pd_free(&newtemplate->t_pdobj); | |||
} | |||
while (nextmsg < natoms) | |||
{ | |||
canvas_readscalar(x, natoms, vec, &nextmsg, selectem); | |||
} | |||
} | |||
static void glist_doread(t_glist *x, t_symbol *filename, t_symbol *format, | |||
int clearme) | |||
{ | |||
t_binbuf *b = binbuf_new(); | |||
t_canvas *canvas = glist_getcanvas(x); | |||
int wasvis = glist_isvisible(canvas); | |||
int cr = 0, natoms, nline, message, nextmsg = 0, i, j; | |||
t_atom *vec; | |||
if (!strcmp(format->s_name, "cr")) | |||
cr = 1; | |||
else if (*format->s_name) | |||
error("qlist_read: unknown flag: %s", format->s_name); | |||
if (binbuf_read_via_canvas(b, filename->s_name, canvas, cr)) | |||
{ | |||
pd_error(x, "read failed"); | |||
binbuf_free(b); | |||
return; | |||
} | |||
if (wasvis) | |||
canvas_vis(canvas, 0); | |||
if (clearme) | |||
glist_clear(x); | |||
glist_readfrombinbuf(x, b, filename->s_name, 0); | |||
if (wasvis) | |||
canvas_vis(canvas, 1); | |||
binbuf_free(b); | |||
} | |||
void glist_read(t_glist *x, t_symbol *filename, t_symbol *format) | |||
{ | |||
glist_doread(x, filename, format, 1); | |||
} | |||
void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format) | |||
{ | |||
glist_doread(x, filename, format, 0); | |||
} | |||
/* read text from a "properties" window, called from a gfxstub set | |||
up in scalar_properties(). We try to restore the object; if successful | |||
we either copy the data from the new scalar to the old one in place | |||
(if their templates match) or else delete the old scalar and put the new | |||
thing in its place on the list. */ | |||
void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b) | |||
{ | |||
int ntotal, nnew, scindex; | |||
t_gobj *y, *y2 = 0, *newone, *oldone = 0; | |||
t_template *template; | |||
glist_noselect(x); | |||
for (y = x->gl_list, ntotal = 0, scindex = -1; y; y = y->g_next) | |||
{ | |||
if (y == &sc->sc_gobj) | |||
scindex = ntotal, oldone = y; | |||
ntotal++; | |||
} | |||
if (scindex == -1) | |||
{ | |||
error("data_properties: scalar disappeared"); | |||
return; | |||
} | |||
glist_readfrombinbuf(x, b, "properties dialog", 0); | |||
newone = 0; | |||
/* take the new object off the list */ | |||
if (ntotal) | |||
{ | |||
for (y = x->gl_list, nnew = 1; (y2 = y->g_next); | |||
y = y2, nnew++) | |||
if (nnew == ntotal) | |||
{ | |||
newone = y2; | |||
gobj_vis(newone, x, 0); | |||
y->g_next = y2->g_next; | |||
break; | |||
} | |||
} | |||
else gobj_vis((newone = x->gl_list), x, 0), x->gl_list = newone->g_next; | |||
if (!newone) | |||
error("couldn't update properties (perhaps a format problem?)"); | |||
else if (!oldone) | |||
bug("data_properties: couldn't find old element"); | |||
else if (newone->g_pd == scalar_class && oldone->g_pd == scalar_class | |||
&& ((t_scalar *)newone)->sc_template == | |||
((t_scalar *)oldone)->sc_template | |||
&& (template = template_findbyname(((t_scalar *)newone)->sc_template))) | |||
{ | |||
/* swap new one with old one; then delete new one */ | |||
int i; | |||
for (i = 0; i < template->t_n; i++) | |||
{ | |||
t_word w = ((t_scalar *)newone)->sc_vec[i]; | |||
((t_scalar *)newone)->sc_vec[i] = ((t_scalar *)oldone)->sc_vec[i]; | |||
((t_scalar *)oldone)->sc_vec[i] = w; | |||
} | |||
pd_free(&newone->g_pd); | |||
if (glist_isvisible(x)) | |||
{ | |||
gobj_vis(oldone, x, 0); | |||
gobj_vis(oldone, x, 1); | |||
} | |||
} | |||
else | |||
{ | |||
/* delete old one; put new one where the old one was on glist */ | |||
glist_delete(x, oldone); | |||
if (scindex > 0) | |||
{ | |||
for (y = x->gl_list, nnew = 1; y; | |||
y = y->g_next, nnew++) | |||
if (nnew == scindex || !y->g_next) | |||
{ | |||
newone->g_next = y->g_next; | |||
y->g_next = newone; | |||
goto didit; | |||
} | |||
bug("data_properties: can't reinsert"); | |||
} | |||
else newone->g_next = x->gl_list, x->gl_list = newone; | |||
} | |||
didit: | |||
; | |||
} | |||
/* ----------- routines to write data to a binbuf ----------- */ | |||
void canvas_doaddtemplate(t_symbol *templatesym, | |||
int *p_ntemplates, t_symbol ***p_templatevec) | |||
{ | |||
int n = *p_ntemplates, i; | |||
t_symbol **templatevec = *p_templatevec; | |||
for (i = 0; i < n; i++) | |||
if (templatevec[i] == templatesym) | |||
return; | |||
templatevec = (t_symbol **)t_resizebytes(templatevec, | |||
n * sizeof(*templatevec), (n+1) * sizeof(*templatevec)); | |||
templatevec[n] = templatesym; | |||
*p_templatevec = templatevec; | |||
*p_ntemplates = n+1; | |||
} | |||
static void glist_writelist(t_gobj *y, t_binbuf *b); | |||
void binbuf_savetext(t_binbuf *bfrom, t_binbuf *bto); | |||
void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, | |||
int amarrayelement) | |||
{ | |||
t_dataslot *ds; | |||
t_template *template = template_findbyname(templatesym); | |||
t_atom *a = (t_atom *)t_getbytes(0); | |||
int i, n = template?(template->t_n):0, natom = 0; | |||
if (!amarrayelement) | |||
{ | |||
t_atom templatename; | |||
SETSYMBOL(&templatename, gensym(templatesym->s_name + 3)); | |||
binbuf_add(b, 1, &templatename); | |||
} | |||
if (!template) | |||
bug("canvas_writescalar"); | |||
/* write the atoms (floats and symbols) */ | |||
for (i = 0; i < n; i++) | |||
{ | |||
if (template->t_vec[i].ds_type == DT_FLOAT || | |||
template->t_vec[i].ds_type == DT_SYMBOL) | |||
{ | |||
a = (t_atom *)t_resizebytes(a, | |||
natom * sizeof(*a), (natom + 1) * sizeof (*a)); | |||
if (template->t_vec[i].ds_type == DT_FLOAT) | |||
SETFLOAT(a + natom, w[i].w_float); | |||
else SETSYMBOL(a + natom, w[i].w_symbol); | |||
natom++; | |||
} | |||
} | |||
/* array elements have to have at least something */ | |||
if (natom == 0 && amarrayelement) | |||
SETSYMBOL(a + natom, &s_bang), natom++; | |||
binbuf_add(b, natom, a); | |||
binbuf_addsemi(b); | |||
t_freebytes(a, natom * sizeof(*a)); | |||
for (i = 0; i < n; i++) | |||
{ | |||
if (template->t_vec[i].ds_type == DT_ARRAY) | |||
{ | |||
int j; | |||
t_array *a = w[i].w_array; | |||
int elemsize = a->a_elemsize, nitems = a->a_n; | |||
t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate; | |||
for (j = 0; j < nitems; j++) | |||
canvas_writescalar(arraytemplatesym, | |||
(t_word *)(((char *)a->a_vec) + elemsize * j), b, 1); | |||
binbuf_addsemi(b); | |||
} | |||
else if (template->t_vec[i].ds_type == DT_TEXT) | |||
binbuf_savetext(w[i].w_binbuf, b); | |||
} | |||
} | |||
static void glist_writelist(t_gobj *y, t_binbuf *b) | |||
{ | |||
for (; y; y = y->g_next) | |||
{ | |||
if (pd_class(&y->g_pd) == scalar_class) | |||
{ | |||
canvas_writescalar(((t_scalar *)y)->sc_template, | |||
((t_scalar *)y)->sc_vec, b, 0); | |||
} | |||
} | |||
} | |||
/* ------------ routines to write out templates for data ------- */ | |||
static void canvas_addtemplatesforlist(t_gobj *y, | |||
int *p_ntemplates, t_symbol ***p_templatevec); | |||
static void canvas_addtemplatesforscalar(t_symbol *templatesym, | |||
t_word *w, int *p_ntemplates, t_symbol ***p_templatevec) | |||
{ | |||
t_dataslot *ds; | |||
int i; | |||
t_template *template = template_findbyname(templatesym); | |||
canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec); | |||
if (!template) | |||
bug("canvas_addtemplatesforscalar"); | |||
else for (ds = template->t_vec, i = template->t_n; i--; ds++, w++) | |||
{ | |||
if (ds->ds_type == DT_ARRAY) | |||
{ | |||
int j; | |||
t_array *a = w->w_array; | |||
int elemsize = a->a_elemsize, nitems = a->a_n; | |||
t_symbol *arraytemplatesym = ds->ds_arraytemplate; | |||
canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec); | |||
for (j = 0; j < nitems; j++) | |||
canvas_addtemplatesforscalar(arraytemplatesym, | |||
(t_word *)(((char *)a->a_vec) + elemsize * j), | |||
p_ntemplates, p_templatevec); | |||
} | |||
} | |||
} | |||
static void canvas_addtemplatesforlist(t_gobj *y, | |||
int *p_ntemplates, t_symbol ***p_templatevec) | |||
{ | |||
for (; y; y = y->g_next) | |||
{ | |||
if (pd_class(&y->g_pd) == scalar_class) | |||
{ | |||
canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | |||
((t_scalar *)y)->sc_vec, p_ntemplates, p_templatevec); | |||
} | |||
} | |||
} | |||
/* write all "scalars" in a glist to a binbuf. */ | |||
t_binbuf *glist_writetobinbuf(t_glist *x, int wholething) | |||
{ | |||
int i; | |||
t_symbol **templatevec = getbytes(0); | |||
int ntemplates = 0; | |||
t_gobj *y; | |||
t_binbuf *b = binbuf_new(); | |||
for (y = x->gl_list; y; y = y->g_next) | |||
{ | |||
if ((pd_class(&y->g_pd) == scalar_class) && | |||
(wholething || glist_isselected(x, y))) | |||
{ | |||
canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | |||
((t_scalar *)y)->sc_vec, &ntemplates, &templatevec); | |||
} | |||
} | |||
binbuf_addv(b, "s;", gensym("data")); | |||
for (i = 0; i < ntemplates; i++) | |||
{ | |||
t_template *template = template_findbyname(templatevec[i]); | |||
int j, m = template->t_n; | |||
/* drop "pd-" prefix from template symbol to print it: */ | |||
binbuf_addv(b, "ss;", gensym("template"), | |||
gensym(templatevec[i]->s_name + 3)); | |||
for (j = 0; j < m; j++) | |||
{ | |||
t_symbol *type; | |||
switch (template->t_vec[j].ds_type) | |||
{ | |||
case DT_FLOAT: type = &s_float; break; | |||
case DT_SYMBOL: type = &s_symbol; break; | |||
case DT_ARRAY: type = gensym("array"); break; | |||
case DT_TEXT: type = &s_list; break; | |||
default: type = &s_float; bug("canvas_write"); | |||
} | |||
if (template->t_vec[j].ds_type == DT_ARRAY) | |||
binbuf_addv(b, "sss;", type, template->t_vec[j].ds_name, | |||
gensym(template->t_vec[j].ds_arraytemplate->s_name + 3)); | |||
else binbuf_addv(b, "ss;", type, template->t_vec[j].ds_name); | |||
} | |||
binbuf_addsemi(b); | |||
} | |||
binbuf_addsemi(b); | |||
/* now write out the objects themselves */ | |||
for (y = x->gl_list; y; y = y->g_next) | |||
{ | |||
if ((pd_class(&y->g_pd) == scalar_class) && | |||
(wholething || glist_isselected(x, y))) | |||
{ | |||
canvas_writescalar(((t_scalar *)y)->sc_template, | |||
((t_scalar *)y)->sc_vec, b, 0); | |||
} | |||
} | |||
t_freebytes(templatevec, ntemplates*sizeof(*templatevec)); | |||
return (b); | |||
} | |||
static void glist_write(t_glist *x, t_symbol *filename, t_symbol *format) | |||
{ | |||
int cr = 0, i; | |||
t_binbuf *b; | |||
char buf[MAXPDSTRING]; | |||
t_gobj *y; | |||
t_canvas *canvas = glist_getcanvas(x); | |||
canvas_makefilename(canvas, filename->s_name, buf, MAXPDSTRING); | |||
if (!strcmp(format->s_name, "cr")) | |||
cr = 1; | |||
else if (*format->s_name) | |||
error("qlist_read: unknown flag: %s", format->s_name); | |||
b = glist_writetobinbuf(x, 1); | |||
if (b) | |||
{ | |||
if (binbuf_write(b, buf, "", cr)) | |||
error("%s: write failed", filename->s_name); | |||
binbuf_free(b); | |||
} | |||
} | |||
/* ------ routines to save and restore canvases (patches) recursively. ----*/ | |||
typedef void (*t_zoomfn)(void *x, t_floatarg arg1); | |||
/* save to a binbuf, called recursively; cf. canvas_savetofile() which | |||
saves the document, and is only called on root canvases. */ | |||
static void canvas_saveto(t_canvas *x, t_binbuf *b) | |||
{ | |||
t_gobj *y; | |||
t_linetraverser t; | |||
t_outconnect *oc; | |||
int zoomwas = x->gl_zoom; | |||
if (zoomwas > 1) | |||
{ | |||
t_zoomfn zoommethod = (t_zoomfn)zgetfn(&x->gl_pd, gensym("zoom")); | |||
if (zoommethod) | |||
(*zoommethod)(&x->gl_pd, (t_floatarg)1); | |||
} | |||
/* subpatch */ | |||
if (x->gl_owner && !x->gl_env) | |||
{ | |||
/* have to go to original binbuf to find out how we were named. */ | |||
t_binbuf *bz = binbuf_new(); | |||
t_symbol *patchsym; | |||
binbuf_addbinbuf(bz, x->gl_obj.ob_binbuf); | |||
patchsym = atom_getsymbolarg(1, binbuf_getnatom(bz), binbuf_getvec(bz)); | |||
binbuf_free(bz); | |||
binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"), | |||
(int)(x->gl_screenx1), | |||
(int)(x->gl_screeny1), | |||
(int)(x->gl_screenx2 - x->gl_screenx1), | |||
(int)(x->gl_screeny2 - x->gl_screeny1), | |||
(patchsym != &s_ ? patchsym: gensym("(subpatch)")), | |||
x->gl_mapped); | |||
} | |||
/* root or abstraction */ | |||
else | |||
{ | |||
binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"), | |||
(int)(x->gl_screenx1), | |||
(int)(x->gl_screeny1), | |||
(int)(x->gl_screenx2 - x->gl_screenx1), | |||
(int)(x->gl_screeny2 - x->gl_screeny1), | |||
(int)x->gl_font); | |||
canvas_savedeclarationsto(x, b); | |||
} | |||
for (y = x->gl_list; y; y = y->g_next) | |||
gobj_save(y, b); | |||
linetraverser_start(&t, x); | |||
while ((oc = linetraverser_next(&t))) | |||
{ | |||
int srcno = canvas_getindex(x, &t.tr_ob->ob_g); | |||
int sinkno = canvas_getindex(x, &t.tr_ob2->ob_g); | |||
binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"), | |||
srcno, t.tr_outno, sinkno, t.tr_inno); | |||
} | |||
/* unless everything is the default (as in ordinary subpatches) | |||
print out a "coords" message to set up the coordinate systems */ | |||
if (x->gl_isgraph || x->gl_x1 || x->gl_y1 || | |||
x->gl_x2 != 1 || x->gl_y2 != 1 || x->gl_pixwidth || x->gl_pixheight) | |||
{ | |||
if (x->gl_isgraph && x->gl_goprect) | |||
/* if we have a graph-on-parent rectangle, we're new style. | |||
The format is arranged so | |||
that old versions of Pd can at least do something with it. */ | |||
binbuf_addv(b, "ssfffffffff;", gensym("#X"), gensym("coords"), | |||
x->gl_x1, x->gl_y1, | |||
x->gl_x2, x->gl_y2, | |||
(t_float)x->gl_pixwidth, (t_float)x->gl_pixheight, | |||
(t_float)((x->gl_hidetext)?2.:1.), | |||
(t_float)x->gl_xmargin, (t_float)x->gl_ymargin); | |||
/* otherwise write in 0.38-compatible form */ | |||
else binbuf_addv(b, "ssfffffff;", gensym("#X"), gensym("coords"), | |||
x->gl_x1, x->gl_y1, | |||
x->gl_x2, x->gl_y2, | |||
(t_float)x->gl_pixwidth, (t_float)x->gl_pixheight, | |||
(t_float)x->gl_isgraph); | |||
} | |||
if (zoomwas > 1) | |||
{ | |||
t_zoomfn zoommethod = (t_zoomfn)zgetfn(&x->gl_pd, gensym("zoom")); | |||
if (zoommethod) | |||
(*zoommethod)(&x->gl_pd, (t_floatarg)zoomwas); | |||
} | |||
} | |||
/* call this recursively to collect all the template names for | |||
a canvas or for the selection. */ | |||
static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp, | |||
t_symbol ***templatevecp, int wholething) | |||
{ | |||
t_gobj *y; | |||
for (y = x->gl_list; y; y = y->g_next) | |||
{ | |||
if ((pd_class(&y->g_pd) == scalar_class) && | |||
(wholething || glist_isselected(x, y))) | |||
canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template, | |||
((t_scalar *)y)->sc_vec, ntemplatesp, templatevecp); | |||
else if ((pd_class(&y->g_pd) == canvas_class) && | |||
(wholething || glist_isselected(x, y))) | |||
canvas_collecttemplatesfor((t_canvas *)y, | |||
ntemplatesp, templatevecp, 1); | |||
} | |||
} | |||
/* save the templates needed by a canvas to a binbuf. */ | |||
static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething) | |||
{ | |||
t_symbol **templatevec = getbytes(0); | |||
int i, ntemplates = 0; | |||
t_gobj *y; | |||
canvas_collecttemplatesfor(x, &ntemplates, &templatevec, wholething); | |||
for (i = 0; i < ntemplates; i++) | |||
{ | |||
t_template *template = template_findbyname(templatevec[i]); | |||
int j, m; | |||
if (!template) | |||
{ | |||
bug("canvas_savetemplatesto"); | |||
continue; | |||
} | |||
m = template->t_n; | |||
/* drop "pd-" prefix from template symbol to print */ | |||
binbuf_addv(b, "sss", &s__N, gensym("struct"), | |||
gensym(templatevec[i]->s_name + 3)); | |||
for (j = 0; j < m; j++) | |||
{ | |||
t_symbol *type; | |||
switch (template->t_vec[j].ds_type) | |||
{ | |||
case DT_FLOAT: type = &s_float; break; | |||
case DT_SYMBOL: type = &s_symbol; break; | |||
case DT_ARRAY: type = gensym("array"); break; | |||
case DT_TEXT: type = gensym("text"); break; | |||
default: type = &s_float; bug("canvas_write"); | |||
} | |||
if (template->t_vec[j].ds_type == DT_ARRAY) | |||
binbuf_addv(b, "sss", type, template->t_vec[j].ds_name, | |||
gensym(template->t_vec[j].ds_arraytemplate->s_name + 3)); | |||
else binbuf_addv(b, "ss", type, template->t_vec[j].ds_name); | |||
} | |||
binbuf_addsemi(b); | |||
} | |||
} | |||
void canvas_reload(t_symbol *name, t_symbol *dir, t_glist *except); | |||
/* save a "root" canvas to a file; cf. canvas_saveto() which saves the | |||
body (and which is called recursively.) */ | |||
static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir, | |||
float fdestroy) | |||
{ | |||
t_binbuf *b = binbuf_new(); | |||
canvas_savetemplatesto(x, b, 1); | |||
canvas_saveto(x, b); | |||
if (binbuf_write(b, filename->s_name, dir->s_name, 0)) sys_ouch(); | |||
else | |||
{ | |||
/* if not an abstraction, reset title bar and directory */ | |||
if (!x->gl_owner) | |||
{ | |||
canvas_rename(x, filename, dir); | |||
/* update window list in case Save As changed the window name */ | |||
canvas_updatewindowlist(); | |||
} | |||
post("saved to: %s/%s", dir->s_name, filename->s_name); | |||
canvas_dirty(x, 0); | |||
canvas_reload(filename, dir, x); | |||
if (fdestroy != 0) | |||
vmess(&x->gl_pd, gensym("menuclose"), "f", 1.); | |||
} | |||
binbuf_free(b); | |||
} | |||
static void canvas_menusaveas(t_canvas *x, float fdestroy) | |||
{ | |||
t_canvas *x2 = canvas_getrootfor(x); | |||
sys_vgui("pdtk_canvas_saveas .x%lx {%s} {%s} %d\n", x2, | |||
x2->gl_name->s_name, canvas_getdir(x2)->s_name, (fdestroy != 0)); | |||
} | |||
static void canvas_menusave(t_canvas *x, float fdestroy) | |||
{ | |||
t_canvas *x2 = canvas_getrootfor(x); | |||
char *name = x2->gl_name->s_name; | |||
if (*name && strncmp(name, "Untitled", 8) | |||
&& (strlen(name) < 4 || strcmp(name + strlen(name)-4, ".pat") | |||
|| strcmp(name + strlen(name)-4, ".mxt"))) | |||
{ | |||
canvas_savetofile(x2, x2->gl_name, canvas_getdir(x2), fdestroy); | |||
} | |||
else canvas_menusaveas(x2, fdestroy); | |||
} | |||
void g_readwrite_setup(void) | |||
{ | |||
class_addmethod(canvas_class, (t_method)glist_write, | |||
gensym("write"), A_SYMBOL, A_DEFSYM, A_NULL); | |||
class_addmethod(canvas_class, (t_method)glist_read, | |||
gensym("read"), A_SYMBOL, A_DEFSYM, A_NULL); | |||
class_addmethod(canvas_class, (t_method)glist_mergefile, | |||
gensym("mergefile"), A_SYMBOL, A_DEFSYM, A_NULL); | |||
class_addmethod(canvas_class, (t_method)canvas_savetofile, | |||
gensym("savetofile"), A_SYMBOL, A_SYMBOL, A_DEFFLOAT, 0); | |||
class_addmethod(canvas_class, (t_method)canvas_saveto, | |||
gensym("saveto"), A_CANT, 0); | |||
/* ------------------ from the menu ------------------------- */ | |||
class_addmethod(canvas_class, (t_method)canvas_menusave, | |||
gensym("menusave"), A_DEFFLOAT, 0); | |||
class_addmethod(canvas_class, (t_method)canvas_menusaveas, | |||
gensym("menusaveas"), A_DEFFLOAT, 0); | |||
} | |||
void canvas_readwrite_for_class(t_class *c) | |||
{ | |||
class_addmethod(c, (t_method)canvas_menusave, | |||
gensym("menusave"), A_DEFFLOAT, 0); | |||
class_addmethod(c, (t_method)canvas_menusaveas, | |||
gensym("menusaveas"), A_DEFFLOAT, 0); | |||
} |
@@ -0,0 +1,664 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* changes by Thomas Musil IEM KUG Graz Austria 2001 */ | |||
/* have to insert gui-objects into editor-list */ | |||
/* all changes are labeled with iemlib */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include "g_canvas.h" | |||
#include "s_utf8.h" | |||
#define LMARGIN 2 | |||
#define RMARGIN 2 | |||
#define TMARGIN 3 | |||
#define BMARGIN 2 | |||
#define SEND_FIRST 1 | |||
#define SEND_UPDATE 2 | |||
#define SEND_CHECK 0 | |||
struct _rtext | |||
{ | |||
char *x_buf; /*-- raw byte string, assumed UTF-8 encoded (moo) --*/ | |||
int x_bufsize; /*-- byte length --*/ | |||
int x_selstart; /*-- byte offset --*/ | |||
int x_selend; /*-- byte offset --*/ | |||
int x_active; | |||
int x_dragfrom; | |||
int x_height; | |||
int x_drawnwidth; | |||
int x_drawnheight; | |||
t_text *x_text; | |||
t_glist *x_glist; | |||
char x_tag[50]; | |||
struct _rtext *x_next; | |||
}; | |||
t_rtext *rtext_new(t_glist *glist, t_text *who) | |||
{ | |||
t_rtext *x = (t_rtext *)getbytes(sizeof *x); | |||
int w = 0, h = 0, indx; | |||
x->x_height = -1; | |||
x->x_text = who; | |||
x->x_glist = glist; | |||
x->x_next = glist->gl_editor->e_rtext; | |||
x->x_selstart = x->x_selend = x->x_active = | |||
x->x_drawnwidth = x->x_drawnheight = 0; | |||
binbuf_gettext(who->te_binbuf, &x->x_buf, &x->x_bufsize); | |||
glist->gl_editor->e_rtext = x; | |||
sprintf(x->x_tag, ".x%lx.t%lx", (t_int)glist_getcanvas(x->x_glist), | |||
(t_int)x); | |||
return (x); | |||
} | |||
void rtext_free(t_rtext *x) | |||
{ | |||
if (x->x_glist->gl_editor->e_textedfor == x) | |||
x->x_glist->gl_editor->e_textedfor = 0; | |||
if (x->x_glist->gl_editor->e_rtext == x) | |||
x->x_glist->gl_editor->e_rtext = x->x_next; | |||
else | |||
{ | |||
t_rtext *e2; | |||
for (e2 = x->x_glist->gl_editor->e_rtext; e2; e2 = e2->x_next) | |||
if (e2->x_next == x) | |||
{ | |||
e2->x_next = x->x_next; | |||
break; | |||
} | |||
} | |||
freebytes(x->x_buf, x->x_bufsize); | |||
freebytes(x, sizeof *x); | |||
} | |||
char *rtext_gettag(t_rtext *x) | |||
{ | |||
return (x->x_tag); | |||
} | |||
void rtext_gettext(t_rtext *x, char **buf, int *bufsize) | |||
{ | |||
*buf = x->x_buf; | |||
*bufsize = x->x_bufsize; | |||
} | |||
void rtext_getseltext(t_rtext *x, char **buf, int *bufsize) | |||
{ | |||
*buf = x->x_buf + x->x_selstart; | |||
*bufsize = x->x_selend - x->x_selstart; | |||
} | |||
/* convert t_text te_type symbol for use as a Tk tag */ | |||
static t_symbol *rtext_gettype(t_rtext *x) | |||
{ | |||
switch (x->x_text->te_type) | |||
{ | |||
case T_TEXT: return gensym("text"); | |||
case T_OBJECT: return gensym("obj"); | |||
case T_MESSAGE: return gensym("msg"); | |||
case T_ATOM: return gensym("atom"); | |||
} | |||
return (&s_); | |||
} | |||
/* LATER deal with tcl-significant characters */ | |||
/* firstone(), lastone() | |||
* + returns byte offset of (first|last) occurrence of 'c' in 's[0..n-1]', or | |||
* -1 if none was found | |||
* + 's' is a raw byte string | |||
* + 'c' is a byte value | |||
* + 'n' is the length (in bytes) of the prefix of 's' to be searched. | |||
* + we could make these functions work on logical characters in utf8 strings, | |||
* but we don't really need to... | |||
*/ | |||
static int firstone(char *s, int c, int n) | |||
{ | |||
char *s2 = s + n; | |||
int i = 0; | |||
while (s != s2) | |||
{ | |||
if (*s == c) return (i); | |||
i++; | |||
s++; | |||
} | |||
return (-1); | |||
} | |||
static int lastone(char *s, int c, int n) | |||
{ | |||
char *s2 = s + n; | |||
while (s2 != s) | |||
{ | |||
s2--; | |||
n--; | |||
if (*s2 == c) return (n); | |||
} | |||
return (-1); | |||
} | |||
/* the following routine computes line breaks and carries out | |||
some action which could be: | |||
SEND_FIRST - draw the box for the first time | |||
SEND_UPDATE - redraw the updated box | |||
otherwise - don't draw, just calculate. | |||
Called with *widthp and *heightp as coordinates of | |||
a test point, the routine reports the index of the character found | |||
there in *indexp. *widthp and *heightp are set to the width and height | |||
of the entire text in pixels. | |||
*/ | |||
/*-- moo: | |||
* + some variables from the original version have been renamed | |||
* + variables with a "_b" suffix are raw byte strings, lengths, or offsets | |||
* + variables with a "_c" suffix are logical character lengths or offsets | |||
* (assuming valid UTF-8 encoded byte string in x->x_buf) | |||
* + a fair amount of O(n) computations required to convert between raw byte | |||
* offsets (needed by the C side) and logical character offsets (needed by | |||
* the GUI) | |||
*/ | |||
/* LATER get this and sys_vgui to work together properly, | |||
breaking up messages as needed. As of now, there's | |||
a limit of 1950 characters, imposed by sys_vgui(). */ | |||
#define UPBUFSIZE 4000 | |||
#define BOXWIDTH 60 | |||
static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp, | |||
int *indexp) | |||
{ | |||
t_float dispx, dispy; | |||
char smallbuf[200], *tempbuf; | |||
int outchars_b = 0, nlines = 0, ncolumns = 0, | |||
pixwide, pixhigh, font, fontwidth, fontheight, findx, findy; | |||
int reportedindex = 0; | |||
t_canvas *canvas = glist_getcanvas(x->x_glist); | |||
int widthspec_c = x->x_text->te_width; | |||
int widthlimit_c = (widthspec_c ? widthspec_c : BOXWIDTH); | |||
int inindex_b = 0; | |||
int inindex_c = 0; | |||
int selstart_b = 0, selend_b = 0; | |||
int x_bufsize_c = u8_charnum(x->x_buf, x->x_bufsize); | |||
/* if we're a GOP (the new, "goprect" style) borrow the font size | |||
from the inside to preserve the spacing */ | |||
if (pd_class(&x->x_text->te_pd) == canvas_class && | |||
((t_glist *)(x->x_text))->gl_isgraph && | |||
((t_glist *)(x->x_text))->gl_goprect) | |||
{ | |||
font = glist_getfont((t_glist *)(x->x_text)); | |||
fontwidth = glist_fontwidth((t_glist *)(x->x_text)); | |||
fontheight = glist_fontheight((t_glist *)(x->x_text)); | |||
} | |||
else | |||
{ | |||
font = glist_getfont(x->x_glist); | |||
fontwidth = glist_fontwidth(x->x_glist); | |||
fontheight = glist_fontheight(x->x_glist); | |||
} | |||
findx = (*widthp + (fontwidth/2)) / fontwidth; | |||
findy = *heightp / fontheight; | |||
if (x->x_bufsize >= 100) | |||
tempbuf = (char *)t_getbytes(2 * x->x_bufsize + 1); | |||
else tempbuf = smallbuf; | |||
while (x_bufsize_c - inindex_c > 0) | |||
{ | |||
int inchars_b = x->x_bufsize - inindex_b; | |||
int inchars_c = x_bufsize_c - inindex_c; | |||
int maxindex_c = (inchars_c > widthlimit_c ? widthlimit_c : inchars_c); | |||
int maxindex_b = u8_offset(x->x_buf + inindex_b, maxindex_c); | |||
int eatchar = 1; | |||
int foundit_b = firstone(x->x_buf + inindex_b, '\n', maxindex_b); | |||
int foundit_c; | |||
if (foundit_b < 0) | |||
{ | |||
/* too much text to fit in one line? */ | |||
if (inchars_c > widthlimit_c) | |||
{ | |||
/* is there a space to break the line at? OK if it's even | |||
one byte past the end since in this context we know there's | |||
more text */ | |||
foundit_b = lastone(x->x_buf + inindex_b, ' ', maxindex_b + 1); | |||
if (foundit_b < 0) | |||
{ | |||
foundit_b = maxindex_b; | |||
foundit_c = maxindex_c; | |||
eatchar = 0; | |||
} | |||
else | |||
foundit_c = u8_charnum(x->x_buf + inindex_b, foundit_b); | |||
} | |||
else | |||
{ | |||
foundit_b = inchars_b; | |||
foundit_c = inchars_c; | |||
eatchar = 0; | |||
} | |||
} | |||
else | |||
foundit_c = u8_charnum(x->x_buf + inindex_b, foundit_b); | |||
if (nlines == findy) | |||
{ | |||
int actualx = (findx < 0 ? 0 : | |||
(findx > foundit_c ? foundit_c : findx)); | |||
*indexp = inindex_b + u8_offset(x->x_buf + inindex_b, actualx); | |||
reportedindex = 1; | |||
} | |||
strncpy(tempbuf+outchars_b, x->x_buf + inindex_b, foundit_b); | |||
if (x->x_selstart >= inindex_b && | |||
x->x_selstart <= inindex_b + foundit_b + eatchar) | |||
selstart_b = x->x_selstart + outchars_b - inindex_b; | |||
if (x->x_selend >= inindex_b && | |||
x->x_selend <= inindex_b + foundit_b + eatchar) | |||
selend_b = x->x_selend + outchars_b - inindex_b; | |||
outchars_b += foundit_b; | |||
inindex_b += (foundit_b + eatchar); | |||
inindex_c += (foundit_c + eatchar); | |||
if (inindex_b < x->x_bufsize) | |||
tempbuf[outchars_b++] = '\n'; | |||
if (foundit_c > ncolumns) | |||
ncolumns = foundit_c; | |||
nlines++; | |||
} | |||
if (!reportedindex) | |||
*indexp = outchars_b; | |||
dispx = text_xpix(x->x_text, x->x_glist); | |||
dispy = text_ypix(x->x_text, x->x_glist); | |||
if (nlines < 1) nlines = 1; | |||
if (!widthspec_c) | |||
{ | |||
while (ncolumns < (x->x_text->te_type == T_TEXT ? 1 : 3)) | |||
{ | |||
tempbuf[outchars_b++] = ' '; | |||
ncolumns++; | |||
} | |||
} | |||
else ncolumns = widthspec_c; | |||
pixwide = ncolumns * fontwidth; | |||
pixhigh = nlines * fontheight; | |||
if (glist_getzoom(x->x_glist) > 1) | |||
{ | |||
/* zoom margins */ | |||
pixwide += (LMARGIN + RMARGIN) * glist_getzoom(x->x_glist); | |||
pixhigh += (TMARGIN + BMARGIN) * glist_getzoom(x->x_glist); | |||
} | |||
else | |||
{ | |||
pixwide += LMARGIN + RMARGIN; | |||
pixhigh += TMARGIN + BMARGIN; | |||
} | |||
if (action && x->x_text->te_width && x->x_text->te_type != T_ATOM) | |||
{ | |||
/* if our width is specified but the "natural" width is the | |||
same as the specified width, set specified width to zero | |||
so future text editing will automatically change width. | |||
Except atoms whose content changes at runtime. */ | |||
int widthwas = x->x_text->te_width, newwidth = 0, newheight = 0, | |||
newindex = 0; | |||
x->x_text->te_width = 0; | |||
rtext_senditup(x, 0, &newwidth, &newheight, &newindex); | |||
if (newwidth/fontwidth != widthwas) | |||
x->x_text->te_width = widthwas; | |||
else x->x_text->te_width = 0; | |||
} | |||
if (action == SEND_FIRST) | |||
{ | |||
int lmargin = LMARGIN, tmargin = TMARGIN; | |||
if (glist_getzoom(x->x_glist) > 1) | |||
{ | |||
/* zoom margins */ | |||
lmargin *= glist_getzoom(x->x_glist); | |||
tmargin *= glist_getzoom(x->x_glist); | |||
} | |||
sys_vgui("pdtk_text_new .x%lx.c {%s %s text} %f %f {%.*s} %d %s\n", | |||
canvas, x->x_tag, rtext_gettype(x)->s_name, | |||
dispx + lmargin, dispy + tmargin, | |||
outchars_b, tempbuf, | |||
sys_hostfontsize(font, glist_getzoom(x->x_glist)), | |||
(glist_isselected(x->x_glist, | |||
&x->x_glist->gl_gobj)? "blue" : "black")); | |||
} | |||
else if (action == SEND_UPDATE) | |||
{ | |||
sys_vgui("pdtk_text_set .x%lx.c %s {%.*s}\n", | |||
canvas, x->x_tag, outchars_b, tempbuf); | |||
if (pixwide != x->x_drawnwidth || pixhigh != x->x_drawnheight) | |||
text_drawborder(x->x_text, x->x_glist, x->x_tag, | |||
pixwide, pixhigh, 0); | |||
if (x->x_active) | |||
{ | |||
if (selend_b > selstart_b) | |||
{ | |||
sys_vgui(".x%lx.c select from %s %d\n", canvas, | |||
x->x_tag, u8_charnum(x->x_buf, selstart_b)); | |||
sys_vgui(".x%lx.c select to %s %d\n", canvas, | |||
x->x_tag, u8_charnum(x->x_buf, selend_b) - 1); | |||
sys_vgui(".x%lx.c focus \"\"\n", canvas); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c select clear\n", canvas); | |||
sys_vgui(".x%lx.c icursor %s %d\n", canvas, x->x_tag, | |||
u8_charnum(x->x_buf, selstart_b)); | |||
sys_vgui(".x%lx.c focus %s\n", canvas, x->x_tag); | |||
} | |||
} | |||
} | |||
x->x_drawnwidth = pixwide; | |||
x->x_drawnheight = pixhigh; | |||
*widthp = pixwide; | |||
*heightp = pixhigh; | |||
if (tempbuf != smallbuf) | |||
t_freebytes(tempbuf, 2 * x->x_bufsize + 1); | |||
} | |||
void rtext_retext(t_rtext *x) | |||
{ | |||
int w = 0, h = 0, indx; | |||
t_text *text = x->x_text; | |||
t_freebytes(x->x_buf, x->x_bufsize); | |||
binbuf_gettext(text->te_binbuf, &x->x_buf, &x->x_bufsize); | |||
/* special case: for number boxes, try to pare the number down | |||
to the specified width of the box. */ | |||
if (text->te_width > 0 && text->te_type == T_ATOM && | |||
x->x_bufsize > text->te_width) | |||
{ | |||
t_atom *atomp = binbuf_getvec(text->te_binbuf); | |||
int natom = binbuf_getnatom(text->te_binbuf); | |||
int bufsize = x->x_bufsize; | |||
if (natom == 1 && atomp->a_type == A_FLOAT) | |||
{ | |||
/* try to reduce size by dropping decimal digits */ | |||
int wantreduce = bufsize - text->te_width; | |||
char *decimal = 0, *nextchar, *ebuf = x->x_buf + bufsize, | |||
*s1, *s2; | |||
int ndecimals; | |||
for (decimal = x->x_buf; decimal < ebuf; decimal++) | |||
if (*decimal == '.') | |||
break; | |||
if (decimal >= ebuf) | |||
goto giveup; | |||
for (nextchar = decimal + 1; nextchar < ebuf; nextchar++) | |||
if (*nextchar < '0' || *nextchar > '9') | |||
break; | |||
if (nextchar - decimal - 1 < wantreduce) | |||
goto giveup; | |||
for (s1 = nextchar - wantreduce, s2 = s1 + wantreduce; | |||
s2 < ebuf; s1++, s2++) | |||
*s1 = *s2; | |||
x->x_buf = t_resizebytes(x->x_buf, bufsize, text->te_width); | |||
bufsize = text->te_width; | |||
goto done; | |||
giveup: | |||
/* give up and bash it to "+" or "-" */ | |||
x->x_buf[0] = (atomp->a_w.w_float < 0 ? '-' : '+'); | |||
x->x_buf = t_resizebytes(x->x_buf, bufsize, 1); | |||
bufsize = 1; | |||
} | |||
else if (bufsize > text->te_width) | |||
{ | |||
x->x_buf[text->te_width - 1] = '>'; | |||
x->x_buf = t_resizebytes(x->x_buf, bufsize, text->te_width); | |||
bufsize = text->te_width; | |||
} | |||
done: | |||
x->x_bufsize = bufsize; | |||
} | |||
rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | |||
} | |||
/* find the rtext that goes with a text item */ | |||
t_rtext *glist_findrtext(t_glist *gl, t_text *who) | |||
{ | |||
t_rtext *x; | |||
if (!gl->gl_editor) | |||
canvas_create_editor(gl); | |||
{ | |||
int i = 0; | |||
for (x = gl->gl_editor->e_rtext; x && x->x_text != who; x = x->x_next) | |||
i++; | |||
// post("i=%d", i); | |||
} | |||
for (x = gl->gl_editor->e_rtext; x && x->x_text != who; x = x->x_next) | |||
; | |||
return (x); | |||
} | |||
int rtext_width(t_rtext *x) | |||
{ | |||
int w = 0, h = 0, indx; | |||
rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | |||
return (w); | |||
} | |||
int rtext_height(t_rtext *x) | |||
{ | |||
int w = 0, h = 0, indx; | |||
rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | |||
return (h); | |||
} | |||
void rtext_draw(t_rtext *x) | |||
{ | |||
int w = 0, h = 0, indx; | |||
rtext_senditup(x, SEND_FIRST, &w, &h, &indx); | |||
} | |||
void rtext_erase(t_rtext *x) | |||
{ | |||
sys_vgui(".x%lx.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag); | |||
} | |||
void rtext_displace(t_rtext *x, int dx, int dy) | |||
{ | |||
sys_vgui(".x%lx.c move %s %d %d\n", glist_getcanvas(x->x_glist), | |||
x->x_tag, dx, dy); | |||
} | |||
void rtext_select(t_rtext *x, int state) | |||
{ | |||
t_glist *glist = x->x_glist; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %s -fill %s\n", canvas, | |||
x->x_tag, (state? "blue" : "black")); | |||
} | |||
void rtext_activate(t_rtext *x, int state) | |||
{ | |||
int w = 0, h = 0, indx; | |||
t_glist *glist = x->x_glist; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if (state) | |||
{ | |||
sys_vgui("pdtk_text_editing .x%lx %s 1\n", canvas, x->x_tag); | |||
glist->gl_editor->e_textedfor = x; | |||
glist->gl_editor->e_textdirty = 0; | |||
x->x_dragfrom = x->x_selstart = 0; | |||
x->x_selend = x->x_bufsize; | |||
x->x_active = 1; | |||
} | |||
else | |||
{ | |||
sys_vgui("pdtk_text_editing .x%lx {} 0\n", canvas); | |||
if (glist->gl_editor->e_textedfor == x) | |||
glist->gl_editor->e_textedfor = 0; | |||
x->x_active = 0; | |||
} | |||
rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | |||
} | |||
void rtext_key(t_rtext *x, int keynum, t_symbol *keysym) | |||
{ | |||
int w = 0, h = 0, indx, i, newsize, ndel; | |||
char *s1, *s2; | |||
if (keynum) | |||
{ | |||
int n = keynum; | |||
if (n == '\r') n = '\n'; | |||
if (n == '\b') /* backspace */ | |||
{ | |||
/* LATER delete the box if all text is selected... | |||
this causes reentrancy problems now. */ | |||
/* if ((!x->x_selstart) && (x->x_selend == x->x_bufsize)) | |||
{ | |||
.... | |||
} */ | |||
if (x->x_selstart && (x->x_selstart == x->x_selend)) | |||
u8_dec(x->x_buf, &x->x_selstart); | |||
} | |||
else if (n == 127) /* delete */ | |||
{ | |||
if (x->x_selend < x->x_bufsize && (x->x_selstart == x->x_selend)) | |||
u8_inc(x->x_buf, &x->x_selend); | |||
} | |||
ndel = x->x_selend - x->x_selstart; | |||
for (i = x->x_selend; i < x->x_bufsize; i++) | |||
x->x_buf[i- ndel] = x->x_buf[i]; | |||
newsize = x->x_bufsize - ndel; | |||
x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize); | |||
x->x_bufsize = newsize; | |||
/* at Guenter's suggestion, use 'n>31' to test wither a character might | |||
be printable in whatever 8-bit character set we find ourselves. */ | |||
/*-- moo: | |||
... but test with "<" rather than "!=" in order to accommodate unicode | |||
codepoints for n (which we get since Tk is sending the "%A" substitution | |||
for bind <Key>), effectively reducing the coverage of this clause to 7 | |||
bits. Case n>127 is covered by the next clause. | |||
*/ | |||
if (n == '\n' || (n > 31 && n < 127)) | |||
{ | |||
newsize = x->x_bufsize+1; | |||
x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize); | |||
for (i = x->x_bufsize; i > x->x_selstart; i--) | |||
x->x_buf[i] = x->x_buf[i-1]; | |||
x->x_buf[x->x_selstart] = n; | |||
x->x_bufsize = newsize; | |||
x->x_selstart = x->x_selstart + 1; | |||
} | |||
/*--moo: check for unicode codepoints beyond 7-bit ASCII --*/ | |||
else if (n > 127) | |||
{ | |||
int ch_nbytes = u8_wc_nbytes(n); | |||
newsize = x->x_bufsize + ch_nbytes; | |||
x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize); | |||
for (i = newsize-1; i > x->x_selstart; i--) | |||
x->x_buf[i] = x->x_buf[i-ch_nbytes]; | |||
x->x_bufsize = newsize; | |||
/*-- moo: assume canvas_key() has encoded keysym as UTF-8 */ | |||
strncpy(x->x_buf+x->x_selstart, keysym->s_name, ch_nbytes); | |||
x->x_selstart = x->x_selstart + ch_nbytes; | |||
} | |||
x->x_selend = x->x_selstart; | |||
x->x_glist->gl_editor->e_textdirty = 1; | |||
} | |||
else if (!strcmp(keysym->s_name, "Right")) | |||
{ | |||
if (x->x_selend == x->x_selstart && x->x_selstart < x->x_bufsize) | |||
{ | |||
u8_inc(x->x_buf, &x->x_selstart); | |||
x->x_selend = x->x_selstart; | |||
} | |||
else | |||
x->x_selstart = x->x_selend; | |||
} | |||
else if (!strcmp(keysym->s_name, "Left")) | |||
{ | |||
if (x->x_selend == x->x_selstart && x->x_selstart > 0) | |||
{ | |||
u8_dec(x->x_buf, &x->x_selstart); | |||
x->x_selend = x->x_selstart; | |||
} | |||
else | |||
x->x_selend = x->x_selstart; | |||
} | |||
/* this should be improved... life's too short */ | |||
else if (!strcmp(keysym->s_name, "Up")) | |||
{ | |||
if (x->x_selstart) | |||
u8_dec(x->x_buf, &x->x_selstart); | |||
while (x->x_selstart > 0 && x->x_buf[x->x_selstart] != '\n') | |||
u8_dec(x->x_buf, &x->x_selstart); | |||
x->x_selend = x->x_selstart; | |||
} | |||
else if (!strcmp(keysym->s_name, "Down")) | |||
{ | |||
while (x->x_selend < x->x_bufsize && | |||
x->x_buf[x->x_selend] != '\n') | |||
u8_inc(x->x_buf, &x->x_selend); | |||
if (x->x_selend < x->x_bufsize) | |||
u8_inc(x->x_buf, &x->x_selend); | |||
x->x_selstart = x->x_selend; | |||
} | |||
rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | |||
} | |||
void rtext_mouse(t_rtext *x, int xval, int yval, int flag) | |||
{ | |||
int w = xval, h = yval, indx; | |||
rtext_senditup(x, SEND_CHECK, &w, &h, &indx); | |||
if (flag == RTEXT_DOWN) | |||
{ | |||
x->x_dragfrom = x->x_selstart = x->x_selend = indx; | |||
} | |||
else if (flag == RTEXT_DBL) | |||
{ | |||
int whereseparator, newseparator; | |||
x->x_dragfrom = -1; | |||
whereseparator = 0; | |||
if ((newseparator = lastone(x->x_buf, ' ', indx)) > whereseparator) | |||
whereseparator = newseparator+1; | |||
if ((newseparator = lastone(x->x_buf, '\n', indx)) > whereseparator) | |||
whereseparator = newseparator+1; | |||
if ((newseparator = lastone(x->x_buf, ';', indx)) > whereseparator) | |||
whereseparator = newseparator+1; | |||
if ((newseparator = lastone(x->x_buf, ',', indx)) > whereseparator) | |||
whereseparator = newseparator+1; | |||
x->x_selstart = whereseparator; | |||
whereseparator = x->x_bufsize - indx; | |||
if ((newseparator = | |||
firstone(x->x_buf+indx, ' ', x->x_bufsize - indx)) >= 0 && | |||
newseparator < whereseparator) | |||
whereseparator = newseparator; | |||
if ((newseparator = | |||
firstone(x->x_buf+indx, '\n', x->x_bufsize - indx)) >= 0 && | |||
newseparator < whereseparator) | |||
whereseparator = newseparator; | |||
if ((newseparator = | |||
firstone(x->x_buf+indx, ';', x->x_bufsize - indx)) >= 0 && | |||
newseparator < whereseparator) | |||
whereseparator = newseparator; | |||
if ((newseparator = | |||
firstone(x->x_buf+indx, ',', x->x_bufsize - indx)) >= 0 && | |||
newseparator < whereseparator) | |||
whereseparator = newseparator; | |||
x->x_selend = indx + whereseparator; | |||
} | |||
else if (flag == RTEXT_SHIFT) | |||
{ | |||
if (indx * 2 > x->x_selstart + x->x_selend) | |||
x->x_dragfrom = x->x_selstart, x->x_selend = indx; | |||
else | |||
x->x_dragfrom = x->x_selend, x->x_selstart = indx; | |||
} | |||
else if (flag == RTEXT_DRAG) | |||
{ | |||
if (x->x_dragfrom < 0) | |||
return; | |||
x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx); | |||
x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx); | |||
} | |||
rtext_senditup(x, SEND_UPDATE, &w, &h, &indx); | |||
} |
@@ -0,0 +1,452 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* This file defines the "scalar" object, which is not a text object, just a | |||
"gobj". Scalars have templates which describe their structures, which | |||
can contain numbers, sublists, and arrays. | |||
*/ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> /* for read/write to files */ | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
t_class *scalar_class; | |||
void word_init(t_word *wp, t_template *template, t_gpointer *gp) | |||
{ | |||
int i, nitems = template->t_n; | |||
t_dataslot *datatypes = template->t_vec; | |||
for (i = 0; i < nitems; i++, datatypes++, wp++) | |||
{ | |||
int type = datatypes->ds_type; | |||
if (type == DT_FLOAT) | |||
wp->w_float = 0; | |||
else if (type == DT_SYMBOL) | |||
wp->w_symbol = &s_symbol; | |||
else if (type == DT_ARRAY) | |||
wp->w_array = array_new(datatypes->ds_arraytemplate, gp); | |||
else if (type == DT_TEXT) | |||
wp->w_binbuf = binbuf_new(); | |||
} | |||
} | |||
void word_restore(t_word *wp, t_template *template, | |||
int argc, t_atom *argv) | |||
{ | |||
int i, nitems = template->t_n; | |||
t_dataslot *datatypes = template->t_vec; | |||
for (i = 0; i < nitems; i++, datatypes++, wp++) | |||
{ | |||
int type = datatypes->ds_type; | |||
if (type == DT_FLOAT) | |||
{ | |||
t_float f; | |||
if (argc) | |||
{ | |||
f = atom_getfloat(argv); | |||
argv++, argc--; | |||
} | |||
else f = 0; | |||
wp->w_float = f; | |||
} | |||
else if (type == DT_SYMBOL) | |||
{ | |||
t_symbol *s; | |||
if (argc) | |||
{ | |||
s = atom_getsymbol(argv); | |||
argv++, argc--; | |||
} | |||
else s = &s_; | |||
wp->w_symbol = s; | |||
} | |||
} | |||
if (argc) | |||
post("warning: word_restore: extra arguments"); | |||
} | |||
void word_free(t_word *wp, t_template *template) | |||
{ | |||
int i; | |||
t_dataslot *dt; | |||
for (dt = template->t_vec, i = 0; i < template->t_n; i++, dt++) | |||
{ | |||
if (dt->ds_type == DT_ARRAY) | |||
array_free(wp[i].w_array); | |||
else if (dt->ds_type == DT_TEXT) | |||
binbuf_free(wp[i].w_binbuf); | |||
} | |||
} | |||
static int template_cancreate(t_template *template) | |||
{ | |||
int i, type, nitems = template->t_n; | |||
t_dataslot *datatypes = template->t_vec; | |||
t_template *elemtemplate; | |||
for (i = 0; i < nitems; i++, datatypes++) | |||
if (datatypes->ds_type == DT_ARRAY && | |||
(!(elemtemplate = template_findbyname(datatypes->ds_arraytemplate)) | |||
|| !template_cancreate(elemtemplate))) | |||
{ | |||
error("%s: no such template", datatypes->ds_arraytemplate->s_name); | |||
return (0); | |||
} | |||
return (1); | |||
} | |||
/* make a new scalar and add to the glist. We create a "gp" here which | |||
will be used for array items to point back here. This gp doesn't do | |||
reference counting or "validation" updates though; the parent won't go away | |||
without the contained arrays going away too. The "gp" is copied out | |||
by value in the word_init() routine so we can throw our copy away. */ | |||
t_scalar *scalar_new(t_glist *owner, t_symbol *templatesym) | |||
{ | |||
t_scalar *x; | |||
t_template *template; | |||
t_gpointer gp; | |||
gpointer_init(&gp); | |||
template = template_findbyname(templatesym); | |||
if (!template) | |||
{ | |||
error("scalar: couldn't find template %s", templatesym->s_name); | |||
return (0); | |||
} | |||
if (!template_cancreate(template)) | |||
return (0); | |||
x = (t_scalar *)getbytes(sizeof(t_scalar) + | |||
(template->t_n - 1) * sizeof(*x->sc_vec)); | |||
x->sc_gobj.g_pd = scalar_class; | |||
x->sc_template = templatesym; | |||
gpointer_setglist(&gp, owner, x); | |||
word_init(x->sc_vec, template, &gp); | |||
return (x); | |||
} | |||
/* Pd method to create a new scalar, add it to a glist, and initialize | |||
it from the message arguments. */ | |||
void glist_scalar(t_glist *glist, | |||
t_symbol *classname, int argc, t_atom *argv) | |||
{ | |||
t_symbol *templatesym = | |||
canvas_makebindsym(atom_getsymbolarg(0, argc, argv)); | |||
t_binbuf *b; | |||
int natoms, nextmsg = 0; | |||
t_atom *vec; | |||
if (!template_findbyname(templatesym)) | |||
{ | |||
pd_error(glist, "%s: no such template", | |||
atom_getsymbolarg(0, argc, argv)->s_name); | |||
return; | |||
} | |||
b = binbuf_new(); | |||
binbuf_restore(b, argc, argv); | |||
natoms = binbuf_getnatom(b); | |||
vec = binbuf_getvec(b); | |||
canvas_readscalar(glist, natoms, vec, &nextmsg, 0); | |||
binbuf_free(b); | |||
} | |||
/* -------------------- widget behavior for scalar ------------ */ | |||
void scalar_getbasexy(t_scalar *x, t_float *basex, t_float *basey) | |||
{ | |||
t_template *template = template_findbyname(x->sc_template); | |||
*basex = template_getfloat(template, gensym("x"), x->sc_vec, 0); | |||
*basey = template_getfloat(template, gensym("y"), x->sc_vec, 0); | |||
} | |||
static void scalar_getrect(t_gobj *z, t_glist *owner, | |||
int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_scalar *x = (t_scalar *)z; | |||
t_template *template = template_findbyname(x->sc_template); | |||
t_canvas *templatecanvas = template_findcanvas(template); | |||
int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff; | |||
t_gobj *y; | |||
t_float basex, basey; | |||
scalar_getbasexy(x, &basex, &basey); | |||
/* if someone deleted the template canvas, we're just a point */ | |||
if (!templatecanvas) | |||
{ | |||
x1 = x2 = glist_xtopixels(owner, basex); | |||
y1 = y2 = glist_ytopixels(owner, basey); | |||
} | |||
else | |||
{ | |||
x1 = y1 = 0x7fffffff; | |||
x2 = y2 = -0x7fffffff; | |||
for (y = templatecanvas->gl_list; y; y = y->g_next) | |||
{ | |||
const t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd); | |||
int nx1, ny1, nx2, ny2; | |||
if (!wb) continue; | |||
(*wb->w_parentgetrectfn)(y, owner, | |||
x->sc_vec, template, basex, basey, | |||
&nx1, &ny1, &nx2, &ny2); | |||
if (nx1 < x1) x1 = nx1; | |||
if (ny1 < y1) y1 = ny1; | |||
if (nx2 > x2) x2 = nx2; | |||
if (ny2 > y2) y2 = ny2; | |||
} | |||
if (x2 < x1 || y2 < y1) | |||
x1 = y1 = x2 = y2 = 0; | |||
} | |||
/* post("scalar x1 %d y1 %d x2 %d y2 %d", x1, y1, x2, y2); */ | |||
*xp1 = x1; | |||
*yp1 = y1; | |||
*xp2 = x2; | |||
*yp2 = y2; | |||
} | |||
static void scalar_drawselectrect(t_scalar *x, t_glist *glist, int state) | |||
{ | |||
if (state) | |||
{ | |||
int x1, y1, x2, y2; | |||
scalar_getrect(&x->sc_gobj, glist, &x1, &y1, &x2, &y2); | |||
x1--; x2++; y1--; y2++; | |||
sys_vgui(".x%lx.c create line %d %d %d %d %d %d %d %d %d %d \ | |||
-width 0 -fill blue -tags select%lx\n", | |||
glist_getcanvas(glist), x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, | |||
x); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c delete select%lx\n", glist_getcanvas(glist), x); | |||
} | |||
} | |||
static void scalar_select(t_gobj *z, t_glist *owner, int state) | |||
{ | |||
t_scalar *x = (t_scalar *)z; | |||
t_template *tmpl; | |||
t_symbol *templatesym = x->sc_template; | |||
t_atom at; | |||
t_gpointer gp; | |||
gpointer_init(&gp); | |||
gpointer_setglist(&gp, owner, x); | |||
SETPOINTER(&at, &gp); | |||
if ((tmpl = template_findbyname(templatesym))) | |||
template_notify(tmpl, (state ? gensym("select") : gensym("deselect")), | |||
1, &at); | |||
gpointer_unset(&gp); | |||
scalar_drawselectrect(x, owner, state); | |||
} | |||
static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy) | |||
{ | |||
t_scalar *x = (t_scalar *)z; | |||
t_symbol *templatesym = x->sc_template; | |||
t_template *template = template_findbyname(templatesym); | |||
t_symbol *zz; | |||
t_atom at[3]; | |||
t_gpointer gp; | |||
int xonset, yonset, xtype, ytype, gotx, goty; | |||
if (!template) | |||
{ | |||
error("scalar: couldn't find template %s", templatesym->s_name); | |||
return; | |||
} | |||
gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz); | |||
if (gotx && (xtype != DT_FLOAT)) | |||
gotx = 0; | |||
goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz); | |||
if (goty && (ytype != DT_FLOAT)) | |||
goty = 0; | |||
if (gotx) | |||
*(t_float *)(((char *)(x->sc_vec)) + xonset) += | |||
dx * (glist_pixelstox(glist, 1) - glist_pixelstox(glist, 0)); | |||
if (goty) | |||
*(t_float *)(((char *)(x->sc_vec)) + yonset) += | |||
dy * (glist_pixelstoy(glist, 1) - glist_pixelstoy(glist, 0)); | |||
gpointer_init(&gp); | |||
gpointer_setglist(&gp, glist, x); | |||
SETPOINTER(&at[0], &gp); | |||
SETFLOAT(&at[1], (t_float)dx); | |||
SETFLOAT(&at[2], (t_float)dy); | |||
template_notify(template, gensym("displace"), 2, at); | |||
scalar_redraw(x, glist); | |||
} | |||
static void scalar_activate(t_gobj *z, t_glist *owner, int state) | |||
{ | |||
/* post("scalar_activate %d", state); */ | |||
/* later */ | |||
} | |||
static void scalar_delete(t_gobj *z, t_glist *glist) | |||
{ | |||
/* nothing to do */ | |||
} | |||
static void scalar_vis(t_gobj *z, t_glist *owner, int vis) | |||
{ | |||
t_scalar *x = (t_scalar *)z; | |||
t_template *template = template_findbyname(x->sc_template); | |||
t_canvas *templatecanvas = template_findcanvas(template); | |||
t_gobj *y; | |||
t_float basex, basey; | |||
scalar_getbasexy(x, &basex, &basey); | |||
/* if we don't know how to draw it, make a small rectangle */ | |||
if (!templatecanvas) | |||
{ | |||
if (vis) | |||
{ | |||
int x1 = glist_xtopixels(owner, basex); | |||
int y1 = glist_ytopixels(owner, basey); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags scalar%lx\n", | |||
glist_getcanvas(owner), x1-1, y1-1, x1+1, y1+1, x); | |||
} | |||
else sys_vgui(".x%lx.c delete scalar%lx\n", glist_getcanvas(owner), x); | |||
return; | |||
} | |||
for (y = templatecanvas->gl_list; y; y = y->g_next) | |||
{ | |||
const t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd); | |||
if (!wb) continue; | |||
(*wb->w_parentvisfn)(y, owner, x->sc_vec, template, basex, basey, vis); | |||
} | |||
if (glist_isselected(owner, &x->sc_gobj)) | |||
{ | |||
scalar_drawselectrect(x, owner, 0); | |||
scalar_drawselectrect(x, owner, 1); | |||
} | |||
sys_unqueuegui(x); | |||
} | |||
static void scalar_doredraw(t_gobj *client, t_glist *glist) | |||
{ | |||
if (glist_isvisible(glist)) | |||
{ | |||
scalar_vis(client, glist, 0); | |||
scalar_vis(client, glist, 1); | |||
} | |||
} | |||
void scalar_redraw(t_scalar *x, t_glist *glist) | |||
{ | |||
if (glist_isvisible(glist)) | |||
sys_queuegui(x, glist, scalar_doredraw); | |||
} | |||
extern void template_notifyforscalar(t_template *template, t_glist *owner, | |||
t_scalar *sc, t_symbol *s, int argc, t_atom *argv); | |||
int scalar_doclick(t_word *data, t_template *template, t_scalar *sc, | |||
t_array *ap, struct _glist *owner, | |||
t_float xloc, t_float yloc, int xpix, int ypix, | |||
int shift, int alt, int dbl, int doit) | |||
{ | |||
int hit = 0; | |||
t_canvas *templatecanvas = template_findcanvas(template); | |||
t_gobj *y; | |||
t_atom at[2]; | |||
t_float basex = template_getfloat(template, gensym("x"), data, 0); | |||
t_float basey = template_getfloat(template, gensym("y"), data, 0); | |||
SETFLOAT(at, basex + xloc); | |||
SETFLOAT(at+1, basey + yloc); | |||
if (doit) | |||
template_notifyforscalar(template, owner, | |||
sc, gensym("click"), 2, at); | |||
for (y = templatecanvas->gl_list; y; y = y->g_next) | |||
{ | |||
const t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd); | |||
if (!wb) continue; | |||
if ((hit = (*wb->w_parentclickfn)(y, owner, | |||
data, template, sc, ap, basex + xloc, basey + yloc, | |||
xpix, ypix, shift, alt, dbl, doit))) | |||
return (hit); | |||
} | |||
return (0); | |||
} | |||
static int scalar_click(t_gobj *z, struct _glist *owner, | |||
int xpix, int ypix, int shift, int alt, int dbl, int doit) | |||
{ | |||
t_scalar *x = (t_scalar *)z; | |||
t_template *template = template_findbyname(x->sc_template); | |||
return (scalar_doclick(x->sc_vec, template, x, 0, | |||
owner, 0, 0, xpix, ypix, shift, alt, dbl, doit)); | |||
} | |||
static void scalar_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_scalar *x = (t_scalar *)z; | |||
t_binbuf *b2 = binbuf_new(); | |||
t_atom a, *argv; | |||
int i, argc; | |||
canvas_writescalar(x->sc_template, x->sc_vec, b2, 0); | |||
binbuf_addv(b, "ss", &s__X, gensym("scalar")); | |||
binbuf_addbinbuf(b, b2); | |||
binbuf_addsemi(b); | |||
binbuf_free(b2); | |||
} | |||
static void scalar_properties(t_gobj *z, struct _glist *owner) | |||
{ | |||
t_scalar *x = (t_scalar *)z; | |||
char *buf, buf2[80]; | |||
int bufsize; | |||
t_binbuf *b; | |||
glist_noselect(owner); | |||
glist_select(owner, z); | |||
b = glist_writetobinbuf(owner, 0); | |||
binbuf_gettext(b, &buf, &bufsize); | |||
binbuf_free(b); | |||
buf = t_resizebytes(buf, bufsize, bufsize+1); | |||
buf[bufsize] = 0; | |||
sprintf(buf2, "pdtk_data_dialog %%s {"); | |||
gfxstub_new((t_pd *)owner, x, buf2); | |||
sys_gui(buf); | |||
sys_gui("}\n"); | |||
t_freebytes(buf, bufsize+1); | |||
} | |||
static const t_widgetbehavior scalar_widgetbehavior = | |||
{ | |||
scalar_getrect, | |||
scalar_displace, | |||
scalar_select, | |||
scalar_activate, | |||
scalar_delete, | |||
scalar_vis, | |||
scalar_click, | |||
}; | |||
static void scalar_free(t_scalar *x) | |||
{ | |||
int i; | |||
t_dataslot *datatypes, *dt; | |||
t_symbol *templatesym = x->sc_template; | |||
t_template *template = template_findbyname(templatesym); | |||
sys_unqueuegui(x); | |||
if (!template) | |||
{ | |||
error("scalar: couldn't find template %s", templatesym->s_name); | |||
return; | |||
} | |||
word_free(x->sc_vec, template); | |||
gfxstub_deleteforkey(x); | |||
/* the "size" field in the class is zero, so Pd doesn't try to free | |||
us automatically (see pd_free()) */ | |||
freebytes(x, sizeof(t_scalar) + (template->t_n - 1) * sizeof(*x->sc_vec)); | |||
} | |||
/* ----------------- setup function ------------------- */ | |||
void g_scalar_setup(void) | |||
{ | |||
scalar_class = class_new(gensym("scalar"), 0, (t_method)scalar_free, 0, | |||
CLASS_GOBJ, 0); | |||
class_setwidget(scalar_class, &scalar_widgetbehavior); | |||
class_setsavefn(scalar_class, scalar_save); | |||
class_setpropertiesfn(scalar_class, scalar_properties); | |||
} |
@@ -0,0 +1,520 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
/* --------------- tgl gui-toggle ------------------------- */ | |||
t_widgetbehavior toggle_widgetbehavior; | |||
static t_class *toggle_class; | |||
/* widget helper functions */ | |||
void toggle_draw_update(t_toggle *x, t_glist *glist) | |||
{ | |||
if(glist_isvisible(glist)) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxX1 -fill #%06x\n", canvas, x, | |||
(x->x_on != 0.0) ? x->x_gui.x_fcol : x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxX2 -fill #%06x\n", canvas, x, | |||
(x->x_on != 0.0) ? x->x_gui.x_fcol : x->x_gui.x_bcol); | |||
} | |||
} | |||
void toggle_draw_new(t_toggle *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int crossw = 1, w = x->x_gui.x_w / IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(w >= 30) | |||
crossw = 2; | |||
if(w >= 60) | |||
crossw = 3; | |||
crossw *= IEMGUI_ZOOM(x); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -width %d -fill #%06x -tags %lxBASE\n", | |||
canvas, xpos, ypos, | |||
xpos + x->x_gui.x_w, ypos + x->x_gui.x_h, | |||
IEMGUI_ZOOM(x), | |||
x->x_gui.x_bcol, x); | |||
sys_vgui(".x%lx.c create line %d %d %d %d -width %d -fill #%06x -tags %lxX1\n", | |||
canvas, | |||
xpos + crossw + IEMGUI_ZOOM(x), ypos + crossw + IEMGUI_ZOOM(x), | |||
xpos + x->x_gui.x_w - crossw - IEMGUI_ZOOM(x), ypos + x->x_gui.x_h - crossw - IEMGUI_ZOOM(x), | |||
crossw, (x->x_on != 0.0) ? x->x_gui.x_fcol : x->x_gui.x_bcol, x); | |||
sys_vgui(".x%lx.c create line %d %d %d %d -width %d -fill #%06x -tags %lxX2\n", | |||
canvas, | |||
xpos + crossw + IEMGUI_ZOOM(x), ypos + x->x_gui.x_h - crossw - IEMGUI_ZOOM(x), | |||
xpos + x->x_gui.x_w - crossw - IEMGUI_ZOOM(x), ypos + crossw + IEMGUI_ZOOM(x), | |||
crossw, (x->x_on != 0.0) ? x->x_gui.x_fcol : x->x_gui.x_bcol, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags [list %lxLABEL label text]\n", | |||
canvas, xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
} | |||
void toggle_draw_move(t_toggle *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
int crossw = 1, w = x->x_gui.x_w / IEMGUI_ZOOM(x); | |||
if(w >= 30) | |||
crossw = 2; | |||
if(w >= 60) | |||
crossw = 3; | |||
crossw *= IEMGUI_ZOOM(x); | |||
sys_vgui(".x%lx.c coords %lxBASE %d %d %d %d\n", | |||
canvas, x, xpos, ypos, | |||
xpos + x->x_gui.x_w, ypos + x->x_gui.x_h); | |||
sys_vgui(".x%lx.c itemconfigure %lxX1 -width %d\n", canvas, x, crossw); | |||
sys_vgui(".x%lx.c coords %lxX1 %d %d %d %d\n", | |||
canvas, x, | |||
xpos + crossw + IEMGUI_ZOOM(x), ypos + crossw + IEMGUI_ZOOM(x), | |||
xpos + x->x_gui.x_w - crossw, ypos + x->x_gui.x_h - crossw); | |||
sys_vgui(".x%lx.c itemconfigure %lxX2 -width %d\n", canvas, x, crossw); | |||
sys_vgui(".x%lx.c coords %lxX2 %d %d %d %d\n", | |||
canvas, x, | |||
xpos + crossw + IEMGUI_ZOOM(x), ypos + x->x_gui.x_h - crossw - IEMGUI_ZOOM(x), | |||
xpos + x->x_gui.x_w - crossw, ypos + crossw); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh); | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, | |||
xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
} | |||
void toggle_draw_erase(t_toggle* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxX1\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxX2\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
void toggle_draw_config(t_toggle* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : "")); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -fill #%06x\n", canvas, x, | |||
x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxX1 -fill #%06x\n", canvas, x, | |||
x->x_on ? x->x_gui.x_fcol : x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxX2 -fill #%06x\n", canvas, x, | |||
x->x_on ? x->x_gui.x_fcol : x->x_gui.x_bcol); | |||
} | |||
void toggle_draw_io(t_toggle* x, t_glist* glist, int old_snd_rcv_flags) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able) { | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
/* keep above outlet */ | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxOUT%d\n", canvas, x, x, 0); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able) { | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
/* keep above inlet */ | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxIN%d\n", canvas, x, x, 0); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
void toggle_draw_select(t_toggle* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_NORMAL); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, x->x_gui.x_lcol); | |||
} | |||
} | |||
void toggle_draw(t_toggle *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_UPDATE) | |||
toggle_draw_update(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
toggle_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
toggle_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
toggle_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
toggle_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
toggle_draw_config(x, glist); | |||
else if(mode >= IEM_GUI_DRAW_MODE_IO) | |||
toggle_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO); | |||
} | |||
/* ------------------------ tgl widgetbehaviour----------------------------- */ | |||
static void toggle_getrect(t_gobj *z, t_glist *glist, | |||
int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_toggle *x = (t_toggle *)z; | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist); | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist); | |||
*xp2 = *xp1 + x->x_gui.x_w; | |||
*yp2 = *yp1 + x->x_gui.x_h; | |||
} | |||
static void toggle_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_toggle *x = (t_toggle *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
binbuf_addv(b, "ssiisiisssiiiisssff", gensym("#X"), gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, | |||
(int)x->x_gui.x_obj.te_ypix, | |||
gensym("tgl"), x->x_gui.x_w/IEMGUI_ZOOM(x), | |||
iem_symargstoint(&x->x_gui.x_isa), | |||
srl[0], srl[1], srl[2], | |||
x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[1], bflcol[2], x->x_on, x->x_nonzero); | |||
binbuf_addv(b, ";"); | |||
} | |||
static void toggle_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_toggle *x = (t_toggle *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
iemgui_properties(&x->x_gui, srl); | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |tgl| \ | |||
----------dimensions(pix):----------- %d %d size: 0 0 empty \ | |||
-----------non-zero-value:----------- %g value: 0.0 empty %g \ | |||
-1 lin log %d %d empty %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x #%06x #%06x\n", | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), IEM_GUI_MINSIZE, | |||
x->x_nonzero, 1.0,/*non_zero-schedule*/ | |||
x->x_gui.x_isa.x_loadinit, -1, -1,/*no multi*/ | |||
srl[0]->s_name, srl[1]->s_name, | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
static void toggle_bang(t_toggle *x) | |||
{ | |||
x->x_on = (x->x_on == 0.0) ? x->x_nonzero : 0.0; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, x->x_on); | |||
} | |||
static void toggle_dialog(t_toggle *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int a = (int)atom_getfloatarg(0, argc, argv); | |||
t_float nonzero = (t_float)atom_getfloatarg(2, argc, argv); | |||
int sr_flags; | |||
if(nonzero == 0.0) | |||
nonzero = 1.0; | |||
x->x_nonzero = nonzero; | |||
if(x->x_on != 0.0) | |||
x->x_on = x->x_nonzero; | |||
sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
x->x_gui.x_w = iemgui_clip_size(a) * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
static void toggle_click(t_toggle *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | |||
{toggle_bang(x);} | |||
static int toggle_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit) | |||
{ | |||
if(doit) | |||
toggle_click((t_toggle *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt); | |||
return (1); | |||
} | |||
static void toggle_set(t_toggle *x, t_floatarg f) | |||
{ | |||
int old = (x->x_on != 0); | |||
x->x_on = f; | |||
if (f != 0.0 && pd_compatibilitylevel < 46) | |||
x->x_nonzero = f; | |||
if ((x->x_on != 0) != old) | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
} | |||
static void toggle_float(t_toggle *x, t_floatarg f) | |||
{ | |||
toggle_set(x, f); | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, x->x_on); | |||
} | |||
} | |||
static void toggle_fout(t_toggle *x, t_floatarg f) | |||
{ | |||
toggle_set(x, f); | |||
outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, x->x_on); | |||
} | |||
static void toggle_loadbang(t_toggle *x, t_floatarg action) | |||
{ | |||
if (action == LB_LOAD && x->x_gui.x_isa.x_loadinit) | |||
toggle_fout(x, (t_float)x->x_on); | |||
} | |||
static void toggle_size(t_toggle *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
x->x_gui.x_w = iemgui_clip_size((int)atom_getfloatarg(0, ac, av)) * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
iemgui_size((void *)x, &x->x_gui); | |||
} | |||
static void toggle_delta(t_toggle *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void toggle_pos(t_toggle *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void toggle_color(t_toggle *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void toggle_send(t_toggle *x, t_symbol *s) | |||
{iemgui_send(x, &x->x_gui, s);} | |||
static void toggle_receive(t_toggle *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void toggle_label(t_toggle *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void toggle_label_font(t_toggle *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);} | |||
static void toggle_label_pos(t_toggle *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void toggle_init(t_toggle *x, t_floatarg f) | |||
{ | |||
x->x_gui.x_isa.x_loadinit = (f == 0.0) ? 0 : 1; | |||
} | |||
static void toggle_nonzero(t_toggle *x, t_floatarg f) | |||
{ | |||
if(f != 0.0) | |||
x->x_nonzero = f; | |||
} | |||
static void *toggle_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_toggle *x = (t_toggle *)pd_new(toggle_class); | |||
int a = IEM_GUI_DEFAULTSIZE, f = 0; | |||
int ldx = 17, ldy = 7; | |||
int fs = 10; | |||
t_float on = 0.0, nonzero = 1.0; | |||
char str[144]; | |||
iem_inttosymargs(&x->x_gui.x_isa, 0); | |||
iem_inttofstyle(&x->x_gui.x_fsf, 0); | |||
x->x_gui.x_bcol = 0xFCFCFC; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x00; | |||
if(((argc == 13)||(argc == 14))&&IS_A_FLOAT(argv,0) | |||
&&IS_A_FLOAT(argv,1) | |||
&&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2)) | |||
&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3)) | |||
&&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4)) | |||
&&IS_A_FLOAT(argv,5)&&IS_A_FLOAT(argv,6) | |||
&&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,12)) | |||
{ | |||
a = (int)atom_getfloatarg(0, argc, argv); | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(1, argc, argv)); | |||
iemgui_new_getnames(&x->x_gui, 2, argv); | |||
ldx = (int)atom_getfloatarg(5, argc, argv); | |||
ldy = (int)atom_getfloatarg(6, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(7, argc, argv)); | |||
fs = (int)atom_getfloatarg(8, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+9, argv+10, argv+11); | |||
on = (t_float)atom_getfloatarg(12, argc, argv); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 2, 0); | |||
if((argc == 14)&&IS_A_FLOAT(argv,13)) | |||
nonzero = (t_float)atom_getfloatarg(13, argc, argv); | |||
x->x_gui.x_draw = (t_iemfunptr)toggle_draw; | |||
x->x_gui.x_fsf.x_snd_able = 1; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if (!strcmp(x->x_gui.x_snd->s_name, "empty")) | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
if (!strcmp(x->x_gui.x_rcv->s_name, "empty")) | |||
x->x_gui.x_fsf.x_rcv_able = 0; | |||
if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
x->x_nonzero = (nonzero != 0.0) ? nonzero : 1.0; | |||
if(x->x_gui.x_isa.x_loadinit) | |||
x->x_on = (on != 0.0) ? nonzero : 0.0; | |||
else | |||
x->x_on = 0.0; | |||
if (x->x_gui.x_fsf.x_rcv_able) | |||
pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < 4) | |||
fs = 4; | |||
x->x_gui.x_fontsize = fs; | |||
x->x_gui.x_w = iemgui_clip_size(a); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
iemgui_newzoom(&x->x_gui); | |||
outlet_new(&x->x_gui.x_obj, &s_float); | |||
return (x); | |||
} | |||
static void toggle_ff(t_toggle *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_toggle_setup(void) | |||
{ | |||
toggle_class = class_new(gensym("tgl"), (t_newmethod)toggle_new, | |||
(t_method)toggle_ff, sizeof(t_toggle), 0, A_GIMME, 0); | |||
class_addcreator((t_newmethod)toggle_new, gensym("toggle"), A_GIMME, 0); | |||
class_addbang(toggle_class, toggle_bang); | |||
class_addfloat(toggle_class, toggle_float); | |||
class_addmethod(toggle_class, (t_method)toggle_click, gensym("click"), | |||
A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_dialog, gensym("dialog"), | |||
A_GIMME, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_loadbang, | |||
gensym("loadbang"), A_DEFFLOAT, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_set, gensym("set"), A_FLOAT, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_size, gensym("size"), A_GIMME, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_delta, gensym("delta"), A_GIMME, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_pos, gensym("pos"), A_GIMME, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_color, gensym("color"), A_GIMME, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_send, gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_receive, gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_label, gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_label_pos, gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_label_font, gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_init, gensym("init"), A_FLOAT, 0); | |||
class_addmethod(toggle_class, (t_method)toggle_nonzero, gensym("nonzero"), A_FLOAT, 0); | |||
class_addmethod(toggle_class, (t_method)iemgui_zoom, gensym("zoom"), | |||
A_CANT, 0); | |||
toggle_widgetbehavior.w_getrectfn = toggle_getrect; | |||
toggle_widgetbehavior.w_displacefn = iemgui_displace; | |||
toggle_widgetbehavior.w_selectfn = iemgui_select; | |||
toggle_widgetbehavior.w_activatefn = NULL; | |||
toggle_widgetbehavior.w_deletefn = iemgui_delete; | |||
toggle_widgetbehavior.w_visfn = iemgui_vis; | |||
toggle_widgetbehavior.w_clickfn = toggle_newclick; | |||
class_setwidget(toggle_class, &toggle_widgetbehavior); | |||
class_sethelpsymbol(toggle_class, gensym("toggle")); | |||
class_setsavefn(toggle_class, toggle_save); | |||
class_setpropertiesfn(toggle_class, toggle_properties); | |||
} |
@@ -0,0 +1,767 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* vdial.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* name change to vradio by MSP (it's a radio button really) and changed to | |||
put out a "float" as in sliders, toggles, etc. */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
/* ------------- vdl gui-vertical radio button ---------------------- */ | |||
t_widgetbehavior vradio_widgetbehavior; | |||
static t_class *vradio_class, *vradio_old_class; | |||
/* widget helper functions */ | |||
void vradio_draw_update(t_gobj *client, t_glist *glist) | |||
{ | |||
t_hradio *x = (t_hradio *)client; | |||
if(glist_isvisible(glist)) | |||
{ | |||
t_canvas *canvas=glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT%d -fill #%06x -outline #%06x\n", | |||
canvas, x, x->x_drawn, | |||
x->x_gui.x_bcol, x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT%d -fill #%06x -outline #%06x\n", | |||
canvas, x, x->x_on, | |||
x->x_gui.x_fcol, x->x_gui.x_fcol); | |||
x->x_drawn = x->x_on; | |||
} | |||
} | |||
void vradio_draw_new(t_vradio *x, t_glist *glist) | |||
{ | |||
int n = x->x_number, i, dy = x->x_gui.x_h, s4 = dy / 4; | |||
int yy11b = text_ypix(&x->x_gui.x_obj, glist); | |||
int yy11 = yy11b, yy12 = yy11 + dy; | |||
int yy21 = yy11 + s4, yy22 = yy12 - s4; | |||
int xx11 = text_xpix(&x->x_gui.x_obj, glist), xx12 = xx11 + dy; | |||
int xx21 = xx11 + s4, xx22 = xx12 - s4; | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -width %d -fill #%06x -tags %lxBASE%d\n", | |||
canvas, xx11, yy11, xx12, yy12, IEMGUI_ZOOM(x), | |||
x->x_gui.x_bcol, x, i); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill #%06x -outline #%06x -tags %lxBUT%d\n", | |||
canvas, xx21, yy21, xx22, yy22, | |||
(x->x_on == i) ? x->x_gui.x_fcol : x->x_gui.x_bcol, | |||
(x->x_on == i) ? x->x_gui.x_fcol : x->x_gui.x_bcol, x, i); | |||
yy11 += dy; | |||
yy12 += dy; | |||
yy21 += dy; | |||
yy22 += dy; | |||
x->x_drawn = x->x_on; | |||
} | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]\n", | |||
canvas, | |||
xx11, yy11 + IEMGUI_ZOOM(x) - ioh, | |||
xx11 + iow, yy11, | |||
x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xx11, yy11b, | |||
xx11 + iow, yy11b - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w -font {{%s} -%d %s} -fill #%06x -tags [list %lxLABEL label text]\n", | |||
canvas, xx11 + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
yy11b + x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
} | |||
void vradio_draw_move(t_vradio *x, t_glist *glist) | |||
{ | |||
int n = x->x_number, i, dy = x->x_gui.x_h, s4 = dy / 4; | |||
int yy11b = text_ypix(&x->x_gui.x_obj, glist); | |||
int yy11 = yy11b, yy12 = yy11 + dy; | |||
int yy21 = yy11 + s4, yy22 = yy12 - s4; | |||
int xx11 = text_xpix(&x->x_gui.x_obj, glist), xx12 = xx11 + dy; | |||
int xx21 = xx11 + s4, xx22 = xx12 - s4; | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c coords %lxBASE%d %d %d %d %d\n", | |||
canvas, x, i, xx11, yy11, xx12, yy12); | |||
sys_vgui(".x%lx.c coords %lxBUT%d %d %d %d %d\n", | |||
canvas, x, i, xx21, yy21, xx22, yy22); | |||
yy11 += dy; | |||
yy12 += dy; | |||
yy21 += dy; | |||
yy22 += dy; | |||
} | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xx11, yy11 + IEMGUI_ZOOM(x) - ioh, | |||
xx11 + iow, yy11); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xx11, yy11b, | |||
xx11 + iow, yy11b - IEMGUI_ZOOM(x) + ioh); | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, xx11 + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
yy11b + x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
} | |||
void vradio_draw_erase(t_vradio* x, t_glist* glist) | |||
{ | |||
int n = x->x_number, i; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c delete %lxBASE%d\n", canvas, x, i); | |||
sys_vgui(".x%lx.c delete %lxBUT%d\n", canvas, x, i); | |||
} | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
void vradio_draw_config(t_vradio* x, t_glist* glist) | |||
{ | |||
int n = x->x_number, i; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol, | |||
strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""); | |||
for(i=0; i<n; i++) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE%d -fill #%06x\n", canvas, x, i, | |||
x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBUT%d -fill #%06x -outline #%06x\n", canvas, x, i, | |||
(x->x_on == i) ? x->x_gui.x_fcol : x->x_gui.x_bcol, | |||
(x->x_on == i) ? x->x_gui.x_fcol : x->x_gui.x_bcol); | |||
} | |||
} | |||
void vradio_draw_io(t_vradio* x, t_glist* glist, int old_snd_rcv_flags) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h, | |||
x, 0); | |||
/* keep these above outlet */ | |||
if(x->x_on == 0) { | |||
sys_vgui(".x%lx.c raise %lxBUT%d %lxOUT%d\n", canvas, x, x->x_on, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxBUT%d\n", canvas, x, x, x->x_on); | |||
} | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos, ypos, | |||
xpos + iow, ypos - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
/* keep these above inlet */ | |||
if(x->x_on == 0) { | |||
sys_vgui(".x%lx.c raise %lxBUT%d %lxIN%d\n", canvas, x, x->x_on, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxBUT%d\n", canvas, x, x, x->x_on); | |||
} | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
void vradio_draw_select(t_vradio* x, t_glist* glist) | |||
{ | |||
int n = x->x_number, i; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE%d -outline #%06x\n", canvas, x, i, | |||
IEM_GUI_COLOR_SELECTED); | |||
} | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
for(i = 0; i < n; i++) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE%d -outline #%06x\n", canvas, x, i, | |||
IEM_GUI_COLOR_NORMAL); | |||
} | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, | |||
x->x_gui.x_lcol); | |||
} | |||
} | |||
void vradio_draw(t_vradio *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_UPDATE) | |||
sys_queuegui(x, glist, vradio_draw_update); | |||
else if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
vradio_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
vradio_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
vradio_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
vradio_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
vradio_draw_config(x, glist); | |||
else if(mode >= IEM_GUI_DRAW_MODE_IO) | |||
vradio_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO); | |||
} | |||
/* ------------------------ vdl widgetbehaviour----------------------------- */ | |||
static void vradio_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_vradio *x = (t_vradio *)z; | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist); | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist); | |||
*xp2 = *xp1 + x->x_gui.x_w; | |||
*yp2 = *yp1 + x->x_gui.x_h * x->x_number; | |||
} | |||
static void vradio_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_vradio *x = (t_vradio *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
binbuf_addv(b, "ssiisiiiisssiiiisssf", gensym("#X"), gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, | |||
(int)x->x_gui.x_obj.te_ypix, | |||
(pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class ? | |||
gensym("vdl") : gensym("vradio")), | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), | |||
x->x_change, iem_symargstoint(&x->x_gui.x_isa), x->x_number, | |||
srl[0], srl[1], srl[2], | |||
x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[1], bflcol[2], x->x_fval); | |||
binbuf_addv(b, ";"); | |||
} | |||
static void vradio_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_vradio *x = (t_vradio *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
int hchange = -1; | |||
iemgui_properties(&x->x_gui, srl); | |||
if(pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class) | |||
hchange = x->x_change; | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |vradio| \ | |||
----------dimensions(pix):----------- %d %d size: 0 0 empty \ | |||
empty 0.0 empty 0.0 empty %d \ | |||
%d new-only new&old %d %d number: %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x #%06x #%06x\n", | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), IEM_GUI_MINSIZE, | |||
0,/*no_schedule*/ | |||
hchange, x->x_gui.x_isa.x_loadinit, -1, x->x_number, | |||
srl[0]->s_name, srl[1]->s_name, | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
static void vradio_dialog(t_vradio *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int a = (int)atom_getfloatarg(0, argc, argv); | |||
int chg = (int)atom_getfloatarg(4, argc, argv); | |||
int num = (int)atom_getfloatarg(6, argc, argv); | |||
int sr_flags; | |||
if(chg != 0) chg = 1; | |||
x->x_change = chg; | |||
sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
x->x_gui.x_w = iemgui_clip_size(a) * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
if(x->x_number != num) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE); | |||
x->x_number = num; | |||
if(x->x_on >= x->x_number) | |||
{ | |||
x->x_on = x->x_number - 1; | |||
x->x_on_old = x->x_on; | |||
} | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW); | |||
} | |||
else | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
} | |||
static void vradio_set(t_vradio *x, t_floatarg f) | |||
{ | |||
int i = (int)f; | |||
int old; | |||
x->x_fval = f; | |||
if(i < 0) | |||
i = 0; | |||
if(i >= x->x_number) | |||
i = x->x_number - 1; | |||
if(x->x_on != x->x_on_old) | |||
{ | |||
old = x->x_on_old; | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
x->x_on_old = old; | |||
} | |||
else | |||
{ | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
} | |||
} | |||
static void vradio_bang(t_vradio *x) | |||
{ | |||
/* compatibility with earlier "vdial" behavior */ | |||
if(pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class) | |||
{ | |||
if((x->x_change) && (x->x_on != x->x_on_old)) | |||
{ | |||
SETFLOAT(x->x_at, (t_float)x->x_on_old); | |||
SETFLOAT(x->x_at+1, 0.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
x->x_on_old = x->x_on; | |||
SETFLOAT(x->x_at, (t_float)x->x_on); | |||
SETFLOAT(x->x_at+1, 1.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
else | |||
{ | |||
float outval = (pd_compatibilitylevel < 46 ? x->x_on : x->x_fval); | |||
outlet_float(x->x_gui.x_obj.ob_outlet, outval); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, outval); | |||
} | |||
} | |||
static void vradio_fout(t_vradio *x, t_floatarg f) | |||
{ | |||
int i = (int)f; | |||
x->x_fval = f; | |||
if(i < 0) | |||
i = 0; | |||
if(i >= x->x_number) | |||
i = x->x_number - 1; | |||
if(pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class) | |||
{ | |||
/* compatibility with earlier "vdial" behavior */ | |||
if((x->x_change) && (i != x->x_on_old)) | |||
{ | |||
SETFLOAT(x->x_at, (t_float)x->x_on_old); | |||
SETFLOAT(x->x_at+1, 0.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
if(x->x_on != x->x_on_old) | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
x->x_on_old = x->x_on; | |||
SETFLOAT(x->x_at, (t_float)x->x_on); | |||
SETFLOAT(x->x_at+1, 1.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
else | |||
{ | |||
float outval = (pd_compatibilitylevel < 46 ? i : x->x_fval); | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
outlet_float(x->x_gui.x_obj.ob_outlet, outval); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, outval); | |||
} | |||
} | |||
static void vradio_float(t_vradio *x, t_floatarg f) | |||
{ | |||
int i = (int)f; | |||
x->x_fval = f; | |||
if(i < 0) | |||
i = 0; | |||
if(i >= x->x_number) | |||
i = x->x_number - 1; | |||
if(pd_class(&x->x_gui.x_obj.ob_pd) == vradio_old_class) | |||
{ | |||
/* compatibility with earlier "vdial" behavior */ | |||
if((x->x_change) && (i != x->x_on_old)) | |||
{ | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
SETFLOAT(x->x_at, (t_float)x->x_on_old); | |||
SETFLOAT(x->x_at+1, 0.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
} | |||
if(x->x_on != x->x_on_old) | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
x->x_on_old = x->x_on; | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
SETFLOAT(x->x_at, (t_float)x->x_on); | |||
SETFLOAT(x->x_at+1, 1.0); | |||
outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at); | |||
} | |||
} | |||
else | |||
{ | |||
float outval = (pd_compatibilitylevel < 46 ? i : x->x_fval); | |||
x->x_on_old = x->x_on; | |||
x->x_on = i; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
{ | |||
outlet_float(x->x_gui.x_obj.ob_outlet, outval); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, outval); | |||
} | |||
} | |||
} | |||
static void vradio_click(t_vradio *x, t_floatarg xpos, t_floatarg ypos, | |||
t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | |||
{ | |||
int yy = (int)ypos - text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist); | |||
vradio_fout(x, (t_float)(yy / x->x_gui.x_h)); | |||
} | |||
static int vradio_newclick(t_gobj *z, struct _glist *glist, | |||
int xpix, int ypix, int shift, int alt, int dbl, int doit) | |||
{ | |||
if(doit) | |||
vradio_click((t_vradio *)z, (t_floatarg)xpix, (t_floatarg)ypix, | |||
(t_floatarg)shift, 0, (t_floatarg)alt); | |||
return (1); | |||
} | |||
static void vradio_loadbang(t_vradio *x, t_floatarg action) | |||
{ | |||
if(action == LB_LOAD && x->x_gui.x_isa.x_loadinit) | |||
vradio_bang(x); | |||
} | |||
static void vradio_number(t_vradio *x, t_floatarg num) | |||
{ | |||
int n = (int)num; | |||
if(n < 1) | |||
n = 1; | |||
if(n > IEM_RADIO_MAX) | |||
n = IEM_RADIO_MAX; | |||
if(n != x->x_number) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE); | |||
x->x_number = n; | |||
if(x->x_on >= x->x_number) | |||
x->x_on = x->x_number - 1; | |||
x->x_on_old = x->x_on; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
} | |||
static void vradio_size(t_vradio *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
x->x_gui.x_w = iemgui_clip_size((int)atom_getfloatarg(0, ac, av)) * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
iemgui_size((void *)x, &x->x_gui); | |||
} | |||
static void vradio_delta(t_vradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void vradio_pos(t_vradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void vradio_color(t_vradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void vradio_send(t_vradio *x, t_symbol *s) | |||
{iemgui_send(x, &x->x_gui, s);} | |||
static void vradio_receive(t_vradio *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void vradio_label(t_vradio *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void vradio_label_pos(t_vradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void vradio_label_font(t_vradio *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);} | |||
static void vradio_init(t_vradio *x, t_floatarg f) | |||
{x->x_gui.x_isa.x_loadinit = (f == 0.0) ? 0 : 1;} | |||
static void vradio_double_change(t_vradio *x) | |||
{x->x_change = 1;} | |||
static void vradio_single_change(t_vradio *x) | |||
{x->x_change = 0;} | |||
static void *vradio_donew(t_symbol *s, int argc, t_atom *argv, int old) | |||
{ | |||
t_vradio *x = (t_vradio *)pd_new(old ? vradio_old_class : vradio_class); | |||
int a = IEM_GUI_DEFAULTSIZE, on = 0, f = 0; | |||
int ldx = 0, ldy = -8, chg = 1, num = 8; | |||
int fs = 10; | |||
int ftbreak = IEM_BNG_DEFAULTBREAKFLASHTIME, fthold = IEM_BNG_DEFAULTHOLDFLASHTIME; | |||
char str[144]; | |||
float fval = 0; | |||
x->x_gui.x_bcol = 0xFCFCFC; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x00; | |||
if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2) | |||
&&IS_A_FLOAT(argv,3) | |||
&&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4)) | |||
&&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5)) | |||
&&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6)) | |||
&&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8) | |||
&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,14)) | |||
{ | |||
a = (int)atom_getfloatarg(0, argc, argv); | |||
chg = (int)atom_getfloatarg(1, argc, argv); | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(2, argc, argv)); | |||
num = (int)atom_getfloatarg(3, argc, argv); | |||
iemgui_new_getnames(&x->x_gui, 4, argv); | |||
ldx = (int)atom_getfloatarg(7, argc, argv); | |||
ldy = (int)atom_getfloatarg(8, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(9, argc, argv)); | |||
fs = (int)atom_getfloatarg(10, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+11, argv+12, argv+13); | |||
fval = atom_getfloatarg(14, argc, argv); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 4, 0); | |||
x->x_gui.x_draw = (t_iemfunptr)vradio_draw; | |||
x->x_gui.x_fsf.x_snd_able = 1; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if(!strcmp(x->x_gui.x_snd->s_name, "empty")) | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) | |||
x->x_gui.x_fsf.x_rcv_able = 0; | |||
if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
if(num < 1) | |||
num = 1; | |||
if(num > IEM_RADIO_MAX) | |||
num = IEM_RADIO_MAX; | |||
x->x_number = num; | |||
x->x_fval = fval; | |||
on = fval; | |||
if(on < 0) | |||
on = 0; | |||
if(on >= x->x_number) | |||
on = x->x_number - 1; | |||
if(x->x_gui.x_isa.x_loadinit) | |||
x->x_on = on; | |||
else | |||
x->x_on = 0; | |||
x->x_on_old = x->x_on; | |||
x->x_change = (chg == 0) ? 0 : 1; | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < 4) | |||
fs = 4; | |||
x->x_gui.x_fontsize = fs; | |||
x->x_gui.x_w = iemgui_clip_size(a); | |||
x->x_gui.x_h = x->x_gui.x_w; | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
iemgui_newzoom(&x->x_gui); | |||
outlet_new(&x->x_gui.x_obj, &s_list); | |||
return (x); | |||
} | |||
static void *vradio_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
return (vradio_donew(s, argc, argv, 0)); | |||
} | |||
static void *vdial_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
return (vradio_donew(s, argc, argv, 1)); | |||
} | |||
static void vradio_ff(t_vradio *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_vradio_setup(void) | |||
{ | |||
vradio_class = class_new(gensym("vradio"), (t_newmethod)vradio_new, | |||
(t_method)vradio_ff, sizeof(t_vradio), 0, A_GIMME, 0); | |||
class_addbang(vradio_class, vradio_bang); | |||
class_addfloat(vradio_class, vradio_float); | |||
class_addmethod(vradio_class, (t_method)vradio_click, | |||
gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_loadbang, | |||
gensym("loadbang"), A_DEFFLOAT, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_set, | |||
gensym("set"), A_FLOAT, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_init, | |||
gensym("init"), A_FLOAT, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_number, | |||
gensym("number"), A_FLOAT, 0); | |||
class_addmethod(vradio_class, (t_method)vradio_single_change, | |||
gensym("single_change"), 0); | |||
class_addmethod(vradio_class, (t_method)vradio_double_change, | |||
gensym("double_change"), 0); | |||
class_addmethod(vradio_class, (t_method)iemgui_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
vradio_widgetbehavior.w_getrectfn = vradio_getrect; | |||
vradio_widgetbehavior.w_displacefn = iemgui_displace; | |||
vradio_widgetbehavior.w_selectfn = iemgui_select; | |||
vradio_widgetbehavior.w_activatefn = NULL; | |||
vradio_widgetbehavior.w_deletefn = iemgui_delete; | |||
vradio_widgetbehavior.w_visfn = iemgui_vis; | |||
vradio_widgetbehavior.w_clickfn = vradio_newclick; | |||
class_setwidget(vradio_class, &vradio_widgetbehavior); | |||
class_sethelpsymbol(vradio_class, gensym("vradio")); | |||
class_setsavefn(vradio_class, vradio_save); | |||
class_setpropertiesfn(vradio_class, vradio_properties); | |||
/* obsolete version (0.34-0.35) */ | |||
vradio_old_class = class_new(gensym("vdl"), (t_newmethod)vdial_new, | |||
(t_method)vradio_ff, sizeof(t_vradio), 0, A_GIMME, 0); | |||
class_addbang(vradio_old_class, vradio_bang); | |||
class_addfloat(vradio_old_class, vradio_float); | |||
class_addmethod(vradio_old_class, (t_method)vradio_click, | |||
gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_loadbang, | |||
gensym("loadbang"), 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_set, | |||
gensym("set"), A_FLOAT, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_init, | |||
gensym("init"), A_FLOAT, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_number, | |||
gensym("number"), A_FLOAT, 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_single_change, | |||
gensym("single_change"), 0); | |||
class_addmethod(vradio_old_class, (t_method)vradio_double_change, | |||
gensym("double_change"), 0); | |||
class_addmethod(vradio_old_class, (t_method)iemgui_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
class_setwidget(vradio_old_class, &vradio_widgetbehavior); | |||
class_sethelpsymbol(vradio_old_class, gensym("vradio")); | |||
} |
@@ -0,0 +1,690 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
#define TMARGIN 2 | |||
#define BMARGIN 3 | |||
/* ------------ vsl gui-vertical slider ----------------------- */ | |||
t_widgetbehavior vslider_widgetbehavior; | |||
static t_class *vslider_class; | |||
/* widget helper functions */ | |||
static void vslider_draw_update(t_gobj *client, t_glist *glist) | |||
{ | |||
t_vslider *x = (t_vslider *)client; | |||
if (glist_isvisible(glist)) | |||
{ | |||
int r = text_ypix(&x->x_gui.x_obj, glist) + x->x_gui.x_h - | |||
((x->x_val + 50)/100); | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
sys_vgui(".x%lx.c coords %lxKNOB %d %d %d %d\n", | |||
glist_getcanvas(glist), x, xpos + IEMGUI_ZOOM(x), r, | |||
xpos + x->x_gui.x_w - IEMGUI_ZOOM(x), r); | |||
} | |||
} | |||
static void vslider_draw_new(t_vslider *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int tmargin = TMARGIN * IEMGUI_ZOOM(x), bmargin = BMARGIN * IEMGUI_ZOOM(x); | |||
int r = ypos + x->x_gui.x_h - ((x->x_val + 50)/100); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -width %d -fill #%06x -tags %lxBASE\n", | |||
canvas, xpos, ypos - tmargin, | |||
xpos + x->x_gui.x_w, ypos + x->x_gui.x_h + bmargin, | |||
IEMGUI_ZOOM(x), | |||
x->x_gui.x_bcol, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + bmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h + bmargin, | |||
x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xpos, ypos - tmargin, | |||
xpos + iow, ypos - tmargin - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
sys_vgui(".x%lx.c create line %d %d %d %d -width %d -fill #%06x -tags %lxKNOB\n", | |||
canvas, xpos + IEMGUI_ZOOM(x), r, | |||
xpos + x->x_gui.x_w - IEMGUI_ZOOM(x), r, | |||
1 + 2 * IEMGUI_ZOOM(x), x->x_gui.x_fcol, x); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags [list %lxLABEL label text]\n", | |||
canvas, xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
} | |||
static void vslider_draw_move(t_vslider *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int tmargin = TMARGIN * IEMGUI_ZOOM(x), bmargin = BMARGIN * IEMGUI_ZOOM(x); | |||
int r = ypos + x->x_gui.x_h - ((x->x_val+ 50)/100); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c coords %lxBASE %d %d %d %d\n", | |||
canvas, x, | |||
xpos, ypos - tmargin, | |||
xpos + x->x_gui.x_w, ypos + x->x_gui.x_h + bmargin); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos, ypos + x->x_gui.x_h + bmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h + bmargin); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos, ypos - tmargin, | |||
xpos + iow, ypos - tmargin - IEMGUI_ZOOM(x) + ioh); | |||
sys_vgui(".x%lx.c coords %lxKNOB %d %d %d %d\n", | |||
canvas, x, xpos + IEMGUI_ZOOM(x), r, | |||
xpos + x->x_gui.x_w - IEMGUI_ZOOM(x), r); | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, xpos+x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos+x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
} | |||
static void vslider_draw_erase(t_vslider* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxKNOB\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
static void vslider_draw_config(t_vslider* x, t_glist* glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize * IEMGUI_ZOOM(x), sys_fontweight, | |||
(x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : "")); | |||
sys_vgui(".x%lx.c itemconfigure %lxKNOB -fill #%06x\n", canvas, | |||
x, x->x_gui.x_fcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -fill #%06x\n", canvas, | |||
x, x->x_gui.x_bcol); | |||
} | |||
static void vslider_draw_io(t_vslider* x, t_glist* glist, int old_snd_rcv_flags) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int tmargin = TMARGIN * IEMGUI_ZOOM(x), bmargin = BMARGIN * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos, ypos + x->x_gui.x_h + bmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos + iow, ypos + x->x_gui.x_h + bmargin, | |||
x, 0); | |||
/* keep these above outlet */ | |||
sys_vgui(".x%lx.c raise %lxKNOB %lxOUT%d\n", canvas, x, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxKNOB\n", canvas, x, x); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able) | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos, ypos - tmargin, | |||
xpos + iow, ypos - tmargin - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
/* keep these above inlet */ | |||
sys_vgui(".x%lx.c raise %lxKNOB %lxIN%d\n", canvas, x, x, 0); | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxKNOB\n", canvas, x, x); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able) | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
} | |||
static void vslider_draw_select(t_vslider *x, t_glist *glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_NORMAL); | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, x->x_gui.x_lcol); | |||
} | |||
} | |||
void vslider_draw(t_vslider *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_UPDATE) | |||
sys_queuegui(x, glist, vslider_draw_update); | |||
else if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
vslider_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
vslider_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
vslider_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
vslider_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
vslider_draw_config(x, glist); | |||
else if(mode >= IEM_GUI_DRAW_MODE_IO) | |||
vslider_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO); | |||
} | |||
/* ------------------------ vsl widgetbehaviour----------------------------- */ | |||
static void vslider_getrect(t_gobj *z, t_glist *glist, | |||
int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_vslider* x = (t_vslider*)z; | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist); | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist) - TMARGIN*glist_getzoom(glist); | |||
*xp2 = *xp1 + x->x_gui.x_w; | |||
*yp2 = *yp1 + x->x_gui.x_h + (TMARGIN + BMARGIN)*glist_getzoom(glist); | |||
} | |||
static void vslider_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_vslider *x = (t_vslider *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
binbuf_addv(b, "ssiisiiffiisssiiiisssii", gensym("#X"), gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix, | |||
gensym("vsl"), x->x_gui.x_w/IEMGUI_ZOOM(x), x->x_gui.x_h/IEMGUI_ZOOM(x), | |||
(t_float)x->x_min, (t_float)x->x_max, | |||
x->x_lin0_log1, iem_symargstoint(&x->x_gui.x_isa), | |||
srl[0], srl[1], srl[2], | |||
x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[1], bflcol[2], | |||
x->x_val, x->x_steady); | |||
binbuf_addv(b, ";"); | |||
} | |||
void vslider_check_height(t_vslider *x, int h) | |||
{ | |||
if(h < IEM_SL_MINSIZE * IEMGUI_ZOOM(x)) | |||
h = IEM_SL_MINSIZE * IEMGUI_ZOOM(x); | |||
x->x_gui.x_h = h; | |||
if(x->x_val > (x->x_gui.x_h*100 - 100)) | |||
{ | |||
x->x_pos = x->x_gui.x_h*100 - 100; | |||
x->x_val = x->x_pos; | |||
} | |||
if(x->x_lin0_log1) | |||
x->x_k = log(x->x_max / x->x_min) / (double)(x->x_gui.x_h/IEMGUI_ZOOM(x) - 1); | |||
else | |||
x->x_k = (x->x_max - x->x_min) / (double)(x->x_gui.x_h/IEMGUI_ZOOM(x) - 1); | |||
} | |||
void vslider_check_minmax(t_vslider *x, double min, double max) | |||
{ | |||
if(x->x_lin0_log1) | |||
{ | |||
if((min == 0.0) && (max == 0.0)) | |||
max = 1.0; | |||
if(max > 0.0) | |||
{ | |||
if(min <= 0.0) | |||
min = 0.01 * max; | |||
} | |||
else | |||
{ | |||
if(min > 0.0) | |||
max = 0.01 * min; | |||
} | |||
} | |||
x->x_min = min; | |||
x->x_max = max; | |||
if(x->x_lin0_log1) | |||
x->x_k = log(x->x_max/x->x_min) / (double)(x->x_gui.x_h/IEMGUI_ZOOM(x) - 1); | |||
else | |||
x->x_k = (x->x_max - x->x_min) / (double)(x->x_gui.x_h/IEMGUI_ZOOM(x) - 1); | |||
} | |||
static void vslider_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_vslider *x = (t_vslider *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
iemgui_properties(&x->x_gui, srl); | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |vsl| \ | |||
--------dimensions(pix)(pix):-------- %d %d width: %d %d height: \ | |||
-----------output-range:----------- %g bottom: %g top: %d \ | |||
%d lin log %d %d empty %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x #%06x #%06x\n", | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), IEM_GUI_MINSIZE, x->x_gui.x_h/IEMGUI_ZOOM(x), IEM_SL_MINSIZE, | |||
x->x_min, x->x_max, 0,/*no_schedule*/ | |||
x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/ | |||
srl[0]->s_name, srl[1]->s_name, | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
/* compute numeric value (fval) from pixel location (val) and range */ | |||
static t_float vslider_getfval(t_vslider *x) | |||
{ | |||
t_float fval; | |||
int zoomval = (x->x_gui.x_fsf.x_finemoved) ? | |||
x->x_val/IEMGUI_ZOOM(x) : (x->x_val / (100*IEMGUI_ZOOM(x))) * 100; | |||
if (x->x_lin0_log1) | |||
fval = x->x_min * exp(x->x_k * (double)(zoomval) * 0.01); | |||
else fval = (double)(zoomval) * 0.01 * x->x_k + x->x_min; | |||
if ((fval < 1.0e-10) && (fval > -1.0e-10)) | |||
fval = 0.0; | |||
return (fval); | |||
} | |||
static void vslider_bang(t_vslider *x) | |||
{ | |||
double out; | |||
if (pd_compatibilitylevel < 46) | |||
out = vslider_getfval(x); | |||
else out = x->x_fval; | |||
outlet_float(x->x_gui.x_obj.ob_outlet, out); | |||
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing) | |||
pd_float(x->x_gui.x_snd->s_thing, out); | |||
} | |||
static void vslider_dialog(t_vslider *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int w = (int)atom_getfloatarg(0, argc, argv); | |||
int h = (int)atom_getfloatarg(1, argc, argv) * IEMGUI_ZOOM(x); | |||
double min = (double)atom_getfloatarg(2, argc, argv); | |||
double max = (double)atom_getfloatarg(3, argc, argv); | |||
int lilo = (int)atom_getfloatarg(4, argc, argv); | |||
int steady = (int)atom_getfloatarg(17, argc, argv); | |||
int sr_flags; | |||
if(lilo != 0) lilo = 1; | |||
x->x_lin0_log1 = lilo; | |||
if(steady) | |||
x->x_steady = 1; | |||
else | |||
x->x_steady = 0; | |||
sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
x->x_gui.x_w = iemgui_clip_size(w) * IEMGUI_ZOOM(x); | |||
vslider_check_height(x, h); | |||
vslider_check_minmax(x, min, max); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
static void vslider_motion(t_vslider *x, t_floatarg dx, t_floatarg dy) | |||
{ | |||
int old = x->x_val; | |||
if(x->x_gui.x_fsf.x_finemoved) | |||
x->x_pos -= (int)dy; | |||
else | |||
x->x_pos -= 100 * (int)dy; | |||
x->x_val = x->x_pos; | |||
if(x->x_val > (100*x->x_gui.x_h - 100)) | |||
{ | |||
x->x_val = 100*x->x_gui.x_h - 100; | |||
x->x_pos += 50; | |||
x->x_pos -= x->x_pos % 100; | |||
} | |||
if(x->x_val < 0) | |||
{ | |||
x->x_val = 0; | |||
x->x_pos -= 50; | |||
x->x_pos -= x->x_pos % 100; | |||
} | |||
x->x_fval = vslider_getfval(x); | |||
if (old != x->x_val) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
vslider_bang(x); | |||
} | |||
} | |||
static void vslider_click(t_vslider *x, t_floatarg xpos, t_floatarg ypos, | |||
t_floatarg shift, t_floatarg ctrl, t_floatarg alt) | |||
{ | |||
if(!x->x_steady) | |||
x->x_val = (int)(100.0 * (x->x_gui.x_h + text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist) - ypos)); | |||
if(x->x_val > (100*x->x_gui.x_h - 100)) | |||
x->x_val = 100*x->x_gui.x_h - 100; | |||
if(x->x_val < 0) | |||
x->x_val = 0; | |||
x->x_fval = vslider_getfval(x); | |||
x->x_pos = x->x_val; | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
vslider_bang(x); | |||
glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, | |||
(t_glistmotionfn)vslider_motion, 0, xpos, ypos); | |||
} | |||
static int vslider_newclick(t_gobj *z, struct _glist *glist, | |||
int xpix, int ypix, int shift, int alt, int dbl, int doit) | |||
{ | |||
t_vslider* x = (t_vslider *)z; | |||
if(doit) | |||
{ | |||
vslider_click(x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, | |||
0, (t_floatarg)alt); | |||
if(shift) | |||
x->x_gui.x_fsf.x_finemoved = 1; | |||
else | |||
x->x_gui.x_fsf.x_finemoved = 0; | |||
} | |||
return (1); | |||
} | |||
static void vslider_set(t_vslider *x, t_floatarg f) | |||
{ | |||
int old = x->x_val; | |||
double g; | |||
x->x_fval = f; | |||
if (x->x_min > x->x_max) | |||
{ | |||
if(f > x->x_min) | |||
f = x->x_min; | |||
if(f < x->x_max) | |||
f = x->x_max; | |||
} | |||
else | |||
{ | |||
if(f > x->x_max) | |||
f = x->x_max; | |||
if(f < x->x_min) | |||
f = x->x_min; | |||
} | |||
if(x->x_lin0_log1) | |||
g = log(f/x->x_min) / x->x_k; | |||
else | |||
g = (f - x->x_min) / x->x_k; | |||
x->x_val = IEMGUI_ZOOM(x) * (int)(100.0*g + 0.49999); | |||
x->x_pos = x->x_val; | |||
if(x->x_val != old) | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
} | |||
static void vslider_float(t_vslider *x, t_floatarg f) | |||
{ | |||
vslider_set(x, f); | |||
if(x->x_gui.x_fsf.x_put_in2out) | |||
vslider_bang(x); | |||
} | |||
static void vslider_size(t_vslider *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
x->x_gui.x_w = iemgui_clip_size((int)atom_getfloatarg(0, ac, av))*IEMGUI_ZOOM(x); | |||
if(ac > 1) | |||
vslider_check_height(x, (int)atom_getfloatarg(1, ac, av)*IEMGUI_ZOOM(x)); | |||
iemgui_size((void *)x, &x->x_gui); | |||
} | |||
static void vslider_delta(t_vslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void vslider_pos(t_vslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void vslider_range(t_vslider *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
vslider_check_minmax(x, (double)atom_getfloatarg(0, ac, av), | |||
(double)atom_getfloatarg(1, ac, av)); | |||
} | |||
static void vslider_color(t_vslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void vslider_send(t_vslider *x, t_symbol *s) | |||
{iemgui_send(x, &x->x_gui, s);} | |||
static void vslider_receive(t_vslider *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void vslider_label(t_vslider *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void vslider_label_pos(t_vslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void vslider_label_font(t_vslider *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);} | |||
static void vslider_log(t_vslider *x) | |||
{ | |||
x->x_lin0_log1 = 1; | |||
vslider_check_minmax(x, x->x_min, x->x_max); | |||
} | |||
static void vslider_lin(t_vslider *x) | |||
{ | |||
x->x_lin0_log1 = 0; | |||
x->x_k = (x->x_max - x->x_min) / (double)(x->x_gui.x_h/IEMGUI_ZOOM(x) - 1); | |||
} | |||
static void vslider_init(t_vslider *x, t_floatarg f) | |||
{ | |||
x->x_gui.x_isa.x_loadinit = (f == 0.0) ? 0 : 1; | |||
} | |||
static void vslider_steady(t_vslider *x, t_floatarg f) | |||
{ | |||
x->x_steady = (f == 0.0) ? 0 : 1; | |||
} | |||
static void vslider_zoom(t_vslider *x, t_floatarg f) | |||
{ | |||
/* scale current pixel value */ | |||
x->x_val = (IEMGUI_ZOOM(x) == 2 ? (x->x_val)/2 : (x->x_val)*2); | |||
x->x_pos = x->x_val; | |||
iemgui_zoom(&x->x_gui, f); | |||
} | |||
static void vslider_loadbang(t_vslider *x, t_floatarg action) | |||
{ | |||
if (action == LB_LOAD && x->x_gui.x_isa.x_loadinit) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE); | |||
vslider_bang(x); | |||
} | |||
} | |||
static void *vslider_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_vslider *x = (t_vslider *)pd_new(vslider_class); | |||
int w = IEM_GUI_DEFAULTSIZE, h = IEM_SL_DEFAULTSIZE; | |||
int lilo = 0, f = 0, ldx = 0, ldy = -9; | |||
int fs = 10, steady = 1; | |||
double min = 0.0, max = (double)(IEM_SL_DEFAULTSIZE-1); | |||
char str[144]; | |||
float v = 0; | |||
iem_inttosymargs(&x->x_gui.x_isa, 0); | |||
iem_inttofstyle(&x->x_gui.x_fsf, 0); | |||
x->x_gui.x_bcol = 0xFCFCFC; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x00; | |||
if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1) | |||
&&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3) | |||
&&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5) | |||
&&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6)) | |||
&&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7)) | |||
&&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8)) | |||
&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10) | |||
&&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,16)) | |||
{ | |||
w = (int)atom_getfloatarg(0, argc, argv); | |||
h = (int)atom_getfloatarg(1, argc, argv); | |||
min = (double)atom_getfloatarg(2, argc, argv); | |||
max = (double)atom_getfloatarg(3, argc, argv); | |||
lilo = (int)atom_getfloatarg(4, argc, argv); | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(5, argc, argv)); | |||
iemgui_new_getnames(&x->x_gui, 6, argv); | |||
ldx = (int)atom_getfloatarg(9, argc, argv); | |||
ldy = (int)atom_getfloatarg(10, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(11, argc, argv)); | |||
fs = (int)atom_getfloatarg(12, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+13, argv+14, argv+15); | |||
v = atom_getfloatarg(16, argc, argv); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 6, 0); | |||
if((argc == 18)&&IS_A_FLOAT(argv,17)) | |||
steady = (int)atom_getfloatarg(17, argc, argv); | |||
x->x_gui.x_draw = (t_iemfunptr)vslider_draw; | |||
x->x_gui.x_fsf.x_snd_able = 1; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if (x->x_gui.x_isa.x_loadinit) | |||
x->x_val = v; | |||
else x->x_val = 0; | |||
x->x_pos = x->x_val; | |||
if(lilo != 0) lilo = 1; | |||
x->x_lin0_log1 = lilo; | |||
if(steady != 0) steady = 1; | |||
x->x_steady = steady; | |||
if(!strcmp(x->x_gui.x_snd->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0; | |||
if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0; | |||
if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < 4) | |||
fs = 4; | |||
x->x_gui.x_fontsize = fs; | |||
x->x_gui.x_w = iemgui_clip_size(w); | |||
vslider_check_height(x, h); | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
iemgui_newzoom(&x->x_gui); | |||
vslider_check_minmax(x, min, max); | |||
outlet_new(&x->x_gui.x_obj, &s_float); | |||
x->x_fval = vslider_getfval(x); | |||
return (x); | |||
} | |||
static void vslider_free(t_vslider *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_vslider_setup(void) | |||
{ | |||
vslider_class = class_new(gensym("vsl"), (t_newmethod)vslider_new, | |||
(t_method)vslider_free, sizeof(t_vslider), 0, A_GIMME, 0); | |||
class_addcreator((t_newmethod)vslider_new, gensym("vslider"), A_GIMME, 0); | |||
class_addbang(vslider_class,vslider_bang); | |||
class_addfloat(vslider_class,vslider_float); | |||
class_addmethod(vslider_class, (t_method)vslider_click, | |||
gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_motion, | |||
gensym("motion"), A_FLOAT, A_FLOAT, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_loadbang, | |||
gensym("loadbang"), A_DEFFLOAT, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_set, | |||
gensym("set"), A_FLOAT, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_range, | |||
gensym("range"), A_GIMME, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_send, | |||
gensym("send"), A_DEFSYM, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_log, | |||
gensym("log"), 0); | |||
class_addmethod(vslider_class, (t_method)vslider_lin, | |||
gensym("lin"), 0); | |||
class_addmethod(vslider_class, (t_method)vslider_init, | |||
gensym("init"), A_FLOAT, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_steady, | |||
gensym("steady"), A_FLOAT, 0); | |||
class_addmethod(vslider_class, (t_method)vslider_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
vslider_widgetbehavior.w_getrectfn = vslider_getrect; | |||
vslider_widgetbehavior.w_displacefn = iemgui_displace; | |||
vslider_widgetbehavior.w_selectfn = iemgui_select; | |||
vslider_widgetbehavior.w_activatefn = NULL; | |||
vslider_widgetbehavior.w_deletefn = iemgui_delete; | |||
vslider_widgetbehavior.w_visfn = iemgui_vis; | |||
vslider_widgetbehavior.w_clickfn = vslider_newclick; | |||
class_setwidget(vslider_class, &vslider_widgetbehavior); | |||
class_sethelpsymbol(vslider_class, gensym("vslider")); | |||
class_setsavefn(vslider_class, vslider_save); | |||
class_setpropertiesfn(vslider_class, vslider_properties); | |||
} |
@@ -0,0 +1,773 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */ | |||
/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
#include "m_pd.h" | |||
#include "g_canvas.h" | |||
#include "g_all_guis.h" | |||
#include <math.h> | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#else | |||
#include <unistd.h> | |||
#endif | |||
#define HMARGIN 1 | |||
#define VMARGIN 2 | |||
#define PEAKHEIGHT 10 | |||
/* ----- vu gui-peak- & rms- vu-meter-display ---------- */ | |||
t_widgetbehavior vu_widgetbehavior; | |||
static t_class *vu_class; | |||
/* widget helper functions */ | |||
static void vu_update_rms(t_vu *x, t_glist *glist) | |||
{ | |||
if(glist_isvisible(glist)) | |||
{ | |||
int w4 = x->x_gui.x_w / 4, off = text_ypix(&x->x_gui.x_obj, glist) - IEMGUI_ZOOM(x); | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int quad1 = xpos + w4 - IEMGUI_ZOOM(x), quad3 = xpos + x->x_gui.x_w - w4 + IEMGUI_ZOOM(x); | |||
sys_vgui(".x%lx.c coords %lxRCOVER %d %d %d %d\n", | |||
glist_getcanvas(glist), x, quad1, off, quad3, | |||
off + (x->x_led_size+1)*IEMGUI_ZOOM(x)*(IEM_VU_STEPS-x->x_rms)); | |||
} | |||
} | |||
static void vu_update_peak(t_vu *x, t_glist *glist) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(glist_isvisible(glist)) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
if(x->x_peak) | |||
{ | |||
int i = iemgui_vu_col[x->x_peak]; | |||
int j = ypos + | |||
(x->x_led_size+1)*IEMGUI_ZOOM(x)*(IEM_VU_STEPS+1-x->x_peak) - | |||
(x->x_led_size+1)*IEMGUI_ZOOM(x)/2; | |||
sys_vgui(".x%lx.c coords %lxPLED %d %d %d %d\n", canvas, x, | |||
xpos, j, xpos + x->x_gui.x_w + IEMGUI_ZOOM(x), j); | |||
sys_vgui(".x%lx.c itemconfigure %lxPLED -fill #%06x\n", canvas, x, | |||
iemgui_color_hex[i]); | |||
} | |||
else | |||
{ | |||
int mid = xpos + x->x_gui.x_w/2; | |||
int pkh = PEAKHEIGHT * IEMGUI_ZOOM(x); | |||
sys_vgui(".x%lx.c itemconfigure %lxPLED -fill #%06x\n", | |||
canvas, x, x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c coords %lxPLED %d %d %d %d\n", | |||
canvas, x, mid, ypos + pkh, mid, ypos + pkh); | |||
} | |||
} | |||
} | |||
static void vu_draw_update(t_gobj *client, t_glist *glist) | |||
{ | |||
t_vu *x = (t_vu *)client; | |||
if (x->x_updaterms) | |||
{ | |||
vu_update_rms(x, glist); | |||
x->x_updaterms = 0; | |||
} | |||
if (x->x_updatepeak) | |||
{ | |||
vu_update_peak(x, glist); | |||
x->x_updatepeak = 0; | |||
} | |||
} | |||
static void vu_draw_new(t_vu *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int hmargin = HMARGIN * IEMGUI_ZOOM(x), vmargin = VMARGIN * IEMGUI_ZOOM(x); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int w4 = x->x_gui.x_w/4, mid = xpos + x->x_gui.x_w/2, | |||
quad1 = xpos + w4 + IEMGUI_ZOOM(x); | |||
int quad3 = xpos + x->x_gui.x_w - w4, | |||
end = xpos + x->x_gui.x_w + 4*IEMGUI_ZOOM(x); | |||
int k1 = (x->x_led_size+1)*IEMGUI_ZOOM(x), k2 = IEM_VU_STEPS+1, k3 = k1/2; | |||
int led_col, yyy, i, k4 = ypos - k3; | |||
int ledw = x->x_led_size * IEMGUI_ZOOM(x); | |||
int fs = x->x_gui.x_fontsize * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -width %d -fill #%06x -tags %lxBASE\n", | |||
canvas, xpos - hmargin, ypos - vmargin, | |||
xpos+x->x_gui.x_w + hmargin, | |||
ypos+x->x_gui.x_h + vmargin, IEMGUI_ZOOM(x), x->x_gui.x_bcol, x); | |||
for(i = 1; i <= IEM_VU_STEPS; i++) | |||
{ | |||
led_col = iemgui_vu_col[i]; | |||
yyy = k4 + k1*(k2-i); | |||
sys_vgui(".x%lx.c create line %d %d %d %d -width %d -fill #%06x -tags %lxRLED%d\n", | |||
canvas, quad1, yyy, quad3, yyy, ledw, | |||
iemgui_color_hex[led_col], x, i); | |||
if(((i+2) & 3) && (x->x_scale)) | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags %lxSCALE%d\n", | |||
canvas, end, yyy + k3, iemgui_vu_scale_str[i], | |||
x->x_gui.x_font, fs, | |||
sys_fontweight, x->x_gui.x_lcol, x, i); | |||
} | |||
if(x->x_scale) | |||
{ | |||
i = IEM_VU_STEPS + 1; | |||
yyy = k4 + k1 * (k2 - i); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags %lxSCALE%d\n", | |||
canvas, end, yyy + k3, iemgui_vu_scale_str[i], | |||
x->x_gui.x_font, fs, | |||
sys_fontweight, x->x_gui.x_lcol, x, i); | |||
} | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill #%06x -outline #%06x -tags %lxRCOVER\n", | |||
canvas, quad1 - IEMGUI_ZOOM(x), ypos - IEMGUI_ZOOM(x), quad3 + IEMGUI_ZOOM(x), | |||
ypos - IEMGUI_ZOOM(x) + k1*IEM_VU_STEPS, x->x_gui.x_bcol, x->x_gui.x_bcol, x); | |||
sys_vgui(".x%lx.c create line %d %d %d %d -width %d -fill #%06x -tags %lxPLED\n", | |||
canvas, mid, ypos + PEAKHEIGHT * IEMGUI_ZOOM(x), | |||
mid, ypos + PEAKHEIGHT * IEMGUI_ZOOM(x), | |||
(x->x_led_size+1)*IEMGUI_ZOOM(x), x->x_gui.x_bcol, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]\n", | |||
canvas, | |||
xpos - hmargin, ypos + x->x_gui.x_h + vmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos - hmargin + iow, ypos + x->x_gui.x_h + vmargin, | |||
x, 0); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxOUT%d outlet]x\n", | |||
canvas, | |||
xpos + x->x_gui.x_w + hmargin - iow, ypos + x->x_gui.x_h + vmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos + x->x_gui.x_w + hmargin, ypos + x->x_gui.x_h + vmargin, | |||
x, 1); | |||
} | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xpos - hmargin, ypos - vmargin, | |||
xpos - hmargin + iow, ypos - vmargin - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags [list %lxIN%d inlet]\n", | |||
canvas, | |||
xpos + x->x_gui.x_w + hmargin - iow, ypos - vmargin, | |||
xpos + x->x_gui.x_w + hmargin, ypos - vmargin - IEMGUI_ZOOM(x) + ioh, | |||
x, 1); | |||
} | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags [list %lxLABEL label text]\n", | |||
canvas, xpos+x->x_gui.x_ldx * IEMGUI_ZOOM(x), ypos+x->x_gui.x_ldy * IEMGUI_ZOOM(x), | |||
(strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""), | |||
x->x_gui.x_font, fs, sys_fontweight, | |||
x->x_gui.x_lcol, x); | |||
x->x_updaterms = x->x_updatepeak = 1; | |||
sys_queuegui(x, x->x_gui.x_glist, vu_draw_update); | |||
} | |||
static void vu_draw_move(t_vu *x, t_glist *glist) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int hmargin = HMARGIN * IEMGUI_ZOOM(x), vmargin = VMARGIN * IEMGUI_ZOOM(x); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
int w4 = x->x_gui.x_w/4, quad1 = xpos + w4 + IEMGUI_ZOOM(x); | |||
int quad3 = xpos + x->x_gui.x_w - w4, | |||
end = xpos + x->x_gui.x_w + 4*IEMGUI_ZOOM(x); | |||
int k1 = (x->x_led_size+1)*IEMGUI_ZOOM(x), k2 = IEM_VU_STEPS+1, k3 = k1/2; | |||
int yyy, i, k4 = ypos - k3; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c coords %lxBASE %d %d %d %d\n", | |||
canvas, x, xpos - hmargin, ypos - vmargin, | |||
xpos + x->x_gui.x_w + hmargin, ypos + x->x_gui.x_h + vmargin); | |||
for(i = 1; i <= IEM_VU_STEPS; i++) | |||
{ | |||
yyy = k4 + k1 * (k2 - i); | |||
sys_vgui(".x%lx.c coords %lxRLED%d %d %d %d %d\n", | |||
canvas, x, i, quad1, yyy, quad3, yyy); | |||
if(((i+2) & 3) && (x->x_scale)) | |||
sys_vgui(".x%lx.c coords %lxSCALE%d %d %d\n", | |||
canvas, x, i, end, yyy + k3); | |||
} | |||
if(x->x_scale) | |||
{ | |||
i = IEM_VU_STEPS + 1; | |||
yyy = k4 + k1 * (k2 - i); | |||
sys_vgui(".x%lx.c coords %lxSCALE%d %d %d\n", | |||
canvas, x, i, end, yyy + k3); | |||
} | |||
x->x_updaterms = x->x_updatepeak = 1; | |||
sys_queuegui(x, glist, vu_draw_update); | |||
sys_vgui(".x%lx.c coords %lxLABEL %d %d\n", | |||
canvas, x, xpos + x->x_gui.x_ldx * IEMGUI_ZOOM(x), | |||
ypos + x->x_gui.x_ldy * IEMGUI_ZOOM(x)); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos - hmargin, ypos + x->x_gui.x_h + vmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos - hmargin + iow, ypos + x->x_gui.x_h + vmargin); | |||
sys_vgui(".x%lx.c coords %lxOUT%d %d %d %d %d\n", | |||
canvas, x, 1, | |||
xpos + x->x_gui.x_w + hmargin - iow, ypos + x->x_gui.x_h + vmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos + x->x_gui.x_w + hmargin, ypos + x->x_gui.x_h + vmargin); | |||
} | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 0, | |||
xpos - hmargin, ypos - vmargin, | |||
xpos - hmargin + iow, ypos - vmargin - IEMGUI_ZOOM(x) + ioh); | |||
sys_vgui(".x%lx.c coords %lxIN%d %d %d %d %d\n", | |||
canvas, x, 1, | |||
xpos + x->x_gui.x_w + hmargin - iow, ypos - vmargin, | |||
xpos + x->x_gui.x_w + hmargin, ypos - vmargin - IEMGUI_ZOOM(x) + ioh); | |||
} | |||
} | |||
static void vu_draw_erase(t_vu* x,t_glist* glist) | |||
{ | |||
int i; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c delete %lxBASE\n", canvas, x); | |||
for(i = 1; i <= IEM_VU_STEPS; i++) | |||
{ | |||
sys_vgui(".x%lx.c delete %lxRLED%d\n", canvas, x, i); | |||
if(((i+2) & 3) && (x->x_scale)) | |||
sys_vgui(".x%lx.c delete %lxSCALE%d\n", canvas, x, i); | |||
} | |||
if(x->x_scale) | |||
{ | |||
i = IEM_VU_STEPS + 1; | |||
sys_vgui(".x%lx.c delete %lxSCALE%d\n", canvas, x, i); | |||
} | |||
sys_vgui(".x%lx.c delete %lxPLED\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxRCOVER\n", canvas, x); | |||
sys_vgui(".x%lx.c delete %lxLABEL\n", canvas, x); | |||
if(!x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 1); | |||
} | |||
if(!x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 1); | |||
} | |||
} | |||
static void vu_draw_config(t_vu* x, t_glist* glist) | |||
{ | |||
int i; | |||
int ledw = x->x_led_size * IEMGUI_ZOOM(x); | |||
int fs = x->x_gui.x_fontsize * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -fill #%06x\n", canvas, x, x->x_gui.x_bcol); | |||
for(i = 1; i <= IEM_VU_STEPS; i++) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxRLED%d -width %d\n", canvas, x, i, ledw); | |||
if(((i+2) & 3) && (x->x_scale)) | |||
sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -text {%s} -font {{%s} -%d %s} -fill #%06x\n", | |||
canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, | |||
fs, sys_fontweight, | |||
x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol); | |||
} | |||
if(x->x_scale) | |||
{ | |||
i = IEM_VU_STEPS + 1; | |||
sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -text {%s} -font {{%s} -%d %s} -fill #%06x\n", | |||
canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, | |||
fs, sys_fontweight, | |||
x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol); | |||
} | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -font {{%s} -%d %s} -fill #%06x -text {%s} \n", | |||
canvas, x, x->x_gui.x_font, fs, sys_fontweight, | |||
x->x_gui.x_fsf.x_selected ? IEM_GUI_COLOR_SELECTED : x->x_gui.x_lcol, | |||
strcmp(x->x_gui.x_lab->s_name, "empty") ? x->x_gui.x_lab->s_name : ""); | |||
sys_vgui(".x%lx.c itemconfigure %lxRCOVER -fill #%06x -outline #%06x\n", canvas, | |||
x, x->x_gui.x_bcol, x->x_gui.x_bcol); | |||
sys_vgui(".x%lx.c itemconfigure %lxPLED -width %d\n", canvas, x, ledw); | |||
} | |||
static void vu_draw_io(t_vu* x, t_glist* glist, int old_snd_rcv_flags) | |||
{ | |||
int xpos = text_xpix(&x->x_gui.x_obj, glist); | |||
int ypos = text_ypix(&x->x_gui.x_obj, glist); | |||
int hmargin = HMARGIN * IEMGUI_ZOOM(x), vmargin = VMARGIN * IEMGUI_ZOOM(x); | |||
int iow = IOWIDTH * IEMGUI_ZOOM(x), ioh = IEM_GUI_IOHEIGHT * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos - hmargin, ypos + x->x_gui.x_h + vmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos - hmargin + iow, ypos + x->x_gui.x_h + vmargin, | |||
x, 0); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxOUT%d\n", | |||
canvas, | |||
xpos + x->x_gui.x_w + hmargin - iow, ypos + x->x_gui.x_h + vmargin + IEMGUI_ZOOM(x) - ioh, | |||
xpos + x->x_gui.x_w + hmargin, ypos + x->x_gui.x_h + vmargin, | |||
x, 1); | |||
/* keep above outlets */ | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxOUT%d\n", canvas, x, x, 1); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able) | |||
{ | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 0); | |||
sys_vgui(".x%lx.c delete %lxOUT%d\n", canvas, x, 1); | |||
} | |||
if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos - hmargin, ypos - vmargin, | |||
xpos - hmargin + iow, ypos - vmargin - IEMGUI_ZOOM(x) + ioh, | |||
x, 0); | |||
sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -tags %lxIN%d\n", | |||
canvas, | |||
xpos + x->x_gui.x_w + hmargin - iow, ypos - vmargin, | |||
xpos + x->x_gui.x_w + hmargin, ypos - vmargin - IEMGUI_ZOOM(x) + ioh, | |||
x, 1); | |||
/* keep above inlets */ | |||
sys_vgui(".x%lx.c raise %lxLABEL %lxIN%d\n", canvas, x, x, 1); | |||
} | |||
if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able) | |||
{ | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 0); | |||
sys_vgui(".x%lx.c delete %lxIN%d\n", canvas, x, 1); | |||
} | |||
} | |||
static void vu_draw_select(t_vu* x,t_glist* glist) | |||
{ | |||
int i; | |||
t_canvas *canvas = glist_getcanvas(glist); | |||
if(x->x_gui.x_fsf.x_selected) | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
for(i = 1; i <= IEM_VU_STEPS; i++) | |||
{ | |||
if(((i+2) & 3) && (x->x_scale)) | |||
sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -fill #%06x\n", | |||
canvas, x, i, IEM_GUI_COLOR_SELECTED); | |||
} | |||
if(x->x_scale) | |||
{ | |||
i = IEM_VU_STEPS + 1; | |||
sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -fill #%06x\n", | |||
canvas, x, i, IEM_GUI_COLOR_SELECTED); | |||
} | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, IEM_GUI_COLOR_SELECTED); | |||
} | |||
else | |||
{ | |||
sys_vgui(".x%lx.c itemconfigure %lxBASE -outline #%06x\n", canvas, x, IEM_GUI_COLOR_NORMAL); | |||
for(i = 1; i <= IEM_VU_STEPS; i++) | |||
{ | |||
if(((i+2) & 3) && (x->x_scale)) | |||
sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -fill #%06x\n", | |||
canvas, x, i, x->x_gui.x_lcol); | |||
} | |||
if(x->x_scale) | |||
{ | |||
i = IEM_VU_STEPS+1; | |||
sys_vgui(".x%lx.c itemconfigure %lxSCALE%d -fill #%06x\n", | |||
canvas, x, i, x->x_gui.x_lcol); | |||
} | |||
sys_vgui(".x%lx.c itemconfigure %lxLABEL -fill #%06x\n", canvas, x, x->x_gui.x_lcol); | |||
} | |||
} | |||
void vu_draw(t_vu *x, t_glist *glist, int mode) | |||
{ | |||
if(mode == IEM_GUI_DRAW_MODE_MOVE) | |||
vu_draw_move(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_NEW) | |||
vu_draw_new(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_SELECT) | |||
vu_draw_select(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_ERASE) | |||
vu_draw_erase(x, glist); | |||
else if(mode == IEM_GUI_DRAW_MODE_CONFIG) | |||
vu_draw_config(x, glist); | |||
else if(mode >= IEM_GUI_DRAW_MODE_IO) | |||
vu_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO); | |||
} | |||
/* ------------------------ vu widgetbehaviour----------------------------- */ | |||
static void vu_getrect(t_gobj *z, t_glist *glist, | |||
int *xp1, int *yp1, int *xp2, int *yp2) | |||
{ | |||
t_vu* x = (t_vu*)z; | |||
int hmargin = HMARGIN * IEMGUI_ZOOM(x), vmargin = VMARGIN * IEMGUI_ZOOM(x); | |||
*xp1 = text_xpix(&x->x_gui.x_obj, glist) - hmargin; | |||
*yp1 = text_ypix(&x->x_gui.x_obj, glist) - vmargin; | |||
*xp2 = *xp1 + x->x_gui.x_w + hmargin*2; | |||
*yp2 = *yp1 + x->x_gui.x_h + vmargin*2; | |||
} | |||
static void vu_save(t_gobj *z, t_binbuf *b) | |||
{ | |||
t_vu *x = (t_vu *)z; | |||
t_symbol *bflcol[3]; | |||
t_symbol *srl[3]; | |||
iemgui_save(&x->x_gui, srl, bflcol); | |||
binbuf_addv(b, "ssiisiissiiiissii", gensym("#X"), gensym("obj"), | |||
(int)x->x_gui.x_obj.te_xpix, (int)x->x_gui.x_obj.te_ypix, | |||
gensym("vu"), x->x_gui.x_w/IEMGUI_ZOOM(x), x->x_gui.x_h/IEMGUI_ZOOM(x), | |||
srl[1], srl[2], | |||
x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
iem_fstyletoint(&x->x_gui.x_fsf), x->x_gui.x_fontsize, | |||
bflcol[0], bflcol[2], x->x_scale, | |||
iem_symargstoint(&x->x_gui.x_isa)); | |||
binbuf_addv(b, ";"); | |||
} | |||
void vu_check_height(t_vu *x, int h) | |||
{ | |||
int n; | |||
n = h / IEM_VU_STEPS; | |||
if(n < IEM_VU_MINSIZE) | |||
n = IEM_VU_MINSIZE; | |||
x->x_led_size = n - 1; | |||
x->x_gui.x_h = (IEM_VU_STEPS * n) * IEMGUI_ZOOM(x); | |||
} | |||
static void vu_scale(t_vu *x, t_floatarg fscale) | |||
{ | |||
int i, scale = (int)fscale; | |||
if(scale != 0) scale = 1; | |||
if(x->x_scale && !scale) | |||
{ | |||
t_canvas *canvas = glist_getcanvas(x->x_gui.x_glist); | |||
x->x_scale = (int)scale; | |||
if(glist_isvisible(x->x_gui.x_glist)) | |||
{ | |||
for(i = 1; i <= IEM_VU_STEPS; i++) | |||
{ | |||
if((i+2) & 3) | |||
sys_vgui(".x%lx.c delete %lxSCALE%d\n", canvas, x, i); | |||
} | |||
i = IEM_VU_STEPS + 1; | |||
sys_vgui(".x%lx.c delete %lxSCALE%d\n", canvas, x, i); | |||
} | |||
} | |||
if(!x->x_scale && scale) | |||
{ | |||
int w4 = x->x_gui.x_w/4; | |||
int end = text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist) + x->x_gui.x_w + 4*IEMGUI_ZOOM(x); | |||
int k1 = (x->x_led_size+1)*IEMGUI_ZOOM(x), k2 = IEM_VU_STEPS+1, k3 = k1/2; | |||
int yyy, k4 = text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist) - k3; | |||
int fs = x->x_gui.x_fontsize * IEMGUI_ZOOM(x); | |||
t_canvas *canvas = glist_getcanvas(x->x_gui.x_glist); | |||
x->x_scale = (int)scale; | |||
if(glist_isvisible(x->x_gui.x_glist)) | |||
{ | |||
for(i = 1; i <= IEM_VU_STEPS; i++) | |||
{ | |||
yyy = k4 + k1 * (k2 - i); | |||
if((i+2) & 3) | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags %lxSCALE%d\n", | |||
canvas, end, yyy + k3, iemgui_vu_scale_str[i], | |||
x->x_gui.x_font, fs, | |||
sys_fontweight, x->x_gui.x_lcol, x, i); | |||
} | |||
i = IEM_VU_STEPS + 1; | |||
yyy = k4 + k1 * (k2 - i); | |||
sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor w \ | |||
-font {{%s} -%d %s} -fill #%06x -tags %lxSCALE%d\n", | |||
canvas, end, yyy + k3, iemgui_vu_scale_str[i], | |||
x->x_gui.x_font, fs, | |||
sys_fontweight, x->x_gui.x_lcol, x, i); | |||
} | |||
} | |||
} | |||
static void vu_properties(t_gobj *z, t_glist *owner) | |||
{ | |||
t_vu *x = (t_vu *)z; | |||
char buf[800]; | |||
t_symbol *srl[3]; | |||
iemgui_properties(&x->x_gui, srl); | |||
sprintf(buf, "pdtk_iemgui_dialog %%s |vu| \ | |||
--------dimensions(pix)(pix):-------- %d %d width: %d %d height: \ | |||
empty 0.0 empty 0.0 empty %d \ | |||
%d no_scale scale %d %d empty %d \ | |||
%s %s \ | |||
%s %d %d \ | |||
%d %d \ | |||
#%06x none #%06x\n", | |||
x->x_gui.x_w/IEMGUI_ZOOM(x), IEM_GUI_MINSIZE, | |||
x->x_gui.x_h/IEMGUI_ZOOM(x), IEM_VU_STEPS*IEM_VU_MINSIZE, | |||
0,/*no_schedule*/ | |||
x->x_scale, -1, -1, -1,/*no linlog, no init, no multi*/ | |||
"nosndno", srl[1]->s_name,/*no send*/ | |||
srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy, | |||
x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize, | |||
0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_lcol); | |||
gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf); | |||
} | |||
static void vu_dialog(t_vu *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_symbol *srl[3]; | |||
int w = (int)atom_getfloatarg(0, argc, argv); | |||
int h = (int)atom_getfloatarg(1, argc, argv); | |||
int scale = (int)atom_getfloatarg(4, argc, argv); | |||
int sr_flags; | |||
srl[0] = gensym("empty"); | |||
sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv); | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
x->x_gui.x_isa.x_loadinit = 0; | |||
x->x_gui.x_w = iemgui_clip_size(w) * IEMGUI_ZOOM(x); | |||
vu_check_height(x, h); | |||
if(scale != 0) | |||
scale = 1; | |||
vu_scale(x, (t_float)scale); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
static void vu_size(t_vu *x, t_symbol *s, int ac, t_atom *av) | |||
{ | |||
x->x_gui.x_w = iemgui_clip_size((int)atom_getfloatarg(0, ac, av)) * IEMGUI_ZOOM(x); | |||
if(ac > 1) | |||
vu_check_height(x, (int)atom_getfloatarg(1, ac, av)); | |||
if(glist_isvisible(x->x_gui.x_glist)) | |||
{ | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE); | |||
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG); | |||
canvas_fixlinesfor(x->x_gui.x_glist, (t_text*)x); | |||
} | |||
} | |||
static void vu_delta(t_vu *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_delta((void *)x, &x->x_gui, s, ac, av);} | |||
static void vu_pos(t_vu *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void vu_color(t_vu *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_color((void *)x, &x->x_gui, s, ac, av);} | |||
static void vu_receive(t_vu *x, t_symbol *s) | |||
{iemgui_receive(x, &x->x_gui, s);} | |||
static void vu_label(t_vu *x, t_symbol *s) | |||
{iemgui_label((void *)x, &x->x_gui, s);} | |||
static void vu_label_pos(t_vu *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);} | |||
static void vu_label_font(t_vu *x, t_symbol *s, int ac, t_atom *av) | |||
{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);} | |||
static void vu_float(t_vu *x, t_floatarg rms) | |||
{ | |||
int i; | |||
int old = x->x_rms; | |||
if(rms <= IEM_VU_MINDB) | |||
x->x_rms = 0; | |||
else if(rms >= IEM_VU_MAXDB) | |||
x->x_rms = IEM_VU_STEPS; | |||
else | |||
{ | |||
int i = (int)(2.0*(rms + IEM_VU_OFFSET)); | |||
x->x_rms = iemgui_vu_db2i[i]; | |||
} | |||
i = (int)(100.0*rms + 10000.5); | |||
rms = 0.01*(t_float)(i - 10000); | |||
x->x_fr = rms; | |||
outlet_float(x->x_out_rms, rms); | |||
x->x_updaterms = 1; | |||
if(x->x_rms != old) | |||
sys_queuegui(x, x->x_gui.x_glist, vu_draw_update); | |||
} | |||
static void vu_ft1(t_vu *x, t_floatarg peak) | |||
{ | |||
int i; | |||
int old = x->x_peak; | |||
if(peak <= IEM_VU_MINDB) | |||
x->x_peak = 0; | |||
else if(peak >= IEM_VU_MAXDB) | |||
x->x_peak = IEM_VU_STEPS; | |||
else | |||
{ | |||
int i = (int)(2.0*(peak + IEM_VU_OFFSET)); | |||
x->x_peak = iemgui_vu_db2i[i]; | |||
} | |||
i = (int)(100.0*peak + 10000.5); | |||
peak = 0.01*(t_float)(i - 10000); | |||
x->x_fp = peak; | |||
x->x_updatepeak = 1; | |||
if(x->x_peak != old) | |||
sys_queuegui(x, x->x_gui.x_glist, vu_draw_update); | |||
outlet_float(x->x_out_peak, peak); | |||
} | |||
static void vu_bang(t_vu *x) | |||
{ | |||
outlet_float(x->x_out_peak, x->x_fp); | |||
outlet_float(x->x_out_rms, x->x_fr); | |||
x->x_updaterms = x->x_updatepeak = 1; | |||
sys_queuegui(x, x->x_gui.x_glist, vu_draw_update); | |||
} | |||
static void *vu_new(t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_vu *x = (t_vu *)pd_new(vu_class); | |||
int w = IEM_GUI_DEFAULTSIZE, h = IEM_VU_STEPS*IEM_VU_DEFAULTSIZE; | |||
int ldx = -1, ldy = -8, f = 0, fs = 10, scale =1; | |||
int ftbreak = IEM_BNG_DEFAULTBREAKFLASHTIME, fthold = IEM_BNG_DEFAULTHOLDFLASHTIME; | |||
char str[144]; | |||
iem_inttosymargs(&x->x_gui.x_isa, 0); | |||
iem_inttofstyle(&x->x_gui.x_fsf, 0); | |||
x->x_gui.x_bcol = 0x404040; | |||
x->x_gui.x_fcol = 0x00; | |||
x->x_gui.x_lcol = 0x00; | |||
if((argc >= 11)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1) | |||
&&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2)) | |||
&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3)) | |||
&&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5) | |||
&&IS_A_FLOAT(argv,6)&&IS_A_FLOAT(argv,7) | |||
&&IS_A_FLOAT(argv,10)) | |||
{ | |||
w = (int)atom_getfloatarg(0, argc, argv); | |||
h = (int)atom_getfloatarg(1, argc, argv); | |||
iemgui_new_getnames(&x->x_gui, 1, argv); | |||
ldx = (int)atom_getfloatarg(4, argc, argv); | |||
ldy = (int)atom_getfloatarg(5, argc, argv); | |||
iem_inttofstyle(&x->x_gui.x_fsf, atom_getfloatarg(6, argc, argv)); | |||
fs = (int)atom_getfloatarg(7, argc, argv); | |||
iemgui_all_loadcolors(&x->x_gui, argv+8, NULL, argv+9); | |||
scale = (int)atom_getfloatarg(10, argc, argv); | |||
} | |||
else iemgui_new_getnames(&x->x_gui, 1, 0); | |||
if((argc == 12)&&IS_A_FLOAT(argv,11)) | |||
iem_inttosymargs(&x->x_gui.x_isa, atom_getfloatarg(11, argc, argv)); | |||
x->x_gui.x_draw = (t_iemfunptr)vu_draw; | |||
x->x_gui.x_fsf.x_snd_able = 0; | |||
x->x_gui.x_fsf.x_rcv_able = 1; | |||
x->x_gui.x_glist = (t_glist *)canvas_getcurrent(); | |||
if (!strcmp(x->x_gui.x_rcv->s_name, "empty")) | |||
x->x_gui.x_fsf.x_rcv_able = 0; | |||
if (x->x_gui.x_fsf.x_font_style == 1) | |||
strcpy(x->x_gui.x_font, "helvetica"); | |||
else if(x->x_gui.x_fsf.x_font_style == 2) | |||
strcpy(x->x_gui.x_font, "times"); | |||
else { x->x_gui.x_fsf.x_font_style = 0; | |||
strcpy(x->x_gui.x_font, sys_font); } | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
x->x_gui.x_ldx = ldx; | |||
x->x_gui.x_ldy = ldy; | |||
if(fs < 4) | |||
fs = 4; | |||
x->x_gui.x_fontsize = fs; | |||
x->x_gui.x_w = iemgui_clip_size(w); | |||
vu_check_height(x, h); | |||
if(scale != 0) | |||
scale = 1; | |||
x->x_scale = scale; | |||
x->x_peak = 0; | |||
x->x_rms = 0; | |||
x->x_fp = -101.0; | |||
x->x_fr = -101.0; | |||
iemgui_verify_snd_ne_rcv(&x->x_gui); | |||
inlet_new(&x->x_gui.x_obj, &x->x_gui.x_obj.ob_pd, &s_float, gensym("ft1")); | |||
x->x_out_rms = outlet_new(&x->x_gui.x_obj, &s_float); | |||
x->x_out_peak = outlet_new(&x->x_gui.x_obj, &s_float); | |||
iemgui_newzoom(&x->x_gui); | |||
return (x); | |||
} | |||
static void vu_free(t_vu *x) | |||
{ | |||
if(x->x_gui.x_fsf.x_rcv_able) | |||
pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv); | |||
gfxstub_deleteforkey(x); | |||
} | |||
void g_vumeter_setup(void) | |||
{ | |||
vu_class = class_new(gensym("vu"), (t_newmethod)vu_new, | |||
(t_method)vu_free, sizeof(t_vu), 0, A_GIMME, 0); | |||
class_addbang(vu_class,vu_bang); | |||
class_addfloat(vu_class,vu_float); | |||
class_addmethod(vu_class, (t_method)vu_ft1, | |||
gensym("ft1"), A_FLOAT, 0); | |||
class_addmethod(vu_class, (t_method)vu_dialog, | |||
gensym("dialog"), A_GIMME, 0); | |||
class_addmethod(vu_class, (t_method)vu_size, | |||
gensym("size"), A_GIMME, 0); | |||
class_addmethod(vu_class, (t_method)vu_scale, | |||
gensym("scale"), A_DEFFLOAT, 0); | |||
class_addmethod(vu_class, (t_method)vu_delta, | |||
gensym("delta"), A_GIMME, 0); | |||
class_addmethod(vu_class, (t_method)vu_pos, | |||
gensym("pos"), A_GIMME, 0); | |||
class_addmethod(vu_class, (t_method)vu_color, | |||
gensym("color"), A_GIMME, 0); | |||
class_addmethod(vu_class, (t_method)vu_receive, | |||
gensym("receive"), A_DEFSYM, 0); | |||
class_addmethod(vu_class, (t_method)vu_label, | |||
gensym("label"), A_DEFSYM, 0); | |||
class_addmethod(vu_class, (t_method)vu_label_pos, | |||
gensym("label_pos"), A_GIMME, 0); | |||
class_addmethod(vu_class, (t_method)vu_label_font, | |||
gensym("label_font"), A_GIMME, 0); | |||
class_addmethod(vu_class, (t_method)iemgui_zoom, | |||
gensym("zoom"), A_CANT, 0); | |||
vu_widgetbehavior.w_getrectfn = vu_getrect; | |||
vu_widgetbehavior.w_displacefn = iemgui_displace; | |||
vu_widgetbehavior.w_selectfn = iemgui_select; | |||
vu_widgetbehavior.w_activatefn = NULL; | |||
vu_widgetbehavior.w_deletefn = iemgui_delete; | |||
vu_widgetbehavior.w_visfn = iemgui_vis; | |||
vu_widgetbehavior.w_clickfn = NULL; | |||
class_setwidget(vu_class,&vu_widgetbehavior); | |||
class_sethelpsymbol(vu_class, gensym("vu")); | |||
class_setsavefn(vu_class, vu_save); | |||
class_setpropertiesfn(vu_class, vu_properties); | |||
} |
@@ -0,0 +1,128 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#include "m_pd.h" | |||
#include <stdio.h> | |||
#include <string.h> | |||
/* convenience routines for checking and getting values of | |||
atoms. There's no "pointer" version since there's nothing | |||
safe to return if there's an error. */ | |||
t_float atom_getfloat(t_atom *a) | |||
{ | |||
if (a->a_type == A_FLOAT) return (a->a_w.w_float); | |||
else return (0); | |||
} | |||
t_int atom_getint(t_atom *a) | |||
{ | |||
return (atom_getfloat(a)); | |||
} | |||
t_symbol *atom_getsymbol(t_atom *a) /* LATER think about this more carefully */ | |||
{ | |||
if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol); | |||
else return (&s_float); | |||
} | |||
t_symbol *atom_gensym(t_atom *a) /* this works better for graph labels */ | |||
{ | |||
char buf[30]; | |||
if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol); | |||
else if (a->a_type == A_FLOAT) | |||
sprintf(buf, "%g", a->a_w.w_float); | |||
else strcpy(buf, "???"); | |||
return (gensym(buf)); | |||
} | |||
t_float atom_getfloatarg(int which, int argc, t_atom *argv) | |||
{ | |||
if (argc <= which) return (0); | |||
argv += which; | |||
if (argv->a_type == A_FLOAT) return (argv->a_w.w_float); | |||
else return (0); | |||
} | |||
t_int atom_getintarg(int which, int argc, t_atom *argv) | |||
{ | |||
return (atom_getfloatarg(which, argc, argv)); | |||
} | |||
t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv) | |||
{ | |||
if (argc <= which) return (&s_); | |||
argv += which; | |||
if (argv->a_type == A_SYMBOL) return (argv->a_w.w_symbol); | |||
else return (&s_); | |||
} | |||
/* convert an atom into a string, in the reverse sense of binbuf_text (q.v.) | |||
* special attention is paid to symbols containing the special characters | |||
* ';', ',', '$', and '\'; these are quoted with a preceding '\', except that | |||
* the '$' only gets quoted at the beginning of the string. | |||
*/ | |||
void atom_string(t_atom *a, char *buf, unsigned int bufsize) | |||
{ | |||
char tbuf[30]; | |||
switch(a->a_type) | |||
{ | |||
case A_SEMI: strcpy(buf, ";"); break; | |||
case A_COMMA: strcpy(buf, ","); break; | |||
case A_POINTER: | |||
strcpy(buf, "(pointer)"); | |||
break; | |||
case A_FLOAT: | |||
sprintf(tbuf, "%g", a->a_w.w_float); | |||
if (strlen(tbuf) < bufsize-1) strcpy(buf, tbuf); | |||
else if (a->a_w.w_float < 0) strcpy(buf, "-"); | |||
else strcpy(buf, "+"); | |||
break; | |||
case A_SYMBOL: | |||
{ | |||
char *sp; | |||
unsigned int len; | |||
int quote; | |||
for (sp = a->a_w.w_symbol->s_name, len = 0, quote = 0; *sp; sp++, len++) | |||
if (*sp == ';' || *sp == ',' || *sp == '\\' || | |||
(*sp == '$' && sp[1] >= '0' && sp[1] <= '9')) | |||
quote = 1; | |||
if (quote) | |||
{ | |||
char *bp = buf, *ep = buf + (bufsize-2); | |||
sp = a->a_w.w_symbol->s_name; | |||
while (bp < ep && *sp) | |||
{ | |||
if (*sp == ';' || *sp == ',' || *sp == '\\' || | |||
(*sp == '$' && sp[1] >= '0' && sp[1] <= '9')) | |||
*bp++ = '\\'; | |||
*bp++ = *sp++; | |||
} | |||
if (*sp) *bp++ = '*'; | |||
*bp = 0; | |||
/* post("quote %s -> %s", a->a_w.w_symbol->s_name, buf); */ | |||
} | |||
else | |||
{ | |||
if (len < bufsize-1) strcpy(buf, a->a_w.w_symbol->s_name); | |||
else | |||
{ | |||
strncpy(buf, a->a_w.w_symbol->s_name, bufsize - 2); | |||
strcpy(buf + (bufsize - 2), "*"); | |||
} | |||
} | |||
} | |||
break; | |||
case A_DOLLAR: | |||
sprintf(buf, "$%d", a->a_w.w_index); | |||
break; | |||
case A_DOLLSYM: | |||
strncpy(buf, a->a_w.w_symbol->s_name, bufsize); | |||
buf[bufsize-1] = 0; | |||
break; | |||
default: | |||
bug("atom_string"); | |||
} | |||
} |
@@ -0,0 +1,110 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* changes by Thomas Musil IEM KUG Graz Austria 2001 */ | |||
/* all changes are labeled with iemlib */ | |||
#include "m_pd.h" | |||
void g_array_setup(void); | |||
void g_canvas_setup(void); | |||
void g_guiconnect_setup(void); | |||
/* iemlib */ | |||
void g_bang_setup(void); | |||
void g_hradio_setup(void); | |||
void g_hslider_setup(void); | |||
void g_mycanvas_setup(void); | |||
void g_numbox_setup(void); | |||
void g_toggle_setup(void); | |||
void g_vradio_setup(void); | |||
void g_vslider_setup(void); | |||
void g_vumeter_setup(void); | |||
/* iemlib */ | |||
void g_io_setup(void); | |||
void g_scalar_setup(void); | |||
void g_template_setup(void); | |||
void g_text_setup(void); | |||
void g_traversal_setup(void); | |||
void clone_setup(void); | |||
void m_pd_setup(void); | |||
void x_acoustics_setup(void); | |||
void x_interface_setup(void); | |||
void x_connective_setup(void); | |||
void x_time_setup(void); | |||
void x_arithmetic_setup(void); | |||
void x_array_setup(void); | |||
void x_midi_setup(void); | |||
void x_misc_setup(void); | |||
void x_net_setup(void); | |||
void x_qlist_setup(void); | |||
void x_gui_setup(void); | |||
void x_list_setup(void); | |||
void x_scalar_setup(void); | |||
void expr_setup(void); | |||
void d_arithmetic_setup(void); | |||
void d_array_setup(void); | |||
void d_ctl_setup(void); | |||
void d_dac_setup(void); | |||
void d_delay_setup(void); | |||
void d_fft_setup(void); | |||
void d_filter_setup(void); | |||
void d_global_setup(void); | |||
void d_math_setup(void); | |||
void d_misc_setup(void); | |||
void d_osc_setup(void); | |||
void d_soundfile_setup(void); | |||
void d_ugen_setup(void); | |||
void conf_init(void) | |||
{ | |||
g_array_setup(); | |||
g_canvas_setup(); | |||
g_guiconnect_setup(); | |||
/* iemlib */ | |||
g_bang_setup(); | |||
g_hradio_setup(); | |||
g_hslider_setup(); | |||
g_mycanvas_setup(); | |||
g_numbox_setup(); | |||
g_toggle_setup(); | |||
g_vradio_setup(); | |||
g_vslider_setup(); | |||
g_vumeter_setup(); | |||
/* iemlib */ | |||
g_io_setup(); | |||
g_scalar_setup(); | |||
g_template_setup(); | |||
g_text_setup(); | |||
g_traversal_setup(); | |||
clone_setup(); | |||
m_pd_setup(); | |||
x_acoustics_setup(); | |||
x_interface_setup(); | |||
x_connective_setup(); | |||
x_time_setup(); | |||
x_arithmetic_setup(); | |||
x_array_setup(); | |||
x_midi_setup(); | |||
x_misc_setup(); | |||
x_net_setup(); | |||
x_qlist_setup(); | |||
x_gui_setup(); | |||
x_list_setup(); | |||
x_scalar_setup(); | |||
expr_setup(); | |||
d_arithmetic_setup(); | |||
d_array_setup(); | |||
d_ctl_setup(); | |||
d_dac_setup(); | |||
d_delay_setup(); | |||
d_fft_setup(); | |||
d_filter_setup(); | |||
d_global_setup(); | |||
d_math_setup(); | |||
d_misc_setup(); | |||
d_osc_setup(); | |||
d_soundfile_setup(); | |||
d_ugen_setup(); | |||
} | |||
@@ -0,0 +1,216 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#include "m_pd.h" | |||
#include "m_imp.h" | |||
#include "s_stuff.h" | |||
t_class *glob_pdobject; | |||
static t_class *maxclass; | |||
int sys_perf; /* true if we should query user on close and quit */ | |||
int pd_compatibilitylevel = 100000; /* e.g., 43 for pd 0.43 compatibility */ | |||
/* These "glob" routines, which implement messages to Pd, are from all | |||
over. Some others are prototyped in m_imp.h as well. */ | |||
void glob_menunew(void *dummy, t_symbol *name, t_symbol *dir); | |||
void glob_verifyquit(void *dummy, t_floatarg f); | |||
void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv); | |||
void glob_meters(void *dummy, t_floatarg f); | |||
void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av); | |||
void glob_audiostatus(void *dummy); | |||
void glob_finderror(t_pd *dummy); | |||
void glob_findinstance(t_pd *dummy, t_symbol*s); | |||
void glob_audio_properties(t_pd *dummy, t_floatarg flongform); | |||
void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv); | |||
void glob_audio_setapi(t_pd *dummy, t_floatarg f); | |||
void glob_midi_properties(t_pd *dummy, t_floatarg flongform); | |||
void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv); | |||
void glob_midi_setapi(t_pd *dummy, t_floatarg f); | |||
void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform); | |||
void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv); | |||
void glob_addtopath(t_pd *dummy, t_symbol *path, t_float saveit); | |||
void glob_start_startup_dialog(t_pd *dummy, t_floatarg flongform); | |||
void glob_startup_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv); | |||
void glob_ping(t_pd *dummy); | |||
void glob_plugindispatch(t_pd *dummy, t_symbol *s, int argc, t_atom *argv); | |||
void glob_watchdog(t_pd *dummy); | |||
void glob_loadpreferences(t_pd *dummy, t_symbol *s); | |||
void glob_savepreferences(t_pd *dummy, t_symbol *s); | |||
void glob_forgetpreferences(t_pd *dummy); | |||
static void glob_helpintro(t_pd *dummy) | |||
{ | |||
open_via_helppath("intro.pd", ""); | |||
} | |||
static void glob_compatibility(t_pd *dummy, t_floatarg level) | |||
{ | |||
int dspwas = canvas_suspend_dsp(); | |||
pd_compatibilitylevel = 0.5 + 100. * level; | |||
canvas_resume_dsp(dspwas); | |||
} | |||
#ifdef _WIN32 | |||
void glob_audio(void *dummy, t_floatarg adc, t_floatarg dac); | |||
#endif | |||
/* a method you add for debugging printout */ | |||
void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv); | |||
#if 0 | |||
void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
post("foo 1"); | |||
printf("barbarbar 2\n"); | |||
post("foo 3"); | |||
} | |||
#endif | |||
static void glob_version(t_pd *dummy, float f) | |||
{ | |||
if (f > (PD_MAJOR_VERSION + 0.01*PD_MINOR_VERSION + 0.001)) | |||
{ | |||
static int warned; | |||
if (warned < 1) | |||
post("warning: file format (%g) newer than this version (%g) of Pd", | |||
f, PD_MAJOR_VERSION + 0.01*PD_MINOR_VERSION); | |||
else if (warned < 2) | |||
post("(... more file format messages suppressed)"); | |||
warned++; | |||
} | |||
} | |||
static void glob_perf(t_pd *dummy, float f) | |||
{ | |||
sys_perf = (f != 0); | |||
} | |||
void max_default(t_pd *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
int i; | |||
char str[80]; | |||
startpost("%s: unknown message %s ", class_getname(pd_class(x)), | |||
s->s_name); | |||
for (i = 0; i < argc; i++) | |||
{ | |||
atom_string(argv+i, str, 80); | |||
poststring(str); | |||
} | |||
endpost(); | |||
} | |||
void glob_plugindispatch(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
int i; | |||
char str[80]; | |||
sys_vgui("pdtk_plugin_dispatch "); | |||
for (i = 0; i < argc; i++) | |||
{ | |||
atom_string(argv+i, str, 80); | |||
sys_vgui("%s", str); | |||
if (i < argc-1) { | |||
sys_vgui(" "); | |||
} | |||
} | |||
sys_vgui("\n"); | |||
} | |||
int sys_zoom_open = 1; | |||
void glob_zoom_open(t_pd *dummy, t_floatarg f) | |||
{ | |||
sys_zoom_open = (f != 0 ? 2 : 1); | |||
} | |||
void glob_init(void) | |||
{ | |||
maxclass = class_new(gensym("max"), 0, 0, sizeof(t_pd), | |||
CLASS_DEFAULT, A_NULL); | |||
class_addanything(maxclass, max_default); | |||
pd_bind(&maxclass, gensym("max")); | |||
glob_pdobject = class_new(gensym("pd"), 0, 0, sizeof(t_pd), | |||
CLASS_DEFAULT, A_NULL); | |||
class_addmethod(glob_pdobject, (t_method)glob_initfromgui, gensym("init"), | |||
A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_menunew, gensym("menunew"), | |||
A_SYMBOL, A_SYMBOL, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_evalfile, gensym("open"), | |||
A_SYMBOL, A_SYMBOL, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_quit, gensym("quit"), 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_verifyquit, | |||
gensym("verifyquit"), A_DEFFLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_foo, gensym("foo"), A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_dsp, gensym("dsp"), A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_meters, gensym("meters"), | |||
A_FLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_key, gensym("key"), A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_audiostatus, | |||
gensym("audiostatus"), 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_finderror, | |||
gensym("finderror"), 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_findinstance, | |||
gensym("findinstance"), A_SYMBOL, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_audio_properties, | |||
gensym("audio-properties"), A_DEFFLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_audio_dialog, | |||
gensym("audio-dialog"), A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_audio_setapi, | |||
gensym("audio-setapi"), A_FLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_midi_setapi, | |||
gensym("midi-setapi"), A_FLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_midi_properties, | |||
gensym("midi-properties"), A_DEFFLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_midi_dialog, | |||
gensym("midi-dialog"), A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_start_path_dialog, | |||
gensym("start-path-dialog"), 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_path_dialog, | |||
gensym("path-dialog"), A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_addtopath, | |||
gensym("add-to-path"), A_SYMBOL, A_DEFFLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_start_startup_dialog, | |||
gensym("start-startup-dialog"), 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_startup_dialog, | |||
gensym("startup-dialog"), A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_ping, gensym("ping"), 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_loadpreferences, | |||
gensym("load-preferences"), A_DEFSYM, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_savepreferences, | |||
gensym("save-preferences"), A_DEFSYM, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_forgetpreferences, | |||
gensym("forget-preferences"), A_DEFSYM, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_zoom_open, | |||
gensym("zoom-open"), A_FLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_version, | |||
gensym("version"), A_FLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_perf, | |||
gensym("perf"), A_FLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_compatibility, | |||
gensym("compatibility"), A_FLOAT, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_plugindispatch, | |||
gensym("plugin-dispatch"), A_GIMME, 0); | |||
class_addmethod(glob_pdobject, (t_method)glob_helpintro, | |||
gensym("help-intro"), A_GIMME, 0); | |||
#if defined(__linux__) || defined(__FreeBSD_kernel__) | |||
class_addmethod(glob_pdobject, (t_method)glob_watchdog, | |||
gensym("watchdog"), 0); | |||
#endif | |||
class_addanything(glob_pdobject, max_default); | |||
pd_bind(&glob_pdobject, gensym("pd")); | |||
} | |||
/* function to return version number at run time. Any of the | |||
calling pointers may be zero in case you don't need all of them. */ | |||
void sys_getversion(int *major, int *minor, int *bugfix) | |||
{ | |||
if (major) | |||
*major = PD_MAJOR_VERSION; | |||
if (minor) | |||
*minor = PD_MINOR_VERSION; | |||
if (bugfix) | |||
*bugfix = PD_BUGFIX_VERSION; | |||
} | |||
@@ -0,0 +1,98 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* This file contains function prototypes and data types used to implement | |||
Pd, but not shared with Pd objects. */ | |||
/* NOTE: this file describes Pd implementation details which may change | |||
in future releases. The public (stable) API is in m_pd.h. */ | |||
/* LATER consider whether to use 'char' for method arg types to save space */ | |||
#ifndef __m_imp_h_ | |||
/* the structure for a method handler ala Max */ | |||
typedef struct _methodentry | |||
{ | |||
t_symbol *me_name; | |||
t_gotfn me_fun; | |||
t_atomtype me_arg[MAXPDARG+1]; | |||
} t_methodentry; | |||
EXTERN_STRUCT _widgetbehavior; | |||
typedef void (*t_bangmethod)(t_pd *x); | |||
typedef void (*t_pointermethod)(t_pd *x, t_gpointer *gp); | |||
typedef void (*t_floatmethod)(t_pd *x, t_float f); | |||
typedef void (*t_symbolmethod)(t_pd *x, t_symbol *s); | |||
typedef void (*t_listmethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv); | |||
typedef void (*t_anymethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv); | |||
struct _class | |||
{ | |||
t_symbol *c_name; /* name (mostly for error reporting) */ | |||
t_symbol *c_helpname; /* name of help file */ | |||
t_symbol *c_externdir; /* directory extern was loaded from */ | |||
size_t c_size; /* size of an instance */ | |||
#ifdef PDINSTANCE | |||
t_methodentry **c_methods; /* methods other than bang, etc below */ | |||
#else | |||
t_methodentry *c_methods; | |||
#endif | |||
int c_nmethod; /* number of methods */ | |||
t_method c_freemethod; /* function to call before freeing */ | |||
t_bangmethod c_bangmethod; /* common methods */ | |||
t_pointermethod c_pointermethod; | |||
t_floatmethod c_floatmethod; | |||
t_symbolmethod c_symbolmethod; | |||
t_listmethod c_listmethod; | |||
t_anymethod c_anymethod; | |||
const struct _widgetbehavior *c_wb; /* "gobjs" only */ | |||
const struct _parentwidgetbehavior *c_pwb;/* widget behavior in parent */ | |||
t_savefn c_savefn; /* function to call when saving */ | |||
t_propertiesfn c_propertiesfn; /* function to start prop dialog */ | |||
struct _class *c_next; | |||
int c_floatsignalin; /* onset to float for signal input */ | |||
char c_gobj; /* true if is a gobj */ | |||
char c_patchable; /* true if we have a t_object header */ | |||
char c_firstin; /* if patchable, true if draw first inlet */ | |||
char c_drawcommand; /* a drawing command for a template */ | |||
}; | |||
/* m_class.c */ | |||
EXTERN void pd_emptylist(t_pd *x); | |||
/* m_obj.c */ | |||
EXTERN int obj_noutlets(t_object *x); | |||
EXTERN int obj_ninlets(t_object *x); | |||
EXTERN t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, | |||
int nout); | |||
EXTERN t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect, | |||
t_object **destp, t_inlet **inletp, int *whichp); | |||
EXTERN t_outconnect *obj_connect(t_object *source, int outno, | |||
t_object *sink, int inno); | |||
EXTERN void obj_disconnect(t_object *source, int outno, t_object *sink, | |||
int inno); | |||
EXTERN void outlet_setstacklim(void); | |||
EXTERN int obj_issignalinlet(t_object *x, int m); | |||
EXTERN int obj_issignaloutlet(t_object *x, int m); | |||
EXTERN int obj_nsiginlets(t_object *x); | |||
EXTERN int obj_nsigoutlets(t_object *x); | |||
EXTERN int obj_siginletindex(t_object *x, int m); | |||
EXTERN int obj_sigoutletindex(t_object *x, int m); | |||
/* s_inter.c */ | |||
void pd_globallock( void); | |||
void pd_globalunlock( void); | |||
/* misc */ | |||
#define SYMTABHASHSIZE 1024 | |||
EXTERN t_pd *glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir); | |||
EXTERN void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv); | |||
EXTERN void glob_quit(void *dummy); | |||
EXTERN void open_via_helppath(const char *name, const char *dir); | |||
#define __m_imp_h_ | |||
#endif /* __m_imp_h_ */ |
@@ -0,0 +1,89 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "m_pd.h" | |||
#include "m_imp.h" | |||
/* #define LOUD */ | |||
#ifdef LOUD | |||
#include <stdio.h> | |||
#endif | |||
/* #define DEBUGMEM */ | |||
#ifdef DEBUGMEM | |||
static int totalmem = 0; | |||
#endif | |||
void *getbytes(size_t nbytes) | |||
{ | |||
void *ret; | |||
if (nbytes < 1) nbytes = 1; | |||
ret = (void *)calloc(nbytes, 1); | |||
#ifdef LOUD | |||
fprintf(stderr, "new %lx %d\n", (int)ret, nbytes); | |||
#endif /* LOUD */ | |||
#ifdef DEBUGMEM | |||
totalmem += nbytes; | |||
#endif | |||
if (!ret) | |||
post("pd: getbytes() failed -- out of memory"); | |||
return (ret); | |||
} | |||
void *getzbytes(size_t nbytes) /* obsolete name */ | |||
{ | |||
return (getbytes(nbytes)); | |||
} | |||
void *copybytes(void *src, size_t nbytes) | |||
{ | |||
void *ret; | |||
ret = getbytes(nbytes); | |||
if (nbytes) | |||
memcpy(ret, src, nbytes); | |||
return (ret); | |||
} | |||
void *resizebytes(void *old, size_t oldsize, size_t newsize) | |||
{ | |||
void *ret; | |||
if (newsize < 1) newsize = 1; | |||
if (oldsize < 1) oldsize = 1; | |||
ret = (void *)realloc((char *)old, newsize); | |||
if (newsize > oldsize && ret) | |||
memset(((char *)ret) + oldsize, 0, newsize - oldsize); | |||
#ifdef LOUD | |||
fprintf(stderr, "resize %lx %d --> %lx %d\n", (int)old, oldsize, (int)ret, newsize); | |||
#endif /* LOUD */ | |||
#ifdef DEBUGMEM | |||
totalmem += (newsize - oldsize); | |||
#endif | |||
if (!ret) | |||
post("pd: resizebytes() failed -- out of memory"); | |||
return (ret); | |||
} | |||
void freebytes(void *fatso, size_t nbytes) | |||
{ | |||
if (nbytes == 0) | |||
nbytes = 1; | |||
#ifdef LOUD | |||
fprintf(stderr, "free %lx %d\n", (int)fatso, nbytes); | |||
#endif /* LOUD */ | |||
#ifdef DEBUGMEM | |||
totalmem -= nbytes; | |||
#endif | |||
free(fatso); | |||
} | |||
#ifdef DEBUGMEM | |||
#include <stdio.h> | |||
void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
fprintf(stderr, "total mem %d\n", totalmem); | |||
} | |||
#endif |
@@ -0,0 +1,756 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* this file handles Max-style patchable objects, i.e., objects which | |||
can interconnect via inlets and outlets; also, the (terse) generic | |||
behavior for "gobjs" appears at the end of this file. */ | |||
#include "m_pd.h" | |||
#include "m_imp.h" | |||
union inletunion | |||
{ | |||
t_symbol *iu_symto; | |||
t_gpointer *iu_pointerslot; | |||
t_float *iu_floatslot; | |||
t_symbol **iu_symslot; | |||
t_float iu_floatsignalvalue; | |||
}; | |||
struct _inlet | |||
{ | |||
t_pd i_pd; | |||
struct _inlet *i_next; | |||
t_object *i_owner; | |||
t_pd *i_dest; | |||
t_symbol *i_symfrom; | |||
union inletunion i_un; | |||
}; | |||
#define i_symto i_un.iu_symto | |||
#define i_pointerslot i_un.iu_pointerslot | |||
#define i_floatslot i_un.iu_floatslot | |||
#define i_symslot i_un.iu_symslot | |||
static t_class *inlet_class, *pointerinlet_class, *floatinlet_class, | |||
*symbolinlet_class; | |||
#define ISINLET(pd) ((*(pd) == inlet_class) || \ | |||
(*(pd) == pointerinlet_class) || \ | |||
(*(pd) == floatinlet_class) || \ | |||
(*(pd) == symbolinlet_class)) | |||
/* --------------------- generic inlets ala max ------------------ */ | |||
t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2) | |||
{ | |||
t_inlet *x = (t_inlet *)pd_new(inlet_class), *y, *y2; | |||
x->i_owner = owner; | |||
x->i_dest = dest; | |||
if (s1 == &s_signal) | |||
x->i_un.iu_floatsignalvalue = 0; | |||
else x->i_symto = s2; | |||
x->i_symfrom = s1; | |||
x->i_next = 0; | |||
if ((y = owner->ob_inlet)) | |||
{ | |||
while ((y2 = y->i_next)) y = y2; | |||
y->i_next = x; | |||
} | |||
else owner->ob_inlet = x; | |||
return (x); | |||
} | |||
t_inlet *signalinlet_new(t_object *owner, t_float f) | |||
{ | |||
t_inlet *x = inlet_new(owner, &owner->ob_pd, &s_signal, &s_signal); | |||
x->i_un.iu_floatsignalvalue = f; | |||
return (x); | |||
} | |||
static void inlet_wrong(t_inlet *x, t_symbol *s) | |||
{ | |||
pd_error(x->i_owner, "inlet: expected '%s' but got '%s'", | |||
x->i_symfrom->s_name, s->s_name); | |||
} | |||
static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv); | |||
/* LATER figure out how to make these efficient: */ | |||
static void inlet_bang(t_inlet *x) | |||
{ | |||
if (x->i_symfrom == &s_bang) | |||
pd_vmess(x->i_dest, x->i_symto, ""); | |||
else if (!x->i_symfrom) pd_bang(x->i_dest); | |||
else if (x->i_symfrom == &s_list) | |||
inlet_list(x, &s_bang, 0, 0); | |||
else inlet_wrong(x, &s_bang); | |||
} | |||
static void inlet_pointer(t_inlet *x, t_gpointer *gp) | |||
{ | |||
if (x->i_symfrom == &s_pointer) | |||
pd_vmess(x->i_dest, x->i_symto, "p", gp); | |||
else if (!x->i_symfrom) pd_pointer(x->i_dest, gp); | |||
else if (x->i_symfrom == &s_list) | |||
{ | |||
t_atom a; | |||
SETPOINTER(&a, gp); | |||
inlet_list(x, &s_pointer, 1, &a); | |||
} | |||
else inlet_wrong(x, &s_pointer); | |||
} | |||
static void inlet_float(t_inlet *x, t_float f) | |||
{ | |||
if (x->i_symfrom == &s_float) | |||
pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f); | |||
else if (x->i_symfrom == &s_signal) | |||
x->i_un.iu_floatsignalvalue = f; | |||
else if (!x->i_symfrom) | |||
pd_float(x->i_dest, f); | |||
else if (x->i_symfrom == &s_list) | |||
{ | |||
t_atom a; | |||
SETFLOAT(&a, f); | |||
inlet_list(x, &s_float, 1, &a); | |||
} | |||
else inlet_wrong(x, &s_float); | |||
} | |||
static void inlet_symbol(t_inlet *x, t_symbol *s) | |||
{ | |||
if (x->i_symfrom == &s_symbol) | |||
pd_vmess(x->i_dest, x->i_symto, "s", s); | |||
else if (!x->i_symfrom) pd_symbol(x->i_dest, s); | |||
else if (x->i_symfrom == &s_list) | |||
{ | |||
t_atom a; | |||
SETSYMBOL(&a, s); | |||
inlet_list(x, &s_symbol, 1, &a); | |||
} | |||
else inlet_wrong(x, &s_symbol); | |||
} | |||
static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_atom at; | |||
if (x->i_symfrom == &s_list || x->i_symfrom == &s_float | |||
|| x->i_symfrom == &s_symbol || x->i_symfrom == &s_pointer) | |||
typedmess(x->i_dest, x->i_symto, argc, argv); | |||
else if (!x->i_symfrom) pd_list(x->i_dest, s, argc, argv); | |||
else if (!argc) | |||
inlet_bang(x); | |||
else if (argc==1 && argv->a_type == A_FLOAT) | |||
inlet_float(x, atom_getfloat(argv)); | |||
else if (argc==1 && argv->a_type == A_SYMBOL) | |||
inlet_symbol(x, atom_getsymbol(argv)); | |||
else inlet_wrong(x, &s_list); | |||
} | |||
static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
if (x->i_symfrom == s) | |||
typedmess(x->i_dest, x->i_symto, argc, argv); | |||
else if (!x->i_symfrom) | |||
typedmess(x->i_dest, s, argc, argv); | |||
else inlet_wrong(x, s); | |||
} | |||
void inlet_free(t_inlet *x) | |||
{ | |||
t_object *y = x->i_owner; | |||
t_inlet *x2; | |||
if (y->ob_inlet == x) y->ob_inlet = x->i_next; | |||
else for (x2 = y->ob_inlet; x2; x2 = x2->i_next) | |||
if (x2->i_next == x) | |||
{ | |||
x2->i_next = x->i_next; | |||
break; | |||
} | |||
t_freebytes(x, sizeof(*x)); | |||
} | |||
/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */ | |||
static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp) | |||
{ | |||
gpointer_unset(x->i_pointerslot); | |||
*(x->i_pointerslot) = *gp; | |||
if (gp->gp_stub) gp->gp_stub->gs_refcount++; | |||
} | |||
t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp) | |||
{ | |||
t_inlet *x = (t_inlet *)pd_new(pointerinlet_class), *y, *y2; | |||
x->i_owner = owner; | |||
x->i_dest = 0; | |||
x->i_symfrom = &s_pointer; | |||
x->i_pointerslot = gp; | |||
x->i_next = 0; | |||
if ((y = owner->ob_inlet)) | |||
{ | |||
while ((y2 = y->i_next)) y = y2; | |||
y->i_next = x; | |||
} | |||
else owner->ob_inlet = x; | |||
return (x); | |||
} | |||
static void floatinlet_float(t_inlet *x, t_float f) | |||
{ | |||
*(x->i_floatslot) = f; | |||
} | |||
t_inlet *floatinlet_new(t_object *owner, t_float *fp) | |||
{ | |||
t_inlet *x = (t_inlet *)pd_new(floatinlet_class), *y, *y2; | |||
x->i_owner = owner; | |||
x->i_dest = 0; | |||
x->i_symfrom = &s_float; | |||
x->i_floatslot = fp; | |||
x->i_next = 0; | |||
if ((y = owner->ob_inlet)) | |||
{ | |||
while ((y2 = y->i_next)) y = y2; | |||
y->i_next = x; | |||
} | |||
else owner->ob_inlet = x; | |||
return (x); | |||
} | |||
static void symbolinlet_symbol(t_inlet *x, t_symbol *s) | |||
{ | |||
*(x->i_symslot) = s; | |||
} | |||
t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp) | |||
{ | |||
t_inlet *x = (t_inlet *)pd_new(symbolinlet_class), *y, *y2; | |||
x->i_owner = owner; | |||
x->i_dest = 0; | |||
x->i_symfrom = &s_symbol; | |||
x->i_symslot = sp; | |||
x->i_next = 0; | |||
if ((y = owner->ob_inlet)) | |||
{ | |||
while ((y2 = y->i_next)) y = y2; | |||
y->i_next = x; | |||
} | |||
else owner->ob_inlet = x; | |||
return (x); | |||
} | |||
/* ---------------------- routine to handle lists ---------------------- */ | |||
/* objects interpret lists by feeding them to the individual inlets. | |||
Before you call this check that the object doesn't have a more | |||
specific way to handle lists. */ | |||
void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_atom *ap; | |||
int count; | |||
t_inlet *ip = ((t_object *)x)->ob_inlet; | |||
if (!argc) | |||
{ | |||
pd_emptylist(&x->ob_pd); | |||
return; | |||
} | |||
for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->i_next) | |||
{ | |||
if (ap->a_type == A_POINTER) pd_pointer(&ip->i_pd, ap->a_w.w_gpointer); | |||
else if (ap->a_type == A_FLOAT) pd_float(&ip->i_pd, ap->a_w.w_float); | |||
else pd_symbol(&ip->i_pd, ap->a_w.w_symbol); | |||
} | |||
if (argv->a_type == A_POINTER) pd_pointer(&x->ob_pd, argv->a_w.w_gpointer); | |||
else if (argv->a_type == A_FLOAT) pd_float(&x->ob_pd, argv->a_w.w_float); | |||
else pd_symbol(&x->ob_pd, argv->a_w.w_symbol); | |||
} | |||
void obj_init(void) | |||
{ | |||
inlet_class = class_new(gensym("inlet"), 0, 0, | |||
sizeof(t_inlet), CLASS_PD, 0); | |||
class_addbang(inlet_class, inlet_bang); | |||
class_addpointer(inlet_class, inlet_pointer); | |||
class_addfloat(inlet_class, inlet_float); | |||
class_addsymbol(inlet_class, inlet_symbol); | |||
class_addlist(inlet_class, inlet_list); | |||
class_addanything(inlet_class, inlet_anything); | |||
pointerinlet_class = class_new(gensym("inlet"), 0, 0, | |||
sizeof(t_inlet), CLASS_PD, 0); | |||
class_addpointer(pointerinlet_class, pointerinlet_pointer); | |||
class_addanything(pointerinlet_class, inlet_wrong); | |||
floatinlet_class = class_new(gensym("inlet"), 0, 0, | |||
sizeof(t_inlet), CLASS_PD, 0); | |||
class_addfloat(floatinlet_class, (t_method)floatinlet_float); | |||
class_addanything(floatinlet_class, inlet_wrong); | |||
symbolinlet_class = class_new(gensym("inlet"), 0, 0, | |||
sizeof(t_inlet), CLASS_PD, 0); | |||
class_addsymbol(symbolinlet_class, symbolinlet_symbol); | |||
class_addanything(symbolinlet_class, inlet_wrong); | |||
} | |||
/* --------------------------- outlets ------------------------------ */ | |||
static PERTHREAD int stackcount = 0; /* iteration counter */ | |||
#define STACKITER 1000 /* maximum iterations allowed */ | |||
static PERTHREAD int outlet_eventno; | |||
/* set a stack limit (on each incoming event that can set off messages) | |||
for the outlet functions to check to prevent stack overflow from message | |||
recursion */ | |||
void outlet_setstacklim(void) | |||
{ | |||
outlet_eventno++; | |||
} | |||
/* get a number unique to the (clock, MIDI, GUI, etc.) event we're on */ | |||
int sched_geteventno( void) | |||
{ | |||
return (outlet_eventno); | |||
} | |||
struct _outconnect | |||
{ | |||
struct _outconnect *oc_next; | |||
t_pd *oc_to; | |||
}; | |||
struct _outlet | |||
{ | |||
t_object *o_owner; | |||
struct _outlet *o_next; | |||
t_outconnect *o_connections; | |||
t_symbol *o_sym; | |||
}; | |||
t_outlet *outlet_new(t_object *owner, t_symbol *s) | |||
{ | |||
t_outlet *x = (t_outlet *)getbytes(sizeof(*x)), *y, *y2; | |||
x->o_owner = owner; | |||
x->o_next = 0; | |||
if ((y = owner->ob_outlet)) | |||
{ | |||
while ((y2 = y->o_next)) y = y2; | |||
y->o_next = x; | |||
} | |||
else owner->ob_outlet = x; | |||
x->o_connections = 0; | |||
x->o_sym = s; | |||
return (x); | |||
} | |||
static void outlet_stackerror(t_outlet *x) | |||
{ | |||
pd_error(x->o_owner, "stack overflow"); | |||
} | |||
void outlet_bang(t_outlet *x) | |||
{ | |||
t_outconnect *oc; | |||
if(++stackcount >= STACKITER) | |||
outlet_stackerror(x); | |||
else | |||
for (oc = x->o_connections; oc; oc = oc->oc_next) | |||
pd_bang(oc->oc_to); | |||
--stackcount; | |||
} | |||
void outlet_pointer(t_outlet *x, t_gpointer *gp) | |||
{ | |||
t_outconnect *oc; | |||
t_gpointer gpointer; | |||
if(++stackcount >= STACKITER) | |||
outlet_stackerror(x); | |||
else | |||
{ | |||
gpointer = *gp; | |||
for (oc = x->o_connections; oc; oc = oc->oc_next) | |||
pd_pointer(oc->oc_to, &gpointer); | |||
} | |||
--stackcount; | |||
} | |||
void outlet_float(t_outlet *x, t_float f) | |||
{ | |||
t_outconnect *oc; | |||
if(++stackcount >= STACKITER) | |||
outlet_stackerror(x); | |||
else | |||
for (oc = x->o_connections; oc; oc = oc->oc_next) | |||
pd_float(oc->oc_to, f); | |||
--stackcount; | |||
} | |||
void outlet_symbol(t_outlet *x, t_symbol *s) | |||
{ | |||
t_outconnect *oc; | |||
if(++stackcount >= STACKITER) | |||
outlet_stackerror(x); | |||
else | |||
for (oc = x->o_connections; oc; oc = oc->oc_next) | |||
pd_symbol(oc->oc_to, s); | |||
--stackcount; | |||
} | |||
void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_outconnect *oc; | |||
if(++stackcount >= STACKITER) | |||
outlet_stackerror(x); | |||
else | |||
for (oc = x->o_connections; oc; oc = oc->oc_next) | |||
pd_list(oc->oc_to, s, argc, argv); | |||
--stackcount; | |||
} | |||
void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_outconnect *oc; | |||
if(++stackcount >= STACKITER) | |||
outlet_stackerror(x); | |||
else | |||
for (oc = x->o_connections; oc; oc = oc->oc_next) | |||
typedmess(oc->oc_to, s, argc, argv); | |||
--stackcount; | |||
} | |||
/* get the outlet's declared symbol */ | |||
t_symbol *outlet_getsymbol(t_outlet *x) | |||
{ | |||
return (x->o_sym); | |||
} | |||
void outlet_free(t_outlet *x) | |||
{ | |||
t_object *y = x->o_owner; | |||
t_outlet *x2; | |||
if (y->ob_outlet == x) y->ob_outlet = x->o_next; | |||
else for (x2 = y->ob_outlet; x2; x2 = x2->o_next) | |||
if (x2->o_next == x) | |||
{ | |||
x2->o_next = x->o_next; | |||
break; | |||
} | |||
t_freebytes(x, sizeof(*x)); | |||
} | |||
/* connect an outlet of one object to an inlet of another. The receiving | |||
"pd" is usually a patchable object, but this may be used to add a | |||
non-patchable pd to an outlet by specifying the 0th inlet. */ | |||
t_outconnect *obj_connect(t_object *source, int outno, | |||
t_object *sink, int inno) | |||
{ | |||
t_inlet *i; | |||
t_outlet *o; | |||
t_pd *to; | |||
t_outconnect *oc, *oc2; | |||
for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ; | |||
if (!o) return (0); | |||
if (sink->ob_pd->c_firstin) | |||
{ | |||
if (!inno) | |||
{ | |||
to = &sink->ob_pd; | |||
goto doit; | |||
} | |||
else inno--; | |||
} | |||
for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ; | |||
if (!i) return (0); | |||
to = &i->i_pd; | |||
doit: | |||
oc = (t_outconnect *)t_getbytes(sizeof(*oc)); | |||
oc->oc_next = 0; | |||
oc->oc_to = to; | |||
/* append it to the end of the list */ | |||
/* LATER we might cache the last "oc" to make this faster. */ | |||
if ((oc2 = o->o_connections)) | |||
{ | |||
while (oc2->oc_next) oc2 = oc2->oc_next; | |||
oc2->oc_next = oc; | |||
} | |||
else o->o_connections = oc; | |||
if (o->o_sym == &s_signal) canvas_update_dsp(); | |||
return (oc); | |||
} | |||
void obj_disconnect(t_object *source, int outno, t_object *sink, int inno) | |||
{ | |||
t_inlet *i; | |||
t_outlet *o; | |||
t_pd *to; | |||
t_outconnect *oc, *oc2; | |||
for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ; | |||
if (!o) return; | |||
if (sink->ob_pd->c_firstin) | |||
{ | |||
if (!inno) | |||
{ | |||
to = &sink->ob_pd; | |||
goto doit; | |||
} | |||
else inno--; | |||
} | |||
for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ; | |||
if (!i) return; | |||
to = &i->i_pd; | |||
doit: | |||
if (!(oc = o->o_connections)) return; | |||
if (oc->oc_to == to) | |||
{ | |||
o->o_connections = oc->oc_next; | |||
freebytes(oc, sizeof(*oc)); | |||
goto done; | |||
} | |||
while ((oc2 = oc->oc_next)) | |||
{ | |||
if (oc2->oc_to == to) | |||
{ | |||
oc->oc_next = oc2->oc_next; | |||
freebytes(oc2, sizeof(*oc2)); | |||
goto done; | |||
} | |||
oc = oc2; | |||
} | |||
done: | |||
if (o->o_sym == &s_signal) canvas_update_dsp(); | |||
} | |||
/* ------ traversal routines for code that can't see our structures ------ */ | |||
int obj_noutlets(t_object *x) | |||
{ | |||
int n; | |||
t_outlet *o; | |||
for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++; | |||
return (n); | |||
} | |||
int obj_ninlets(t_object *x) | |||
{ | |||
int n; | |||
t_inlet *i; | |||
for (i = x->ob_inlet, n = 0; i; i = i->i_next) n++; | |||
if (x->ob_pd->c_firstin) n++; | |||
return (n); | |||
} | |||
t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout) | |||
{ | |||
t_outlet *o = x->ob_outlet; | |||
while (nout-- && o) o = o->o_next; | |||
*op = o; | |||
if (o) return (o->o_connections); | |||
else return (0); | |||
} | |||
t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect, | |||
t_object **destp, t_inlet **inletp, int *whichp) | |||
{ | |||
t_pd *y; | |||
y = lastconnect->oc_to; | |||
if (ISINLET(y)) | |||
{ | |||
int n; | |||
t_inlet *i = (t_inlet *)y, *i2; | |||
t_object *dest = i->i_owner; | |||
for (n = dest->ob_pd->c_firstin, i2 = dest->ob_inlet; | |||
i2 && i2 != i; i2 = i2->i_next) n++; | |||
*whichp = n; | |||
*destp = dest; | |||
*inletp = i; | |||
} | |||
else | |||
{ | |||
*whichp = 0; | |||
*inletp = 0; | |||
*destp = ((t_object *)y); | |||
} | |||
return (lastconnect->oc_next); | |||
} | |||
/* this one checks that a pd is indeed a patchable object, and returns | |||
it, correctly typed, or zero if the check failed. */ | |||
t_object *pd_checkobject(t_pd *x) | |||
{ | |||
if ((*x)->c_patchable) return ((t_object *)x); | |||
else return (0); | |||
} | |||
/* move an inlet or outlet to the head of the list */ | |||
void obj_moveinletfirst(t_object *x, t_inlet *i) | |||
{ | |||
t_inlet *i2; | |||
if (x->ob_inlet == i) return; | |||
else for (i2 = x->ob_inlet; i2; i2 = i2->i_next) | |||
if (i2->i_next == i) | |||
{ | |||
i2->i_next = i->i_next; | |||
i->i_next = x->ob_inlet; | |||
x->ob_inlet = i; | |||
return; | |||
} | |||
} | |||
void obj_moveoutletfirst(t_object *x, t_outlet *o) | |||
{ | |||
t_outlet *o2; | |||
if (x->ob_outlet == o) return; | |||
else for (o2 = x->ob_outlet; o2; o2 = o2->o_next) | |||
if (o2->o_next == o) | |||
{ | |||
o2->o_next = o->o_next; | |||
o->o_next = x->ob_outlet; | |||
x->ob_outlet = o; | |||
return; | |||
} | |||
} | |||
/* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */ | |||
/* LATER try to consolidate all the slightly different routines. */ | |||
int obj_nsiginlets(t_object *x) | |||
{ | |||
int n; | |||
t_inlet *i; | |||
for (i = x->ob_inlet, n = 0; i; i = i->i_next) | |||
if (i->i_symfrom == &s_signal) n++; | |||
if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) n++; | |||
return (n); | |||
} | |||
/* get the index, among signal inlets, of the mth inlet overall */ | |||
int obj_siginletindex(t_object *x, int m) | |||
{ | |||
int n = 0; | |||
t_inlet *i; | |||
if (x->ob_pd->c_firstin) | |||
{ | |||
if (!m--) | |||
return (0); | |||
if (x->ob_pd->c_floatsignalin) | |||
n++; | |||
} | |||
for (i = x->ob_inlet; i; i = i->i_next, m--) | |||
if (i->i_symfrom == &s_signal) | |||
{ | |||
if (m == 0) return (n); | |||
n++; | |||
} | |||
return (-1); | |||
} | |||
int obj_issignalinlet(t_object *x, int m) | |||
{ | |||
t_inlet *i; | |||
if (x->ob_pd->c_firstin) | |||
{ | |||
if (!m) | |||
return (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin); | |||
else m--; | |||
} | |||
for (i = x->ob_inlet; i && m; i = i->i_next, m--) | |||
; | |||
return (i && (i->i_symfrom == &s_signal)); | |||
} | |||
int obj_nsigoutlets(t_object *x) | |||
{ | |||
int n; | |||
t_outlet *o; | |||
for (o = x->ob_outlet, n = 0; o; o = o->o_next) | |||
if (o->o_sym == &s_signal) n++; | |||
return (n); | |||
} | |||
int obj_sigoutletindex(t_object *x, int m) | |||
{ | |||
int n; | |||
t_outlet *o2; | |||
for (o2 = x->ob_outlet, n = 0; o2; o2 = o2->o_next, m--) | |||
if (o2->o_sym == &s_signal) | |||
{ | |||
if (m == 0) return (n); | |||
n++; | |||
} | |||
return (-1); | |||
} | |||
int obj_issignaloutlet(t_object *x, int m) | |||
{ | |||
int n; | |||
t_outlet *o2; | |||
for (o2 = x->ob_outlet, n = 0; o2 && m--; o2 = o2->o_next); | |||
return (o2 && (o2->o_sym == &s_signal)); | |||
} | |||
t_float *obj_findsignalscalar(t_object *x, int m) | |||
{ | |||
t_inlet *i; | |||
if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) | |||
{ | |||
if (!m--) | |||
return (x->ob_pd->c_floatsignalin > 0 ? | |||
(t_float *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0); | |||
} | |||
for (i = x->ob_inlet; i; i = i->i_next) | |||
if (i->i_symfrom == &s_signal) | |||
{ | |||
if (m-- == 0) | |||
return (&i->i_un.iu_floatsignalvalue); | |||
} | |||
return (0); | |||
} | |||
/* and these are only used in g_io.c... */ | |||
int inlet_getsignalindex(t_inlet *x) | |||
{ | |||
int n = 0; | |||
t_inlet *i; | |||
if (x->i_symfrom != &s_signal) | |||
bug("inlet_getsignalindex"); | |||
for (i = x->i_owner->ob_inlet, n = 0; i && i != x; i = i->i_next) | |||
if (i->i_symfrom == &s_signal) n++; | |||
return (n); | |||
} | |||
int outlet_getsignalindex(t_outlet *x) | |||
{ | |||
int n = 0; | |||
t_outlet *o; | |||
for (o = x->o_owner->ob_outlet, n = 0; o && o != x; o = o->o_next) | |||
if (o->o_sym == &s_signal) n++; | |||
return (n); | |||
} | |||
void obj_saveformat(t_object *x, t_binbuf *bb) | |||
{ | |||
if (x->te_width) | |||
binbuf_addv(bb, "ssf;", &s__X, gensym("f"), (float)x->te_width); | |||
} | |||
/* this one only in g_clone.c -- LATER consider sending the message | |||
without having to chase the linked list every time? */ | |||
void obj_sendinlet(t_object *x, int n, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
t_inlet *i; | |||
for (i = x->ob_inlet; i && n; i = i->i_next, n--) | |||
; | |||
if (i) | |||
typedmess(&i->i_pd, s, argc, argv); | |||
else bug("obj_sendinlet"); | |||
} |
@@ -0,0 +1,321 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "m_pd.h" | |||
#include "m_imp.h" | |||
#include "g_canvas.h" /* just for LB_LOAD */ | |||
/* FIXME no out-of-memory testing yet! */ | |||
t_pd *pd_new(t_class *c) | |||
{ | |||
t_pd *x; | |||
if (!c) | |||
bug ("pd_new: apparently called before setup routine"); | |||
x = (t_pd *)t_getbytes(c->c_size); | |||
*x = c; | |||
if (c->c_patchable) | |||
{ | |||
((t_object *)x)->ob_inlet = 0; | |||
((t_object *)x)->ob_outlet = 0; | |||
} | |||
return (x); | |||
} | |||
void pd_free(t_pd *x) | |||
{ | |||
t_class *c = *x; | |||
if (c->c_freemethod) (*(t_gotfn)(c->c_freemethod))(x); | |||
if (c->c_patchable) | |||
{ | |||
while (((t_object *)x)->ob_outlet) | |||
outlet_free(((t_object *)x)->ob_outlet); | |||
while (((t_object *)x)->ob_inlet) | |||
inlet_free(((t_object *)x)->ob_inlet); | |||
if (((t_object *)x)->ob_binbuf) | |||
binbuf_free(((t_object *)x)->ob_binbuf); | |||
} | |||
if (c->c_size) t_freebytes(x, c->c_size); | |||
} | |||
void gobj_save(t_gobj *x, t_binbuf *b) | |||
{ | |||
t_class *c = x->g_pd; | |||
if (c->c_savefn) | |||
(c->c_savefn)(x, b); | |||
} | |||
/* deal with several objects bound to the same symbol. If more than one, we | |||
actually bind a collection object to the symbol, which forwards messages sent | |||
to the symbol. */ | |||
static t_class *bindlist_class; | |||
typedef struct _bindelem | |||
{ | |||
t_pd *e_who; | |||
struct _bindelem *e_next; | |||
} t_bindelem; | |||
typedef struct _bindlist | |||
{ | |||
t_pd b_pd; | |||
t_bindelem *b_list; | |||
} t_bindlist; | |||
static void bindlist_bang(t_bindlist *x) | |||
{ | |||
t_bindelem *e; | |||
for (e = x->b_list; e; e = e->e_next) | |||
pd_bang(e->e_who); | |||
} | |||
static void bindlist_float(t_bindlist *x, t_float f) | |||
{ | |||
t_bindelem *e; | |||
for (e = x->b_list; e; e = e->e_next) | |||
pd_float(e->e_who, f); | |||
} | |||
static void bindlist_symbol(t_bindlist *x, t_symbol *s) | |||
{ | |||
t_bindelem *e; | |||
for (e = x->b_list; e; e = e->e_next) | |||
pd_symbol(e->e_who, s); | |||
} | |||
static void bindlist_pointer(t_bindlist *x, t_gpointer *gp) | |||
{ | |||
t_bindelem *e; | |||
for (e = x->b_list; e; e = e->e_next) | |||
pd_pointer(e->e_who, gp); | |||
} | |||
static void bindlist_list(t_bindlist *x, t_symbol *s, | |||
int argc, t_atom *argv) | |||
{ | |||
t_bindelem *e; | |||
for (e = x->b_list; e; e = e->e_next) | |||
pd_list(e->e_who, s, argc, argv); | |||
} | |||
static void bindlist_anything(t_bindlist *x, t_symbol *s, | |||
int argc, t_atom *argv) | |||
{ | |||
t_bindelem *e; | |||
for (e = x->b_list; e; e = e->e_next) | |||
pd_typedmess(e->e_who, s, argc, argv); | |||
} | |||
void m_pd_setup(void) | |||
{ | |||
bindlist_class = class_new(gensym("bindlist"), 0, 0, | |||
sizeof(t_bindlist), CLASS_PD, 0); | |||
class_addbang(bindlist_class, bindlist_bang); | |||
class_addfloat(bindlist_class, (t_method)bindlist_float); | |||
class_addsymbol(bindlist_class, bindlist_symbol); | |||
class_addpointer(bindlist_class, bindlist_pointer); | |||
class_addlist(bindlist_class, bindlist_list); | |||
class_addanything(bindlist_class, bindlist_anything); | |||
} | |||
void pd_bind(t_pd *x, t_symbol *s) | |||
{ | |||
if (s->s_thing) | |||
{ | |||
if (*s->s_thing == bindlist_class) | |||
{ | |||
t_bindlist *b = (t_bindlist *)s->s_thing; | |||
t_bindelem *e = (t_bindelem *)getbytes(sizeof(t_bindelem)); | |||
e->e_next = b->b_list; | |||
e->e_who = x; | |||
b->b_list = e; | |||
} | |||
else | |||
{ | |||
t_bindlist *b = (t_bindlist *)pd_new(bindlist_class); | |||
t_bindelem *e1 = (t_bindelem *)getbytes(sizeof(t_bindelem)); | |||
t_bindelem *e2 = (t_bindelem *)getbytes(sizeof(t_bindelem)); | |||
b->b_list = e1; | |||
e1->e_who = x; | |||
e1->e_next = e2; | |||
e2->e_who = s->s_thing; | |||
e2->e_next = 0; | |||
s->s_thing = &b->b_pd; | |||
} | |||
} | |||
else s->s_thing = x; | |||
} | |||
void pd_unbind(t_pd *x, t_symbol *s) | |||
{ | |||
if (s->s_thing == x) s->s_thing = 0; | |||
else if (s->s_thing && *s->s_thing == bindlist_class) | |||
{ | |||
/* bindlists always have at least two elements... if the number | |||
goes down to one, get rid of the bindlist and bind the symbol | |||
straight to the remaining element. */ | |||
t_bindlist *b = (t_bindlist *)s->s_thing; | |||
t_bindelem *e, *e2; | |||
if ((e = b->b_list)->e_who == x) | |||
{ | |||
b->b_list = e->e_next; | |||
freebytes(e, sizeof(t_bindelem)); | |||
} | |||
else for (e = b->b_list; (e2 = e->e_next); e = e2) | |||
if (e2->e_who == x) | |||
{ | |||
e->e_next = e2->e_next; | |||
freebytes(e2, sizeof(t_bindelem)); | |||
break; | |||
} | |||
if (!b->b_list->e_next) | |||
{ | |||
s->s_thing = b->b_list->e_who; | |||
freebytes(b->b_list, sizeof(t_bindelem)); | |||
pd_free(&b->b_pd); | |||
} | |||
} | |||
else pd_error(x, "%s: couldn't unbind", s->s_name); | |||
} | |||
t_pd *pd_findbyclass(t_symbol *s, t_class *c) | |||
{ | |||
t_pd *x = 0; | |||
if (!s->s_thing) return (0); | |||
if (*s->s_thing == c) return (s->s_thing); | |||
if (*s->s_thing == bindlist_class) | |||
{ | |||
t_bindlist *b = (t_bindlist *)s->s_thing; | |||
t_bindelem *e, *e2; | |||
int warned = 0; | |||
for (e = b->b_list; e; e = e->e_next) | |||
if (*e->e_who == c) | |||
{ | |||
if (x && !warned) | |||
{ | |||
post("warning: %s: multiply defined", s->s_name); | |||
warned = 1; | |||
} | |||
x = e->e_who; | |||
} | |||
} | |||
return x; | |||
} | |||
/* stack for maintaining bindings for the #X symbol during nestable loads. | |||
*/ | |||
typedef struct _gstack | |||
{ | |||
t_pd *g_what; | |||
t_symbol *g_loadingabstraction; | |||
struct _gstack *g_next; | |||
} t_gstack; | |||
static t_gstack *gstack_head = 0; | |||
static t_pd *lastpopped; | |||
static t_symbol *pd_loadingabstraction; | |||
int pd_setloadingabstraction(t_symbol *sym) | |||
{ | |||
t_gstack *foo = gstack_head; | |||
for (foo = gstack_head; foo; foo = foo->g_next) | |||
if (foo->g_loadingabstraction == sym) | |||
return (1); | |||
pd_loadingabstraction = sym; | |||
return (0); | |||
} | |||
void pd_pushsym(t_pd *x) | |||
{ | |||
t_gstack *y = (t_gstack *)t_getbytes(sizeof(*y)); | |||
y->g_what = s__X.s_thing; | |||
y->g_next = gstack_head; | |||
y->g_loadingabstraction = pd_loadingabstraction; | |||
pd_loadingabstraction = 0; | |||
gstack_head = y; | |||
s__X.s_thing = x; | |||
} | |||
void pd_popsym(t_pd *x) | |||
{ | |||
if (!gstack_head || s__X.s_thing != x) bug("gstack_pop"); | |||
else | |||
{ | |||
t_gstack *headwas = gstack_head; | |||
s__X.s_thing = headwas->g_what; | |||
gstack_head = headwas->g_next; | |||
t_freebytes(headwas, sizeof(*headwas)); | |||
lastpopped = x; | |||
} | |||
} | |||
void pd_doloadbang( void) | |||
{ | |||
if (lastpopped) | |||
pd_vmess(lastpopped, gensym("loadbang"), "f", LB_LOAD); | |||
lastpopped = 0; | |||
} | |||
void pd_bang(t_pd *x) | |||
{ | |||
(*(*x)->c_bangmethod)(x); | |||
} | |||
void pd_float(t_pd *x, t_float f) | |||
{ | |||
(*(*x)->c_floatmethod)(x, f); | |||
} | |||
void pd_pointer(t_pd *x, t_gpointer *gp) | |||
{ | |||
(*(*x)->c_pointermethod)(x, gp); | |||
} | |||
void pd_symbol(t_pd *x, t_symbol *s) | |||
{ | |||
(*(*x)->c_symbolmethod)(x, s); | |||
} | |||
void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
(*(*x)->c_listmethod)(x, &s_list, argc, argv); | |||
} | |||
void mess_init(void); | |||
void obj_init(void); | |||
void conf_init(void); | |||
void glob_init(void); | |||
void garray_init(void); | |||
void pd_init(void) | |||
{ | |||
static int initted = 0; | |||
if (initted) | |||
return; | |||
initted = 1; | |||
#ifdef PDINSTANCE | |||
pd_instances = (t_pdinstance **)getbytes(sizeof(*pd_instances)); | |||
pd_instances[0] = &pd_maininstance; | |||
pd_ninstances = 1; | |||
#endif | |||
mess_init(); | |||
sys_lock(); | |||
obj_init(); | |||
conf_init(); | |||
glob_init(); | |||
garray_init(); | |||
sys_unlock(); | |||
} | |||
EXTERN t_canvas *pd_getcanvaslist(void) | |||
{ | |||
return (pd_this->pd_canvaslist); | |||
} | |||
@@ -0,0 +1,894 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#ifndef __m_pd_h_ | |||
#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) | |||
extern "C" { | |||
#endif | |||
#define PD_MAJOR_VERSION 0 | |||
#define PD_MINOR_VERSION 48 | |||
#define PD_BUGFIX_VERSION 1 | |||
#define PD_TEST_VERSION "" | |||
extern int pd_compatibilitylevel; /* e.g., 43 for pd 0.43 compatibility */ | |||
/* old name for "MSW" flag -- we have to take it for the sake of many old | |||
"nmakefiles" for externs, which will define NT and not MSW */ | |||
#if defined(NT) && !defined(MSW) | |||
#define MSW | |||
#endif | |||
/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans@at.or.at> */ | |||
#ifdef _MSC_VER | |||
/* #pragma warning( disable : 4091 ) */ | |||
#pragma warning( disable : 4305 ) /* uncast const double to float */ | |||
#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */ | |||
#pragma warning( disable : 4101 ) /* unused automatic variables */ | |||
#endif /* _MSC_VER */ | |||
/* the external storage class is "extern" in UNIX; in MSW it's ugly. */ | |||
#ifdef _WIN32 | |||
#ifdef PD_INTERNAL | |||
#define EXTERN __declspec(dllexport) extern | |||
#else | |||
#define EXTERN __declspec(dllimport) extern | |||
#endif /* PD_INTERNAL */ | |||
#else | |||
#define EXTERN extern | |||
#endif /* _WIN32 */ | |||
/* On most c compilers, you can just say "struct foo;" to declare a | |||
structure whose elements are defined elsewhere. On MSVC, when compiling | |||
C (but not C++) code, you have to say "extern struct foo;". So we make | |||
a stupid macro: */ | |||
#if defined(_MSC_VER) && !defined(_LANGUAGE_C_PLUS_PLUS) \ | |||
&& !defined(__cplusplus) | |||
#define EXTERN_STRUCT extern struct | |||
#else | |||
#define EXTERN_STRUCT struct | |||
#endif | |||
/* Define some attributes, specific to the compiler */ | |||
#if defined(__GNUC__) | |||
#define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__ ((format (printf, a, b))) | |||
#else | |||
#define ATTRIBUTE_FORMAT_PRINTF(a, b) | |||
#endif | |||
#if !defined(_SIZE_T) && !defined(_SIZE_T_) | |||
#include <stddef.h> /* just for size_t -- how lame! */ | |||
#endif | |||
/* Microsoft Visual Studio is not C99, it does not provide stdint.h */ | |||
#ifdef _MSC_VER | |||
typedef signed __int8 int8_t; | |||
typedef signed __int16 int16_t; | |||
typedef signed __int32 int32_t; | |||
typedef signed __int64 int64_t; | |||
typedef unsigned __int8 uint8_t; | |||
typedef unsigned __int16 uint16_t; | |||
typedef unsigned __int32 uint32_t; | |||
typedef unsigned __int64 uint64_t; | |||
#else | |||
# include <stdint.h> | |||
#endif | |||
/* for FILE, needed by sys_fopen() and sys_fclose() only */ | |||
#include <stdio.h> | |||
#define MAXPDSTRING 1000 /* use this for anything you want */ | |||
#define MAXPDARG 5 /* max number of args we can typecheck today */ | |||
/* signed and unsigned integer types the size of a pointer: */ | |||
#if !defined(PD_LONGINTTYPE) | |||
#if defined(_WIN32) && defined(__x86_64__) | |||
#define PD_LONGINTTYPE long long | |||
#else | |||
#define PD_LONGINTTYPE long | |||
#endif | |||
#endif | |||
#if !defined(PD_FLOATSIZE) | |||
/* normally, our floats (t_float, t_sample,...) are 32bit */ | |||
# define PD_FLOATSIZE 32 | |||
#endif | |||
#if PD_FLOATSIZE == 32 | |||
# define PD_FLOATTYPE float | |||
/* an unsigned int of the same size as FLOATTYPE: */ | |||
# define PD_FLOATUINTTYPE unsigned int | |||
#elif PD_FLOATSIZE == 64 | |||
# define PD_FLOATTYPE double | |||
# define PD_FLOATUINTTYPE unsigned long | |||
#else | |||
# error invalid FLOATSIZE: must be 32 or 64 | |||
#endif | |||
typedef PD_LONGINTTYPE t_int; /* pointer-size integer */ | |||
typedef PD_FLOATTYPE t_float; /* a float type at most the same size */ | |||
typedef PD_FLOATTYPE t_floatarg; /* float type for function calls */ | |||
typedef struct _symbol | |||
{ | |||
char *s_name; | |||
struct _class **s_thing; | |||
struct _symbol *s_next; | |||
} t_symbol; | |||
EXTERN_STRUCT _array; | |||
#define t_array struct _array /* g_canvas.h */ | |||
/* pointers to glist and array elements go through a "stub" which sticks | |||
around after the glist or array is freed. The stub itself is deleted when | |||
both the glist/array is gone and the refcount is zero, ensuring that no | |||
gpointers are pointing here. */ | |||
#define GP_NONE 0 /* the stub points nowhere (has been cut off) */ | |||
#define GP_GLIST 1 /* the stub points to a glist element */ | |||
#define GP_ARRAY 2 /* ... or array */ | |||
typedef struct _gstub | |||
{ | |||
union | |||
{ | |||
struct _glist *gs_glist; /* glist we're in */ | |||
struct _array *gs_array; /* array we're in */ | |||
} gs_un; | |||
int gs_which; /* GP_GLIST/GP_ARRAY */ | |||
int gs_refcount; /* number of gpointers pointing here */ | |||
} t_gstub; | |||
typedef struct _gpointer /* pointer to a gobj in a glist */ | |||
{ | |||
union | |||
{ | |||
struct _scalar *gp_scalar; /* scalar we're in (if glist) */ | |||
union word *gp_w; /* raw data (if array) */ | |||
} gp_un; | |||
int gp_valid; /* number which must match gpointee */ | |||
t_gstub *gp_stub; /* stub which points to glist/array */ | |||
} t_gpointer; | |||
typedef union word | |||
{ | |||
t_float w_float; | |||
t_symbol *w_symbol; | |||
t_gpointer *w_gpointer; | |||
t_array *w_array; | |||
struct _binbuf *w_binbuf; | |||
int w_index; | |||
} t_word; | |||
typedef enum | |||
{ | |||
A_NULL, | |||
A_FLOAT, | |||
A_SYMBOL, | |||
A_POINTER, | |||
A_SEMI, | |||
A_COMMA, | |||
A_DEFFLOAT, | |||
A_DEFSYM, | |||
A_DOLLAR, | |||
A_DOLLSYM, | |||
A_GIMME, | |||
A_CANT | |||
} t_atomtype; | |||
#define A_DEFSYMBOL A_DEFSYM /* better name for this */ | |||
typedef struct _atom | |||
{ | |||
t_atomtype a_type; | |||
union word a_w; | |||
} t_atom; | |||
EXTERN_STRUCT _class; | |||
#define t_class struct _class | |||
EXTERN_STRUCT _outlet; | |||
#define t_outlet struct _outlet | |||
EXTERN_STRUCT _inlet; | |||
#define t_inlet struct _inlet | |||
EXTERN_STRUCT _binbuf; | |||
#define t_binbuf struct _binbuf | |||
EXTERN_STRUCT _clock; | |||
#define t_clock struct _clock | |||
EXTERN_STRUCT _outconnect; | |||
#define t_outconnect struct _outconnect | |||
EXTERN_STRUCT _glist; | |||
#define t_glist struct _glist | |||
#define t_canvas struct _glist /* LATER lose this */ | |||
typedef t_class *t_pd; /* pure datum: nothing but a class pointer */ | |||
typedef struct _gobj /* a graphical object */ | |||
{ | |||
t_pd g_pd; /* pure datum header (class) */ | |||
struct _gobj *g_next; /* next in list */ | |||
} t_gobj; | |||
typedef struct _scalar /* a graphical object holding data */ | |||
{ | |||
t_gobj sc_gobj; /* header for graphical object */ | |||
t_symbol *sc_template; /* template name (LATER replace with pointer) */ | |||
t_word sc_vec[1]; /* indeterminate-length array of words */ | |||
} t_scalar; | |||
typedef struct _text /* patchable object - graphical, with text */ | |||
{ | |||
t_gobj te_g; /* header for graphical object */ | |||
t_binbuf *te_binbuf; /* holder for the text */ | |||
t_outlet *te_outlet; /* linked list of outlets */ | |||
t_inlet *te_inlet; /* linked list of inlets */ | |||
short te_xpix; /* x&y location (within the toplevel) */ | |||
short te_ypix; | |||
short te_width; /* requested width in chars, 0 if auto */ | |||
unsigned int te_type:2; /* from defs below */ | |||
} t_text; | |||
#define T_TEXT 0 /* just a textual comment */ | |||
#define T_OBJECT 1 /* a MAX style patchable object */ | |||
#define T_MESSAGE 2 /* a MAX type message */ | |||
#define T_ATOM 3 /* a cell to display a number or symbol */ | |||
#define te_pd te_g.g_pd | |||
/* t_object is synonym for t_text (LATER unify them) */ | |||
typedef struct _text t_object; | |||
#define ob_outlet te_outlet | |||
#define ob_inlet te_inlet | |||
#define ob_binbuf te_binbuf | |||
#define ob_pd te_g.g_pd | |||
#define ob_g te_g | |||
typedef void (*t_method)(void); | |||
typedef void *(*t_newmethod)( void); | |||
/* in ARM 64 a varargs prototype generates a different function call sequence | |||
from a fixed one, so in that special case we make a more restrictive | |||
definition for t_gotfn. This will break some code in the "chaos" package | |||
in Pd extended. (that code will run incorrectly anyhow so why not catch it | |||
at compile time anyhow.) */ | |||
#if defined(__APPLE__) && defined(__aarch64__) | |||
typedef void (*t_gotfn)(void *x); | |||
#else | |||
typedef void (*t_gotfn)(void *x, ...); | |||
#endif | |||
/* ---------------- pre-defined objects and symbols --------------*/ | |||
EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */ | |||
EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */ | |||
/* --------- prototypes from the central message system ----------- */ | |||
EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv); | |||
EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv); | |||
EXTERN t_symbol *gensym(const char *s); | |||
EXTERN t_gotfn getfn(t_pd *x, t_symbol *s); | |||
EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s); | |||
EXTERN void nullfn(void); | |||
EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...); | |||
/* the following macros are for sending non-type-checkable messages, i.e., | |||
using function lookup but circumventing type checking on arguments. Only | |||
use for internal messaging protected by A_CANT so that the message can't | |||
be generated at patch level. */ | |||
#define mess0(x, s) ((*getfn((x), (s)))((x))) | |||
typedef void (*t_gotfn1)(void *x, void *arg1); | |||
#define mess1(x, s, a) ((*(t_gotfn1)getfn((x), (s)))((x), (a))) | |||
typedef void (*t_gotfn2)(void *x, void *arg1, void *arg2); | |||
#define mess2(x, s, a,b) ((*(t_gotfn2)getfn((x), (s)))((x), (a),(b))) | |||
typedef void (*t_gotfn3)(void *x, void *arg1, void *arg2, void *arg3); | |||
#define mess3(x, s, a,b,c) ((*(t_gotfn3)getfn((x), (s)))((x), (a),(b),(c))) | |||
typedef void (*t_gotfn4)(void *x, | |||
void *arg1, void *arg2, void *arg3, void *arg4); | |||
#define mess4(x, s, a,b,c,d) \ | |||
((*(t_gotfn4)getfn((x), (s)))((x), (a),(b),(c),(d))) | |||
typedef void (*t_gotfn5)(void *x, | |||
void *arg1, void *arg2, void *arg3, void *arg4, void *arg5); | |||
#define mess5(x, s, a,b,c,d,e) \ | |||
((*(t_gotfn5)getfn((x), (s)))((x), (a),(b),(c),(d),(e))) | |||
EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv); | |||
EXTERN t_pd *pd_newest(void); | |||
/* --------------- memory management -------------------- */ | |||
EXTERN void *getbytes(size_t nbytes); | |||
EXTERN void *getzbytes(size_t nbytes); | |||
EXTERN void *copybytes(void *src, size_t nbytes); | |||
EXTERN void freebytes(void *x, size_t nbytes); | |||
EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize); | |||
/* -------------------- atoms ----------------------------- */ | |||
#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0) | |||
#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0) | |||
#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \ | |||
(atom)->a_w.w_gpointer = (gp)) | |||
#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f)) | |||
#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \ | |||
(atom)->a_w.w_symbol = (s)) | |||
#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \ | |||
(atom)->a_w.w_index = (n)) | |||
#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \ | |||
(atom)->a_w.w_symbol= (s)) | |||
EXTERN t_float atom_getfloat(t_atom *a); | |||
EXTERN t_int atom_getint(t_atom *a); | |||
EXTERN t_symbol *atom_getsymbol(t_atom *a); | |||
EXTERN t_symbol *atom_gensym(t_atom *a); | |||
EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv); | |||
EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv); | |||
EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv); | |||
EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize); | |||
/* ------------------ binbufs --------------- */ | |||
EXTERN t_binbuf *binbuf_new(void); | |||
EXTERN void binbuf_free(t_binbuf *x); | |||
EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y); | |||
EXTERN void binbuf_text(t_binbuf *x, const char *text, size_t size); | |||
EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp); | |||
EXTERN void binbuf_clear(t_binbuf *x); | |||
EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv); | |||
EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...); | |||
EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y); | |||
EXTERN void binbuf_addsemi(t_binbuf *x); | |||
EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv); | |||
EXTERN void binbuf_print(t_binbuf *x); | |||
EXTERN int binbuf_getnatom(t_binbuf *x); | |||
EXTERN t_atom *binbuf_getvec(t_binbuf *x); | |||
EXTERN int binbuf_resize(t_binbuf *x, int newsize); | |||
EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv); | |||
EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname, | |||
int crflag); | |||
EXTERN int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas, | |||
int crflag); | |||
EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname, | |||
int crflag); | |||
EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir, | |||
int crflag); | |||
EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir); | |||
EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, | |||
int tonew); | |||
/* ------------------ clocks --------------- */ | |||
EXTERN t_clock *clock_new(void *owner, t_method fn); | |||
EXTERN void clock_set(t_clock *x, double systime); | |||
EXTERN void clock_delay(t_clock *x, double delaytime); | |||
EXTERN void clock_unset(t_clock *x); | |||
EXTERN void clock_setunit(t_clock *x, double timeunit, int sampflag); | |||
EXTERN double clock_getlogicaltime(void); | |||
EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */ | |||
EXTERN double clock_gettimesince(double prevsystime); | |||
EXTERN double clock_gettimesincewithunits(double prevsystime, | |||
double units, int sampflag); | |||
EXTERN double clock_getsystimeafter(double delaytime); | |||
EXTERN void clock_free(t_clock *x); | |||
/* ----------------- pure data ---------------- */ | |||
EXTERN t_pd *pd_new(t_class *cls); | |||
EXTERN void pd_free(t_pd *x); | |||
EXTERN void pd_bind(t_pd *x, t_symbol *s); | |||
EXTERN void pd_unbind(t_pd *x, t_symbol *s); | |||
EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c); | |||
EXTERN void pd_pushsym(t_pd *x); | |||
EXTERN void pd_popsym(t_pd *x); | |||
EXTERN t_symbol *pd_getfilename(void); | |||
EXTERN t_symbol *pd_getdirname(void); | |||
EXTERN void pd_bang(t_pd *x); | |||
EXTERN void pd_pointer(t_pd *x, t_gpointer *gp); | |||
EXTERN void pd_float(t_pd *x, t_float f); | |||
EXTERN void pd_symbol(t_pd *x, t_symbol *s); | |||
EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv); | |||
EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv); | |||
#define pd_class(x) (*(x)) | |||
/* ----------------- pointers ---------------- */ | |||
EXTERN void gpointer_init(t_gpointer *gp); | |||
EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto); | |||
EXTERN void gpointer_unset(t_gpointer *gp); | |||
EXTERN int gpointer_check(const t_gpointer *gp, int headok); | |||
/* ----------------- patchable "objects" -------------- */ | |||
EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, | |||
t_symbol *s2); | |||
EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp); | |||
EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp); | |||
EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp); | |||
EXTERN t_inlet *signalinlet_new(t_object *owner, t_float f); | |||
EXTERN void inlet_free(t_inlet *x); | |||
EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s); | |||
EXTERN void outlet_bang(t_outlet *x); | |||
EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp); | |||
EXTERN void outlet_float(t_outlet *x, t_float f); | |||
EXTERN void outlet_symbol(t_outlet *x, t_symbol *s); | |||
EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv); | |||
EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv); | |||
EXTERN t_symbol *outlet_getsymbol(t_outlet *x); | |||
EXTERN void outlet_free(t_outlet *x); | |||
EXTERN t_object *pd_checkobject(t_pd *x); | |||
/* -------------------- canvases -------------- */ | |||
EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir); | |||
EXTERN void canvas_setargs(int argc, t_atom *argv); | |||
EXTERN void canvas_getargs(int *argcp, t_atom **argvp); | |||
EXTERN t_symbol *canvas_getcurrentdir(void); | |||
EXTERN t_glist *canvas_getcurrent(void); | |||
EXTERN void canvas_makefilename(t_glist *c, char *file, | |||
char *result,int resultsize); | |||
EXTERN t_symbol *canvas_getdir(t_glist *x); | |||
EXTERN char sys_font[]; /* default typeface set in s_main.c */ | |||
EXTERN char sys_fontweight[]; /* default font weight set in s_main.c */ | |||
EXTERN int sys_hostfontsize(int fontsize, int zoom); | |||
EXTERN int sys_zoomfontwidth(int fontsize, int zoom, int worstcase); | |||
EXTERN int sys_zoomfontheight(int fontsize, int zoom, int worstcase); | |||
EXTERN int sys_fontwidth(int fontsize); | |||
EXTERN int sys_fontheight(int fontsize); | |||
EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b); | |||
EXTERN int canvas_open(t_canvas *x, const char *name, const char *ext, | |||
char *dirresult, char **nameresult, unsigned int size, int bin); | |||
/* ---------------- widget behaviors ---------------------- */ | |||
EXTERN_STRUCT _widgetbehavior; | |||
#define t_widgetbehavior struct _widgetbehavior | |||
EXTERN_STRUCT _parentwidgetbehavior; | |||
#define t_parentwidgetbehavior struct _parentwidgetbehavior | |||
EXTERN const t_parentwidgetbehavior *pd_getparentwidget(t_pd *x); | |||
/* -------------------- classes -------------- */ | |||
#define CLASS_DEFAULT 0 /* flags for new classes below */ | |||
#define CLASS_PD 1 | |||
#define CLASS_GOBJ 2 | |||
#define CLASS_PATCHABLE 3 | |||
#define CLASS_NOINLET 8 | |||
#define CLASS_TYPEMASK 3 | |||
EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod, | |||
t_method freemethod, size_t size, int flags, t_atomtype arg1, ...); | |||
EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s, | |||
t_atomtype type1, ...); | |||
EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel, | |||
t_atomtype arg1, ...); | |||
EXTERN void class_addbang(t_class *c, t_method fn); | |||
EXTERN void class_addpointer(t_class *c, t_method fn); | |||
EXTERN void class_doaddfloat(t_class *c, t_method fn); | |||
EXTERN void class_addsymbol(t_class *c, t_method fn); | |||
EXTERN void class_addlist(t_class *c, t_method fn); | |||
EXTERN void class_addanything(t_class *c, t_method fn); | |||
EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s); | |||
EXTERN void class_setwidget(t_class *c, const t_widgetbehavior *w); | |||
EXTERN void class_setparentwidget(t_class *c, const t_parentwidgetbehavior *w); | |||
EXTERN const t_parentwidgetbehavior *class_parentwidget(t_class *c); | |||
EXTERN char *class_getname(t_class *c); | |||
EXTERN char *class_gethelpname(t_class *c); | |||
EXTERN char *class_gethelpdir(t_class *c); | |||
EXTERN void class_setdrawcommand(t_class *c); | |||
EXTERN int class_isdrawcommand(t_class *c); | |||
EXTERN void class_domainsignalin(t_class *c, int onset); | |||
EXTERN void class_set_extern_dir(t_symbol *s); | |||
#define CLASS_MAINSIGNALIN(c, type, field) \ | |||
class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0) | |||
/* prototype for functions to save Pd's to a binbuf */ | |||
typedef void (*t_savefn)(t_gobj *x, t_binbuf *b); | |||
EXTERN void class_setsavefn(t_class *c, t_savefn f); | |||
EXTERN t_savefn class_getsavefn(t_class *c); | |||
EXTERN void obj_saveformat(t_object *x, t_binbuf *bb); /* add format to bb */ | |||
/* prototype for functions to open properties dialogs */ | |||
typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist); | |||
EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f); | |||
EXTERN t_propertiesfn class_getpropertiesfn(t_class *c); | |||
#ifndef PD_CLASS_DEF | |||
#define class_addbang(x, y) class_addbang((x), (t_method)(y)) | |||
#define class_addpointer(x, y) class_addpointer((x), (t_method)(y)) | |||
#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y)) | |||
#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y)) | |||
#define class_addlist(x, y) class_addlist((x), (t_method)(y)) | |||
#define class_addanything(x, y) class_addanything((x), (t_method)(y)) | |||
#endif | |||
/* ------------ printing --------------------------------- */ | |||
EXTERN void post(const char *fmt, ...); | |||
EXTERN void startpost(const char *fmt, ...); | |||
EXTERN void poststring(const char *s); | |||
EXTERN void postfloat(t_floatarg f); | |||
EXTERN void postatom(int argc, t_atom *argv); | |||
EXTERN void endpost(void); | |||
EXTERN void error(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); | |||
EXTERN void verbose(int level, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); | |||
EXTERN void bug(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); | |||
EXTERN void pd_error(void *object, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); | |||
EXTERN void logpost(const void *object, const int level, const char *fmt, ...) | |||
ATTRIBUTE_FORMAT_PRINTF(3, 4); | |||
EXTERN void sys_logerror(const char *object, const char *s); | |||
EXTERN void sys_unixerror(const char *object); | |||
EXTERN void sys_ouch(void); | |||
/* ------------ system interface routines ------------------- */ | |||
EXTERN int sys_isreadablefile(const char *name); | |||
EXTERN int sys_isabsolutepath(const char *dir); | |||
EXTERN void sys_bashfilename(const char *from, char *to); | |||
EXTERN void sys_unbashfilename(const char *from, char *to); | |||
EXTERN int open_via_path(const char *dir, const char *name, const char *ext, | |||
char *dirresult, char **nameresult, unsigned int size, int bin); | |||
EXTERN int sched_geteventno(void); | |||
EXTERN double sys_getrealtime(void); | |||
EXTERN int (*sys_idlehook)(void); /* hook to add idle time computation */ | |||
/* Win32's open()/fopen() do not handle UTF-8 filenames so we need | |||
* these internal versions that handle UTF-8 filenames the same across | |||
* all platforms. They are recommended for use in external | |||
* objectclasses as well so they work with Unicode filenames on Windows */ | |||
EXTERN int sys_open(const char *path, int oflag, ...); | |||
EXTERN int sys_close(int fd); | |||
EXTERN FILE *sys_fopen(const char *filename, const char *mode); | |||
EXTERN int sys_fclose(FILE *stream); | |||
/* ------------ threading ------------------- */ | |||
EXTERN void sys_lock(void); | |||
EXTERN void sys_unlock(void); | |||
EXTERN int sys_trylock(void); | |||
/* --------------- signals ----------------------------------- */ | |||
typedef PD_FLOATTYPE t_sample; | |||
typedef union _sampleint_union { | |||
t_sample f; | |||
PD_FLOATUINTTYPE i; | |||
} t_sampleint_union; | |||
#define MAXLOGSIG 32 | |||
#define MAXSIGSIZE (1 << MAXLOGSIG) | |||
typedef struct _signal | |||
{ | |||
int s_n; /* number of points in the array */ | |||
t_sample *s_vec; /* the array */ | |||
t_float s_sr; /* sample rate */ | |||
int s_refcount; /* number of times used */ | |||
int s_isborrowed; /* whether we're going to borrow our array */ | |||
struct _signal *s_borrowedfrom; /* signal to borrow it from */ | |||
struct _signal *s_nextfree; /* next in freelist */ | |||
struct _signal *s_nextused; /* next in used list */ | |||
int s_vecsize; /* allocated size of array in points */ | |||
} t_signal; | |||
typedef t_int *(*t_perfroutine)(t_int *args); | |||
EXTERN t_int *plus_perform(t_int *args); | |||
EXTERN t_int *zero_perform(t_int *args); | |||
EXTERN t_int *copy_perform(t_int *args); | |||
EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n); | |||
EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n); | |||
EXTERN void dsp_add_scalarcopy(t_float *in, t_sample *out, int n); | |||
EXTERN void dsp_add_zero(t_sample *out, int n); | |||
EXTERN int sys_getblksize(void); | |||
EXTERN t_float sys_getsr(void); | |||
EXTERN int sys_get_inchannels(void); | |||
EXTERN int sys_get_outchannels(void); | |||
EXTERN void dsp_add(t_perfroutine f, int n, ...); | |||
EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec); | |||
EXTERN void pd_fft(t_float *buf, int npoints, int inverse); | |||
EXTERN int ilog2(int n); | |||
EXTERN void mayer_fht(t_sample *fz, int n); | |||
EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag); | |||
EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag); | |||
EXTERN void mayer_realfft(int n, t_sample *real); | |||
EXTERN void mayer_realifft(int n, t_sample *real); | |||
EXTERN float *cos_table; | |||
#define LOGCOSTABSIZE 9 | |||
#define COSTABSIZE (1<<LOGCOSTABSIZE) | |||
EXTERN int canvas_suspend_dsp(void); | |||
EXTERN void canvas_resume_dsp(int oldstate); | |||
EXTERN void canvas_update_dsp(void); | |||
EXTERN int canvas_dspstate; | |||
/* up/downsampling */ | |||
typedef struct _resample | |||
{ | |||
int method; /* up/downsampling method ID */ | |||
int downsample; /* downsampling factor */ | |||
int upsample; /* upsampling factor */ | |||
t_sample *s_vec; /* here we hold the resampled data */ | |||
int s_n; | |||
t_sample *coeffs; /* coefficients for filtering... */ | |||
int coefsize; | |||
t_sample *buffer; /* buffer for filtering */ | |||
int bufsize; | |||
} t_resample; | |||
EXTERN void resample_init(t_resample *x); | |||
EXTERN void resample_free(t_resample *x); | |||
EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method); | |||
EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method); | |||
EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method); | |||
/* ----------------------- utility functions for signals -------------- */ | |||
EXTERN t_float mtof(t_float); | |||
EXTERN t_float ftom(t_float); | |||
EXTERN t_float rmstodb(t_float); | |||
EXTERN t_float powtodb(t_float); | |||
EXTERN t_float dbtorms(t_float); | |||
EXTERN t_float dbtopow(t_float); | |||
EXTERN t_float q8_sqrt(t_float); | |||
EXTERN t_float q8_rsqrt(t_float); | |||
#ifndef N32 | |||
EXTERN t_float qsqrt(t_float); /* old names kept for extern compatibility */ | |||
EXTERN t_float qrsqrt(t_float); | |||
#endif | |||
/* --------------------- data --------------------------------- */ | |||
/* graphical arrays */ | |||
EXTERN_STRUCT _garray; | |||
#define t_garray struct _garray | |||
EXTERN t_class *garray_class; | |||
EXTERN int garray_getfloatarray(t_garray *x, int *size, t_float **vec); | |||
EXTERN int garray_getfloatwords(t_garray *x, int *size, t_word **vec); | |||
EXTERN void garray_redraw(t_garray *x); | |||
EXTERN int garray_npoints(t_garray *x); | |||
EXTERN char *garray_vec(t_garray *x); | |||
EXTERN void garray_resize(t_garray *x, t_floatarg f); /* avoid; use this: */ | |||
EXTERN void garray_resize_long(t_garray *x, long n); /* better version */ | |||
EXTERN void garray_usedindsp(t_garray *x); | |||
EXTERN void garray_setsaveit(t_garray *x, int saveit); | |||
EXTERN t_glist *garray_getglist(t_garray *x); | |||
EXTERN t_array *garray_getarray(t_garray *x); | |||
EXTERN t_class *scalar_class; | |||
EXTERN t_float *value_get(t_symbol *s); | |||
EXTERN void value_release(t_symbol *s); | |||
EXTERN int value_getfloat(t_symbol *s, t_float *f); | |||
EXTERN int value_setfloat(t_symbol *s, t_float f); | |||
/* ------- GUI interface - functions to send strings to TK --------- */ | |||
typedef void (*t_guicallbackfn)(t_gobj *client, t_glist *glist); | |||
EXTERN void sys_vgui(char *fmt, ...); | |||
EXTERN void sys_gui(char *s); | |||
EXTERN void sys_pretendguibytes(int n); | |||
EXTERN void sys_queuegui(void *client, t_glist *glist, t_guicallbackfn f); | |||
EXTERN void sys_unqueuegui(void *client); | |||
/* dialog window creation and destruction */ | |||
EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd); | |||
EXTERN void gfxstub_deleteforkey(void *key); | |||
extern t_class *glob_pdobject; /* object to send "pd" messages */ | |||
/*------------- Max 0.26 compatibility --------------------*/ | |||
/* the following reflects the new way classes are laid out, with the class | |||
pointing to the messlist and not vice versa. Externs shouldn't feel it. */ | |||
typedef t_class *t_externclass; | |||
EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine, | |||
t_method freeroutine, t_symbol *name, size_t size, int tiny, \ | |||
t_atomtype arg1, ...); | |||
EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...); | |||
#define t_getbytes getbytes | |||
#define t_freebytes freebytes | |||
#define t_resizebytes resizebytes | |||
#define typedmess pd_typedmess | |||
#define vmess pd_vmess | |||
/* A definition to help gui objects straddle 0.34-0.35 changes. If this is | |||
defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */ | |||
#define PD_USE_TE_XPIX | |||
#ifndef _MSC_VER /* Microoft compiler can't handle "inline" function/macros */ | |||
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) | |||
/* a test for NANs and denormals. Should only be necessary on i386. */ | |||
#if PD_FLOATSIZE == 32 | |||
typedef union | |||
{ | |||
t_float f; | |||
unsigned int ui; | |||
}t_bigorsmall32; | |||
static inline int PD_BADFLOAT(t_float f) /* malformed float */ | |||
{ | |||
t_bigorsmall32 pun; | |||
pun.f = f; | |||
pun.ui &= 0x7f800000; | |||
return((pun.ui == 0) | (pun.ui == 0x7f800000)); | |||
} | |||
static inline int PD_BIGORSMALL(t_float f) /* exponent outside (-64,64) */ | |||
{ | |||
t_bigorsmall32 pun; | |||
pun.f = f; | |||
return((pun.ui & 0x20000000) == ((pun.ui >> 1) & 0x20000000)); | |||
} | |||
#elif PD_FLOATSIZE == 64 | |||
typedef union | |||
{ | |||
t_float f; | |||
unsigned int ui[2]; | |||
}t_bigorsmall64; | |||
static inline int PD_BADFLOAT(t_float f) /* malformed double */ | |||
{ | |||
t_bigorsmall64 pun; | |||
pun.f = f; | |||
pun.ui[1] &= 0x7ff00000; | |||
return((pun.ui[1] == 0) | (pun.ui[1] == 0x7ff00000)); | |||
} | |||
static inline int PD_BIGORSMALL(t_float f) /* exponent outside (-512,512) */ | |||
{ | |||
t_bigorsmall64 pun; | |||
pun.f = f; | |||
return((pun.ui[1] & 0x20000000) == ((pun.ui[1] >> 1) & 0x20000000)); | |||
} | |||
#endif /* PD_FLOATSIZE */ | |||
#else /* not INTEL or ARM */ | |||
#define PD_BADFLOAT(f) 0 | |||
#define PD_BIGORSMALL(f) 0 | |||
#endif | |||
#else /* _MSC_VER */ | |||
#if PD_FLOATSIZE == 32 | |||
#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \ | |||
(((*(unsigned int*)&(f))&0x7f800000)==0x7f800000)) | |||
/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */ | |||
#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \ | |||
(((*(unsigned int*)&(f))&0x60000000)==0x60000000)) | |||
#else /* 64 bits... don't know what to do here */ | |||
#define PD_BADFLOAT(f) (!(((f) >= 0) || ((f) <= 0))) | |||
#define PD_BIGORSMALL(f) ((f) > 1e150 || (f) < -1e150 \ | |||
|| (f) > -1e-150 && (f) < 1e-150 ) | |||
#endif | |||
#endif /* _MSC_VER */ | |||
/* get version number at run time */ | |||
EXTERN void sys_getversion(int *major, int *minor, int *bugfix); | |||
EXTERN_STRUCT _instancemidi; | |||
#define t_instancemidi struct _instancemidi | |||
EXTERN_STRUCT _instanceinter; | |||
#define t_instanceinter struct _instanceinter | |||
EXTERN_STRUCT _instancecanvas; | |||
#define t_instancecanvas struct _instancecanvas | |||
EXTERN_STRUCT _instanceugen; | |||
#define t_instanceugen struct _instanceugen | |||
EXTERN_STRUCT _instancestuff; | |||
#define t_instancestuff struct _instancestuff | |||
#ifndef PDTHREADS | |||
#define PDTHREADS 1 | |||
#endif | |||
struct _pdinstance | |||
{ | |||
double pd_systime; /* global time in Pd ticks */ | |||
t_clock *pd_clock_setlist; /* list of set clocks */ | |||
t_canvas *pd_canvaslist; /* list of all root canvases */ | |||
int pd_instanceno; /* ordinal number of this instance */ | |||
t_symbol **pd_symhash; /* symbol table hash table */ | |||
t_instancemidi *pd_midi; /* private stuff for x_midi.c */ | |||
t_instanceinter *pd_inter; /* private stuff for s_inter.c */ | |||
t_instanceugen *pd_ugen; /* private stuff for d_ugen.c */ | |||
t_instancecanvas *pd_gui; /* semi-private stuff in g_canvas.h */ | |||
t_instancestuff *pd_stuff; /* semi-private stuff in s_stuff.h */ | |||
t_pd *pd_newest; /* most recently created object */ | |||
#ifdef PDINSTANCE | |||
t_symbol pd_s_pointer; | |||
t_symbol pd_s_float; | |||
t_symbol pd_s_symbol; | |||
t_symbol pd_s_bang; | |||
t_symbol pd_s_list; | |||
t_symbol pd_s_anything; | |||
t_symbol pd_s_signal; | |||
t_symbol pd_s__N; | |||
t_symbol pd_s__X; | |||
t_symbol pd_s_x; | |||
t_symbol pd_s_y; | |||
t_symbol pd_s_; | |||
#endif | |||
#if PDTHREADS | |||
int pd_islocked; | |||
#endif | |||
}; | |||
#define t_pdinstance struct _pdinstance | |||
EXTERN t_pdinstance pd_maininstance; | |||
/* m_pd.c */ | |||
#ifdef PDINSTANCE | |||
EXTERN t_pdinstance *pdinstance_new( void); | |||
EXTERN void pd_setinstance(t_pdinstance *x); | |||
EXTERN void pdinstance_free(t_pdinstance *x); | |||
#endif /* PDINSTANCE */ | |||
#if defined(PDTHREADS) && defined(PDINSTANCE) | |||
#ifdef _MSC_VER | |||
#define PERTHREAD __declspec(thread) | |||
#else | |||
#define PERTHREAD __thread | |||
#endif /* _MSC_VER */ | |||
#else | |||
#define PERTHREAD | |||
#endif | |||
#ifdef PDINSTANCE | |||
extern PERTHREAD t_pdinstance *pd_this; | |||
EXTERN t_pdinstance **pd_instances; | |||
EXTERN int pd_ninstances; | |||
#else | |||
#define pd_this (&pd_maininstance) | |||
#endif /* PDINSTANCE */ | |||
#ifdef PDINSTANCE | |||
#define s_pointer (pd_this->pd_s_pointer) | |||
#define s_float (pd_this->pd_s_float) | |||
#define s_symbol (pd_this->pd_s_symbol) | |||
#define s_bang (pd_this->pd_s_bang) | |||
#define s_list (pd_this->pd_s_list) | |||
#define s_anything (pd_this->pd_s_anything) | |||
#define s_signal (pd_this->pd_s_signal) | |||
#define s__N (pd_this->pd_s__N) | |||
#define s__X (pd_this->pd_s__X) | |||
#define s_x (pd_this->pd_s_x) | |||
#define s_y (pd_this->pd_s_y) | |||
#define s_ (pd_this->pd_s_) | |||
#else | |||
EXTERN t_symbol s_pointer, s_float, s_symbol, s_bang, s_list, s_anything, | |||
s_signal, s__N, s__X, s_x, s_y, s_; | |||
#endif | |||
EXTERN t_canvas *pd_getcanvaslist(void); | |||
EXTERN int pd_getdspstate(void); | |||
#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) | |||
} | |||
#endif | |||
#define __m_pd_h_ | |||
#endif /* __m_pd_h_ */ |
@@ -0,0 +1,620 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* scheduling stuff */ | |||
#include "m_pd.h" | |||
#include "m_imp.h" | |||
#include "s_stuff.h" | |||
#ifdef _WIN32 | |||
#include <windows.h> | |||
#endif | |||
/* LATER consider making this variable. It's now the LCM of all sample | |||
rates we expect to see: 32000, 44100, 48000, 88200, 96000. */ | |||
#define TIMEUNITPERMSEC (32. * 441.) | |||
#define TIMEUNITPERSECOND (TIMEUNITPERMSEC * 1000.) | |||
#define SYS_QUIT_QUIT 1 | |||
#define SYS_QUIT_RESTART 2 | |||
static int sys_quit; | |||
int sys_usecsincelastsleep(void); | |||
int sys_sleepgrain; | |||
typedef void (*t_clockmethod)(void *client); | |||
struct _clock | |||
{ | |||
double c_settime; /* in TIMEUNITS; <0 if unset */ | |||
void *c_owner; | |||
t_clockmethod c_fn; | |||
struct _clock *c_next; | |||
t_float c_unit; /* >0 if in TIMEUNITS; <0 if in samples */ | |||
}; | |||
#ifdef HAVE_UNISTD_H | |||
#include <unistd.h> | |||
#endif | |||
t_clock *clock_new(void *owner, t_method fn) | |||
{ | |||
t_clock *x = (t_clock *)getbytes(sizeof *x); | |||
x->c_settime = -1; | |||
x->c_owner = owner; | |||
x->c_fn = (t_clockmethod)fn; | |||
x->c_next = 0; | |||
x->c_unit = TIMEUNITPERMSEC; | |||
return (x); | |||
} | |||
void clock_unset(t_clock *x) | |||
{ | |||
if (x->c_settime >= 0) | |||
{ | |||
if (x == pd_this->pd_clock_setlist) | |||
pd_this->pd_clock_setlist = x->c_next; | |||
else | |||
{ | |||
t_clock *x2 = pd_this->pd_clock_setlist; | |||
while (x2->c_next != x) x2 = x2->c_next; | |||
x2->c_next = x->c_next; | |||
} | |||
x->c_settime = -1; | |||
} | |||
} | |||
/* set the clock to call back at an absolute system time */ | |||
void clock_set(t_clock *x, double setticks) | |||
{ | |||
if (setticks < pd_this->pd_systime) setticks = pd_this->pd_systime; | |||
clock_unset(x); | |||
x->c_settime = setticks; | |||
if (pd_this->pd_clock_setlist && | |||
pd_this->pd_clock_setlist->c_settime <= setticks) | |||
{ | |||
t_clock *cbefore, *cafter; | |||
for (cbefore = pd_this->pd_clock_setlist, | |||
cafter = pd_this->pd_clock_setlist->c_next; | |||
cbefore; cbefore = cafter, cafter = cbefore->c_next) | |||
{ | |||
if (!cafter || cafter->c_settime > setticks) | |||
{ | |||
cbefore->c_next = x; | |||
x->c_next = cafter; | |||
return; | |||
} | |||
} | |||
} | |||
else x->c_next = pd_this->pd_clock_setlist, pd_this->pd_clock_setlist = x; | |||
} | |||
/* set the clock to call back after a delay in msec */ | |||
void clock_delay(t_clock *x, double delaytime) | |||
{ | |||
clock_set(x, (x->c_unit > 0 ? | |||
pd_this->pd_systime + x->c_unit * delaytime : | |||
pd_this->pd_systime - | |||
(x->c_unit*(TIMEUNITPERSECOND/STUFF->st_dacsr)) * delaytime)); | |||
} | |||
/* set the time unit in msec or (if 'samps' is set) in samples. This | |||
is flagged by setting c_unit negative. If the clock is currently set, | |||
recalculate the delay based on the new unit and reschedule */ | |||
void clock_setunit(t_clock *x, double timeunit, int sampflag) | |||
{ | |||
double timeleft; | |||
if (timeunit <= 0) | |||
timeunit = 1; | |||
/* if no change, return to avoid truncation errors recalculating delay */ | |||
if ((sampflag && (timeunit == -x->c_unit)) || | |||
(!sampflag && (timeunit == x->c_unit * TIMEUNITPERMSEC))) | |||
return; | |||
/* figure out time left in the units we were in */ | |||
timeleft = (x->c_settime < 0 ? -1 : | |||
(x->c_settime - pd_this->pd_systime)/((x->c_unit > 0)? x->c_unit : | |||
(x->c_unit*(TIMEUNITPERSECOND/STUFF->st_dacsr)))); | |||
if (sampflag) | |||
x->c_unit = -timeunit; /* negate to flag sample-based */ | |||
else x->c_unit = timeunit * TIMEUNITPERMSEC; | |||
if (timeleft >= 0) /* reschedule if already set */ | |||
clock_delay(x, timeleft); | |||
} | |||
/* get current logical time. We don't specify what units this is in; | |||
use clock_gettimesince() to measure intervals from time of this call. */ | |||
double clock_getlogicaltime( void) | |||
{ | |||
return (pd_this->pd_systime); | |||
} | |||
/* OBSOLETE (misleading) function name kept for compatibility */ | |||
double clock_getsystime( void) { return (pd_this->pd_systime); } | |||
/* elapsed time in milliseconds since the given system time */ | |||
double clock_gettimesince(double prevsystime) | |||
{ | |||
return ((pd_this->pd_systime - prevsystime)/TIMEUNITPERMSEC); | |||
} | |||
/* elapsed time in units, ala clock_setunit(), since given system time */ | |||
double clock_gettimesincewithunits(double prevsystime, | |||
double units, int sampflag) | |||
{ | |||
/* If in samples, divide TIMEUNITPERSECOND/sys_dacsr first (at | |||
cost of an extra division) since it's probably an integer and if | |||
units == 1 and (sys_time - prevsystime) is an integer number of | |||
DSP ticks, the result will be exact. */ | |||
if (sampflag) | |||
return ((pd_this->pd_systime - prevsystime)/ | |||
((TIMEUNITPERSECOND/STUFF->st_dacsr)*units)); | |||
else return ((pd_this->pd_systime - prevsystime)/(TIMEUNITPERMSEC*units)); | |||
} | |||
/* what value the system clock will have after a delay */ | |||
double clock_getsystimeafter(double delaytime) | |||
{ | |||
return (pd_this->pd_systime + TIMEUNITPERMSEC * delaytime); | |||
} | |||
void clock_free(t_clock *x) | |||
{ | |||
clock_unset(x); | |||
freebytes(x, sizeof *x); | |||
} | |||
/* the following routines maintain a real-execution-time histogram of the | |||
various phases of real-time execution. */ | |||
static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000}; | |||
#define NBIN (sizeof(sys_bin)/sizeof(*sys_bin)) | |||
#define NHIST 10 | |||
static int sys_histogram[NHIST][NBIN]; | |||
static double sys_histtime; | |||
static int sched_diddsp, sched_didpoll, sched_didnothing; | |||
void sys_clearhist( void) | |||
{ | |||
unsigned int i, j; | |||
for (i = 0; i < NHIST; i++) | |||
for (j = 0; j < NBIN; j++) sys_histogram[i][j] = 0; | |||
sys_histtime = sys_getrealtime(); | |||
sched_diddsp = sched_didpoll = sched_didnothing = 0; | |||
} | |||
void sys_printhist( void) | |||
{ | |||
unsigned int i, j; | |||
for (i = 0; i < NHIST; i++) | |||
{ | |||
int doit = 0; | |||
for (j = 0; j < NBIN; j++) if (sys_histogram[i][j]) doit = 1; | |||
if (doit) | |||
{ | |||
post("%2d %8d %8d %8d %8d %8d %8d %8d %8d", i, | |||
sys_histogram[i][0], | |||
sys_histogram[i][1], | |||
sys_histogram[i][2], | |||
sys_histogram[i][3], | |||
sys_histogram[i][4], | |||
sys_histogram[i][5], | |||
sys_histogram[i][6], | |||
sys_histogram[i][7]); | |||
} | |||
} | |||
post("dsp %d, pollgui %d, nothing %d", | |||
sched_diddsp, sched_didpoll, sched_didnothing); | |||
} | |||
static int sys_histphase; | |||
int sys_addhist(int phase) | |||
{ | |||
int i, j, phasewas = sys_histphase; | |||
double newtime = sys_getrealtime(); | |||
int msec = (newtime - sys_histtime) * 1000.; | |||
for (j = NBIN-1; j >= 0; j--) | |||
{ | |||
if (msec >= sys_bin[j]) | |||
{ | |||
sys_histogram[phasewas][j]++; | |||
break; | |||
} | |||
} | |||
sys_histtime = newtime; | |||
sys_histphase = phase; | |||
return (phasewas); | |||
} | |||
#define NRESYNC 20 | |||
typedef struct _resync | |||
{ | |||
int r_ntick; | |||
int r_error; | |||
} t_resync; | |||
static int oss_resyncphase = 0; | |||
static int oss_nresync = 0; | |||
static t_resync oss_resync[NRESYNC]; | |||
static char *(oss_errornames[]) = { | |||
"unknown", | |||
"ADC blocked", | |||
"DAC blocked", | |||
"A/D/A sync", | |||
"data late" | |||
}; | |||
void glob_audiostatus(void) | |||
{ | |||
int dev, nresync, nresyncphase, i; | |||
nresync = (oss_nresync >= NRESYNC ? NRESYNC : oss_nresync); | |||
nresyncphase = oss_resyncphase - 1; | |||
post("audio I/O error history:"); | |||
post("seconds ago\terror type"); | |||
for (i = 0; i < nresync; i++) | |||
{ | |||
int errtype; | |||
if (nresyncphase < 0) | |||
nresyncphase += NRESYNC; | |||
errtype = oss_resync[nresyncphase].r_error; | |||
if (errtype < 0 || errtype > 4) | |||
errtype = 0; | |||
post("%9.2f\t%s", | |||
(sched_diddsp - oss_resync[nresyncphase].r_ntick) | |||
* ((double)STUFF->st_schedblocksize) / STUFF->st_dacsr, | |||
oss_errornames[errtype]); | |||
nresyncphase--; | |||
} | |||
} | |||
static int sched_diored; | |||
static int sched_dioredtime; | |||
static int sched_meterson; | |||
void sys_log_error(int type) | |||
{ | |||
oss_resync[oss_resyncphase].r_ntick = sched_diddsp; | |||
oss_resync[oss_resyncphase].r_error = type; | |||
oss_nresync++; | |||
if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0; | |||
if (type != ERR_NOTHING && !sched_diored && | |||
(sched_diddsp >= sched_dioredtime)) | |||
{ | |||
sys_vgui("pdtk_pd_dio 1\n"); | |||
sched_diored = 1; | |||
} | |||
sched_dioredtime = | |||
sched_diddsp + (int)(STUFF->st_dacsr /(double)STUFF->st_schedblocksize); | |||
} | |||
static int sched_lastinclip, sched_lastoutclip, | |||
sched_lastindb, sched_lastoutdb; | |||
void glob_watchdog(t_pd *dummy); | |||
static void sched_pollformeters( void) | |||
{ | |||
int inclip, outclip, indb, outdb; | |||
static int sched_nextmeterpolltime, sched_nextpingtime; | |||
/* if there's no GUI but we're running in "realtime", here is | |||
where we arrange to ping the watchdog every 2 seconds. */ | |||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) | |||
if (!sys_havegui() && sys_hipriority && | |||
(sched_diddsp - sched_nextpingtime > 0)) | |||
{ | |||
glob_watchdog(0); | |||
/* ping every 2 seconds */ | |||
sched_nextpingtime = sched_diddsp + | |||
2 * (int)(STUFF->st_dacsr /(double)STUFF->st_schedblocksize); | |||
} | |||
#endif | |||
if (sched_diddsp - sched_nextmeterpolltime < 0) | |||
return; | |||
if (sched_diored && (sched_diddsp - sched_dioredtime > 0)) | |||
{ | |||
sys_vgui("pdtk_pd_dio 0\n"); | |||
sched_diored = 0; | |||
} | |||
if (sched_meterson) | |||
{ | |||
t_sample inmax, outmax; | |||
sys_getmeters(&inmax, &outmax); | |||
indb = 0.5 + rmstodb(inmax); | |||
outdb = 0.5 + rmstodb(outmax); | |||
inclip = (inmax > 0.999); | |||
outclip = (outmax >= 1.0); | |||
} | |||
else | |||
{ | |||
indb = outdb = 0; | |||
inclip = outclip = 0; | |||
} | |||
if (inclip != sched_lastinclip || outclip != sched_lastoutclip | |||
|| indb != sched_lastindb || outdb != sched_lastoutdb) | |||
{ | |||
sys_vgui("pdtk_pd_meters %d %d %d %d\n", indb, outdb, inclip, outclip); | |||
sched_lastinclip = inclip; | |||
sched_lastoutclip = outclip; | |||
sched_lastindb = indb; | |||
sched_lastoutdb = outdb; | |||
} | |||
sched_nextmeterpolltime = | |||
sched_diddsp + (int)(STUFF->st_dacsr /(double)STUFF->st_schedblocksize); | |||
} | |||
void glob_meters(void *dummy, t_float f) | |||
{ | |||
if (f == 0) | |||
sys_getmeters(0, 0); | |||
sched_meterson = (f != 0); | |||
sched_lastinclip = sched_lastoutclip = sched_lastindb = sched_lastoutdb = | |||
-1; | |||
} | |||
#if 0 | |||
void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) | |||
{ | |||
if (argc) sys_clearhist(); | |||
else sys_printhist(); | |||
} | |||
#endif | |||
void dsp_tick(void); | |||
static int sched_useaudio = SCHED_AUDIO_NONE; | |||
static double sched_referencerealtime, sched_referencelogicaltime; | |||
void sched_reopenmeplease(void) /* request from s_audio for deferred reopen */ | |||
{ | |||
sys_quit = SYS_QUIT_RESTART; | |||
} | |||
void sched_set_using_audio(int flag) | |||
{ | |||
sched_useaudio = flag; | |||
if (flag == SCHED_AUDIO_NONE) | |||
{ | |||
sched_referencerealtime = sys_getrealtime(); | |||
sched_referencelogicaltime = clock_getlogicaltime(); | |||
} | |||
if (flag == SCHED_AUDIO_CALLBACK && | |||
sched_useaudio != SCHED_AUDIO_CALLBACK) | |||
sys_quit = SYS_QUIT_RESTART; | |||
if (flag != SCHED_AUDIO_CALLBACK && | |||
sched_useaudio == SCHED_AUDIO_CALLBACK) | |||
post("sorry, can't turn off callbacks yet; restart Pd"); | |||
/* not right yet! */ | |||
sys_vgui("pdtk_pd_audio %s\n", flag ? "on" : "off"); | |||
} | |||
/* take the scheduler forward one DSP tick, also handling clock timeouts */ | |||
void sched_tick( void) | |||
{ | |||
double next_sys_time = pd_this->pd_systime + | |||
(STUFF->st_schedblocksize/STUFF->st_dacsr) * TIMEUNITPERSECOND; | |||
int countdown = 5000; | |||
while (pd_this->pd_clock_setlist && | |||
pd_this->pd_clock_setlist->c_settime < next_sys_time) | |||
{ | |||
t_clock *c = pd_this->pd_clock_setlist; | |||
pd_this->pd_systime = c->c_settime; | |||
clock_unset(pd_this->pd_clock_setlist); | |||
outlet_setstacklim(); | |||
(*c->c_fn)(c->c_owner); | |||
if (!countdown--) | |||
{ | |||
countdown = 5000; | |||
sys_pollgui(); | |||
} | |||
if (sys_quit) | |||
return; | |||
} | |||
pd_this->pd_systime = next_sys_time; | |||
dsp_tick(); | |||
sched_diddsp++; | |||
} | |||
/* | |||
Here is Pd's "main loop." This routine dispatches clock timeouts and DSP | |||
"ticks" deterministically, and polls for input from MIDI and the GUI. If | |||
we're left idle we also poll for graphics updates; but these are considered | |||
lower priority than the rest. | |||
The time source is normally the audio I/O subsystem via the "sys_send_dacs()" | |||
call. This call returns true if samples were transferred; false means that | |||
the audio I/O system is still busy with previous transfers. | |||
*/ | |||
void sys_pollmidiqueue( void); | |||
void sys_initmidiqueue( void); | |||
/* sys_idlehook is a hook the user can fill in to grab idle time. Return | |||
nonzero if you actually used the time; otherwise we're really really idle and | |||
will now sleep. */ | |||
int (*sys_idlehook)(void); | |||
static void m_pollingscheduler( void) | |||
{ | |||
int idlecount = 0; | |||
/* delete this when I'm sure it's not needed for back compatibility? */ | |||
STUFF->st_time_per_dsp_tick = (TIMEUNITPERSECOND) * | |||
((double)STUFF->st_schedblocksize) / STUFF->st_dacsr; | |||
sys_lock(); | |||
sys_clearhist(); | |||
if (sys_sleepgrain < 100) | |||
sys_sleepgrain = sys_schedadvance/4; | |||
if (sys_sleepgrain < 100) | |||
sys_sleepgrain = 100; | |||
else if (sys_sleepgrain > 5000) | |||
sys_sleepgrain = 5000; | |||
sys_initmidiqueue(); | |||
while (!sys_quit) | |||
{ | |||
int didsomething = 0; | |||
int timeforward; | |||
sys_addhist(0); | |||
waitfortick: | |||
if (sched_useaudio != SCHED_AUDIO_NONE) | |||
{ | |||
sys_unlock(); | |||
timeforward = sys_send_dacs(); | |||
sys_lock(); | |||
#if 0 /* in linux and windoes, sometimes audio devices would freeze, which | |||
in turn would freeze Pd. This code unfroze things by closing | |||
audio in such cases. But this seems no longer necessary, and | |||
on Macs at least, this seems to cause audio to get dropped if | |||
the machine sleeps. */ | |||
/* if dacs remain "idle" for 1 sec, they're hung up. */ | |||
if (timeforward != 0) | |||
idlecount = 0; | |||
else | |||
{ | |||
idlecount++; | |||
if (!(idlecount & 31)) | |||
{ | |||
static double idletime; | |||
if (sched_useaudio != SCHED_AUDIO_POLL) | |||
{ | |||
bug("m_pollingscheduler\n"); | |||
return; | |||
} | |||
/* on 32nd idle, start a clock watch; every | |||
32 ensuing idles, check it */ | |||
if (idlecount == 32) | |||
idletime = sys_getrealtime(); | |||
else if (sys_getrealtime() - idletime > 1.) | |||
{ | |||
error("audio I/O stuck... closing audio\n"); | |||
sys_close_audio(); | |||
sched_set_using_audio(SCHED_AUDIO_NONE); | |||
goto waitfortick; | |||
} | |||
} | |||
} | |||
#endif /* 0 */ | |||
} | |||
else | |||
{ | |||
if (1000. * (sys_getrealtime() - sched_referencerealtime) | |||
> clock_gettimesince(sched_referencelogicaltime)) | |||
timeforward = SENDDACS_YES; | |||
else timeforward = SENDDACS_NO; | |||
} | |||
sys_setmiditimediff(0, 1e-6 * sys_schedadvance); | |||
sys_addhist(1); | |||
if (timeforward != SENDDACS_NO) | |||
sched_tick(); | |||
if (timeforward == SENDDACS_YES) | |||
didsomething = 1; | |||
sys_addhist(2); | |||
sys_pollmidiqueue(); | |||
if (sys_pollgui()) | |||
{ | |||
if (!didsomething) | |||
sched_didpoll++; | |||
didsomething = 1; | |||
} | |||
sys_addhist(3); | |||
/* test for idle; if so, do graphics updates. */ | |||
if (!didsomething) | |||
{ | |||
sched_pollformeters(); | |||
sys_reportidle(); | |||
sys_unlock(); /* unlock while we idle */ | |||
/* call externally installed idle function if any. */ | |||
if (!sys_idlehook || !sys_idlehook()) | |||
{ | |||
/* if even that had nothing to do, sleep. */ | |||
if (timeforward != SENDDACS_SLEPT) | |||
sys_microsleep(sys_sleepgrain); | |||
} | |||
sys_lock(); | |||
sys_addhist(5); | |||
sched_didnothing++; | |||
} | |||
} | |||
sys_unlock(); | |||
} | |||
void sched_audio_callbackfn(void) | |||
{ | |||
sys_lock(); | |||
sys_setmiditimediff(0, 1e-6 * sys_schedadvance); | |||
sys_addhist(1); | |||
sched_tick(); | |||
sys_addhist(2); | |||
sys_pollmidiqueue(); | |||
sys_addhist(3); | |||
sys_pollgui(); | |||
sys_addhist(5); | |||
sched_pollformeters(); | |||
sys_addhist(0); | |||
sys_unlock(); | |||
} | |||
static void m_callbackscheduler(void) | |||
{ | |||
sys_initmidiqueue(); | |||
while (!sys_quit) | |||
{ | |||
double timewas = pd_this->pd_systime; | |||
#ifdef _WIN32 | |||
Sleep(1000); | |||
#else | |||
sleep(1); | |||
#endif | |||
if (pd_this->pd_systime == timewas) | |||
{ | |||
sys_lock(); | |||
sys_pollgui(); | |||
sched_tick(); | |||
sys_unlock(); | |||
} | |||
if (sys_idlehook) | |||
sys_idlehook(); | |||
} | |||
} | |||
int m_mainloop(void) | |||
{ | |||
while (sys_quit != SYS_QUIT_QUIT) | |||
{ | |||
if (sched_useaudio == SCHED_AUDIO_CALLBACK) | |||
m_callbackscheduler(); | |||
else m_pollingscheduler(); | |||
if (sys_quit == SYS_QUIT_RESTART) | |||
{ | |||
sys_quit = 0; | |||
if (audio_isopen()) | |||
{ | |||
sys_close_audio(); | |||
sys_reopen_audio(); | |||
} | |||
} | |||
} | |||
return (0); | |||
} | |||
int m_batchmain(void) | |||
{ | |||
while (sys_quit != SYS_QUIT_QUIT) | |||
sched_tick(); | |||
return (0); | |||
} | |||
void sys_exit(void) | |||
{ | |||
sys_quit = SYS_QUIT_QUIT; | |||
} |
@@ -0,0 +1,271 @@ | |||
# You can use this makefile to compile Pd for Gnu/linux. Masochists and | |||
# packagers might prefer the automake route as described in ../README.txt | |||
# You can invoke this one as: $ make -f makefile.gnu | |||
# You don't have to "make install" - you can just invoke Pd from ../bin. | |||
# | |||
# targets include: | |||
# all: pd, pd-watchdog, pdsend, pdreceive, and all extras. | |||
# bin: just pd, pd-watchdog, pdsend, pdreceive. | |||
# local-clean: clean up for "bin" target" | |||
# clean: clean everything | |||
# depend: c header dependencies | |||
# tags: tags file | |||
# install: install to /usr/local (or elsewhere by setting "prefix" variable) | |||
# | |||
# You can get jack support ($ make -f makfile.gnu JACK=TRUE) or compile in | |||
# the portaudio library (PA=TRUE). By default, both ALSA and OSS (BSD style) | |||
# audio APIs are compiled in. You can disable them (e.g., OSS=FALSE). In | |||
# Gnu/linux, you can also just install "alsa-oss." | |||
# | |||
# You can add compiler flags using CODECFLAGS, MORECFLAGS and/or MORELDFLAGS. | |||
# For example, you can turn off optimizing and enable debugging: CODECFLAGS=-g | |||
# or compile with native double precision: MORECFLAGS=-DPD_FLOATSIZE=64 | |||
# The MORECFLAGS variable is propagated to "extras" but CODECFLAGS and | |||
# MORELDFLAGS are not. | |||
# | |||
# Packages you might need: | |||
# tk-devel alsa-devel alsa-oss (unless you disable OSS). | |||
# jack-audio-connection-kit-devel (if you want jack support) | |||
VPATH = ../obj:./ | |||
OBJ_DIR = ../obj | |||
BIN_DIR = ../bin | |||
PDEXEC = $(BIN_DIR)/pd | |||
EXT= pd_linux | |||
ALSA=true | |||
OSS=true | |||
prefix = /usr/local | |||
exec_prefix = ${prefix} | |||
bindir = ${exec_prefix}/bin | |||
includedir = ${prefix}/include | |||
libdir = ${exec_prefix}/lib | |||
mandir = ${prefix}/share/man | |||
# varibles to match packages/Makefile.buildlayout so that they can be easily | |||
# overridden when building Pd-extended builds. <hans@at.or.at> | |||
libpddir = $(libdir)/pd | |||
pddocdir = $(libpddir)/doc | |||
libpdbindir = $(libpddir)/bin | |||
libpdtcldir = $(libpddir)/tcl | |||
# The C flags are separated into CPPFLAGS, CODECFLAGS, and MORECFLAGS | |||
# to allow easy overriding of CODECFLAGS and to allow adding MORECFLAGS: | |||
# C preprocessor flags, and flags controlling errors and warnings | |||
CPPFLAGS = -DPD -DHAVE_LIBDL -DHAVE_UNISTD_H -DHAVE_ALLOCA_H \ | |||
-DPDGUIDIR=\"tcl/\" \ | |||
-D_LARGEFILE64_SOURCE -DINSTALL_PREFIX=\"$(prefix)\" \ | |||
-Wall -W -Wstrict-prototypes -Wno-address\ | |||
-Wno-unused -Wno-unused-parameter -Wno-parentheses -Wno-switch | |||
# code generation flags (e.g., optimization). | |||
CODECFLAGS = -g -O3 -ffast-math -funroll-loops -fomit-frame-pointer | |||
# anything else you want to specify. Also passed on to "extra" makefiles. | |||
MORECFLAGS = | |||
# "standard" flags for linker | |||
LDFLAGS = -Wl,-export-dynamic | |||
# and another variable you can override to add more (like "-g"). | |||
MORELDFLAGS = | |||
# libraries and system-dependent sources. | |||
# These get added onto if JACK, etc., are defined below | |||
LIB = -ldl -lm -lpthread | |||
SYSSRC = s_midi_oss.c | |||
# conditionally add code and flags for various audio APIs | |||
ifeq ($(ALSA), true) | |||
CPPFLAGS += -DUSEAPI_ALSA | |||
SYSSRC += s_audio_alsa.c s_audio_alsamm.c s_midi_alsa.c | |||
LIB += -lasound | |||
HAVEAUDIOAPI=true | |||
endif | |||
ifdef JACK | |||
CPPFLAGS += -DUSEAPI_JACK | |||
SYSSRC += s_audio_jack.c | |||
LIB += -ljack | |||
HAVEAUDIOAPI=true | |||
endif | |||
ifeq ($(OSS), true) | |||
#error foo | |||
CPPFLAGS += -DUSEAPI_OSS | |||
SYSSRC += s_audio_oss.c | |||
HAVEAUDIOAPI=true | |||
endif | |||
ifdef PA | |||
CPPFLAGS += -DUSEAPI_PORTAUDIO | |||
SYSSRC += s_audio_pa.c | |||
LIB += -lportaudio | |||
HAVEAUDIOAPI=true | |||
endif | |||
ifndef HAVEAUDIOAPI | |||
CPPFLAGS += -DUSEAPI_DUMMY | |||
SYSSRC += s_audio_dummy.c | |||
endif | |||
CFLAGS = $(CPPFLAGS) $(CODECFLAGS) $(MORECFLAGS) | |||
SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \ | |||
g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c g_clone.c \ | |||
g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ | |||
g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \ | |||
m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \ | |||
m_conf.c m_glob.c m_sched.c \ | |||
s_main.c s_inter.c s_file.c s_print.c \ | |||
s_loader.c s_path.c s_entry.c s_audio.c s_midi.c s_utf8.c s_audio_paring.c \ | |||
d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \ | |||
d_math.c d_fft.c d_fft_fftsg.c d_array.c d_global.c \ | |||
d_delay.c d_resample.c d_soundfile.c \ | |||
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \ | |||
x_time.c x_acoustics.c x_net.c x_text.c x_gui.c x_list.c x_array.c \ | |||
x_scalar.c x_vexp.c x_vexp_if.c x_vexp_fun.c \ | |||
$(SYSSRC) | |||
OBJ = $(SRC:.c=.o) | |||
# get version from m_pd.h to use in doc/1.manual/1.introduction.txt | |||
PD_MAJOR_VERSION := $(shell grep PD_MAJOR_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_MAJOR_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_MINOR_VERSION := $(shell grep PD_MINOR_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_MINOR_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_BUGFIX_VERSION := $(shell grep PD_BUGFIX_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_BUGFIX_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_TEST_VERSION := $(shell grep PD_TEST_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_TEST_VERSION *"\(.*\)".*|\1|' ) | |||
PD_VERSION := $(PD_MAJOR_VERSION).$(PD_MINOR_VERSION).$(PD_BUGFIX_VERSION) | |||
ifneq ($(PD_TEST_VERSION),) | |||
PD_VERSION := $(PD_VERSION)-$(PD_TEST_VERSION) | |||
endif | |||
# | |||
# ------------------ targets ------------------------------------ | |||
# | |||
.PHONY: pd externs all depend | |||
all: pd $(BIN_DIR)/pd-watchdog $(BIN_DIR)/pdsend $(BIN_DIR)/pdreceive externs \ | |||
makefile.dependencies | |||
bin: pd $(BIN_DIR)/pd-watchdog $(BIN_DIR)/pdsend $(BIN_DIR)/pdreceive | |||
$(OBJ) : %.o : %.c | |||
$(CC) $(CFLAGS) $(INCLUDE) -c -o $(OBJ_DIR)/$*.o $*.c | |||
pd: $(PDEXEC) | |||
pd-watchdog: $(BIN_DIR)/pd-watchdog | |||
$(BIN_DIR)/pd-watchdog: s_watchdog.c | |||
test -d $(BIN_DIR) || mkdir -p $(BIN_DIR) | |||
$(CC) $(CFLAGS) -o $(BIN_DIR)/pd-watchdog s_watchdog.c | |||
$(BIN_DIR)/pdsend: u_pdsend.c | |||
test -d $(BIN_DIR) || mkdir -p $(BIN_DIR) | |||
$(CC) $(CFLAGS) -o $(BIN_DIR)/pdsend u_pdsend.c | |||
$(BIN_DIR)/pdreceive: u_pdreceive.c | |||
test -d $(BIN_DIR) || mkdir -p $(BIN_DIR) | |||
$(CC) $(CFLAGS) -o $(BIN_DIR)/pdreceive u_pdreceive.c | |||
$(PDEXEC): $(OBJ_DIR) $(OBJ) | |||
test -d $(BIN_DIR) || mkdir -p $(BIN_DIR) | |||
cd ../obj; $(CC) $(LDFLAGS) $(MORELDFLAGS) -o $(PDEXEC) $(OBJ) $(LIB) | |||
externs: | |||
make -C ../extra/bonk~ MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/choice MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/fiddle~ MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/loop~ MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/lrshift~ MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/pique MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/sigmund~ MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/pd~ MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/stdout MORECFLAGS="$(MORECFLAGS)" | |||
make -C ../extra/bob~ MORECFLAGS="$(MORECFLAGS)" | |||
BINARYMODE=-m755 | |||
ABOUT_FILE=$(DESTDIR)$(pddocdir)/1.manual/1.introduction.txt | |||
install: all | |||
install -d $(DESTDIR)$(libpdbindir) | |||
install $(BIN_DIR)/pd-watchdog $(DESTDIR)$(libpdbindir)/pd-watchdog | |||
install $(BINARYMODE) $(PDEXEC) $(DESTDIR)$(libpdbindir)/pd | |||
install -d $(DESTDIR)$(bindir) | |||
install $(BINARYMODE) $(PDEXEC) $(DESTDIR)$(bindir)/pd | |||
install -m755 $(BIN_DIR)/pdsend $(DESTDIR)$(bindir)/pdsend | |||
install -m755 $(BIN_DIR)/pdreceive $(DESTDIR)$(bindir)/pdreceive | |||
install -d $(DESTDIR)$(libpdtcldir) | |||
install ../tcl/* $(DESTDIR)$(libpdtcldir) | |||
for dir in $(shell ls -1 ../doc | grep -v CVS); do \ | |||
echo "installing $$dir"; \ | |||
install -d $(DESTDIR)$(pddocdir)/$$dir ; \ | |||
install -m644 -p ../doc/$$dir/*.* $(DESTDIR)$(pddocdir)/$$dir ; \ | |||
done | |||
for dir in $(shell ls -1 ../doc/7.stuff | grep -v CVS); do \ | |||
echo "installing 7.stuff/$$dir"; \ | |||
install -d $(DESTDIR)$(pddocdir)/7.stuff/$$dir ; \ | |||
install -m644 -p ../doc/7.stuff/$$dir/*.* \ | |||
$(DESTDIR)$(pddocdir)/7.stuff/$$dir ; \ | |||
done | |||
mv $(ABOUT_FILE) $(ABOUT_FILE).tmp | |||
cat $(ABOUT_FILE).tmp | sed 's|PD_VERSION|Pd version $(PD_VERSION)|' \ | |||
> $(ABOUT_FILE) | |||
rm $(ABOUT_FILE).tmp | |||
cp -pr ../extra $(DESTDIR)$(libpddir)/ | |||
rm -f $(DESTDIR)$(libpddir)/extra/*/*.o | |||
install -d $(DESTDIR)$(includedir) | |||
install -m644 m_pd.h $(DESTDIR)$(includedir)/m_pd.h | |||
install -d $(DESTDIR)$(mandir)/man1 | |||
gzip < ../man/pd.1 > $(DESTDIR)$(mandir)/man1/pd.1.gz | |||
chmod 644 $(DESTDIR)$(mandir)/man1/pd.1.gz | |||
gzip < ../man/pdsend.1 > $(DESTDIR)$(mandir)/man1/pdsend.1.gz | |||
chmod 644 $(DESTDIR)$(mandir)/man1/pdsend.1.gz | |||
gzip < ../man/pdreceive.1 > $(DESTDIR)$(mandir)/man1/pdreceive.1.gz | |||
chmod 644 $(DESTDIR)$(mandir)/man1/pdreceive.1.gz | |||
@echo "Pd install succeeded." | |||
local-clean: | |||
-rm -f ../obj/* $(BIN_DIR)/pd $(BIN_DIR)/pdsend \ | |||
$(BIN_DIR)/pdreceive $(BIN_DIR)/pd-watchdog m_stamp.c \ | |||
$(BIN_DIR)/*.tcl | |||
-rm -f `find ../portaudio -name "*.o"` | |||
-rm -f *~ | |||
-(cd ../doc/6.externs; rm -f *.pd_linux) | |||
-rm -f makefile.dependencies | |||
extra-clean: | |||
-rm -f `find ../extra/ -name "*.pd_*"` | |||
-rm -f tags | |||
clean: extra-clean local-clean | |||
distclean: clean | |||
-rm -f config.cache config.log config.status makefile tags \ | |||
autom4te.cache/output.* autom4te.cache/traces.* autom4te.cache/requests | |||
-rmdir autom4te.cache | |||
-rm -rf autom4te-*.cache | |||
tags: $(SRC) $(GSRC); ctags *.[ch] | |||
depend: makefile.dependencies | |||
$(OBJ_DIR): | |||
test -d $(OBJ_DIR) || mkdir -p $(OBJ_DIR) | |||
makefile.dependencies: | |||
$(CC) $(CPPFLAGS) -M $(SRC) > makefile.dependencies | |||
uninstall: | |||
rm -f -r $(DESTDIR)$(libpddir) | |||
rm -f $(DESTDIR)$(bindir)/pd | |||
rm -f $(DESTDIR)$(bindir)/pdsend | |||
rm -f $(DESTDIR)$(bindir)/pdreceive | |||
rm -f $(DESTDIR)$(includedir)/m_pd.h | |||
rm -f $(DESTDIR)$(mandir)/man1/pd.1.gz | |||
rm -f $(DESTDIR)$(mandir)/man1/pdsend.1.gz | |||
rm -f $(DESTDIR)$(mandir)/man1/pdreceive.1.gz | |||
-include makefile.dependencies |
@@ -0,0 +1,242 @@ | |||
# On Mac OS X, this needs to be defined to enable dlopen and weak linking | |||
# support. Its safe on other platforms since gcc only checks this env var on | |||
# Apple's gcc. <hans@at.or.at> | |||
export MACOSX_DEPLOYMENT_TARGET = 10.3 | |||
VPATH = ../obj:./ | |||
OBJ_DIR = ../obj | |||
BIN_DIR = ../bin | |||
PDEXEC = $(BIN_DIR)/pd | |||
EXT= pd_darwin | |||
GUINAME= libPdTcl.dylib | |||
ARCH= -arch i386 -arch ppc | |||
EXTRAARCH= -arch i386 -arch x86_64 -arch ppc | |||
prefix = /usr/local | |||
exec_prefix = ${prefix} | |||
bindir = ${exec_prefix}/bin | |||
includedir = ${prefix}/include | |||
libdir = ${exec_prefix}/lib | |||
mandir = ${prefix}/man | |||
# varibles to match packages/Makefile.buildlayout so that they can be easily | |||
# overridden when building Pd-extended builds. <hans@at.or.at> | |||
libpddir = $(libdir)/pd | |||
pddocdir = $(libpddir)/doc | |||
libpdbindir = $(libpddir)/bin | |||
libpdtcldir = $(libpddir)/tcl | |||
PADIR = ../portaudio/portaudio | |||
PMDIR = ../portmidi/portmidi | |||
CPPFLAGS = -DPD -DINSTALL_PREFIX=\"$(prefix)\" \ | |||
-DHAVE_LIBDL -DMACOSX -DHAVE_UNISTD_H -I/usr/X11R6/include \ | |||
-I$(PADIR)/include -I$(PADIR)/src/common \ | |||
-I$(PADIR)/src/os/mac_osx/ -I$(PMDIR)/pm_common \ | |||
-I$(PMDIR)/pm_mac -I$(PMDIR)/porttime \ | |||
-DUSEAPI_PORTAUDIO -DPA_USE_COREAUDIO -DNEWBUFFER | |||
ARCH_CFLAGS = $(ARCH) | |||
WARN_CFLAGS = -Wall -W -Wstrict-prototypes -Wno-unused -Wno-unused-parameter \ | |||
-Wno-parentheses -Wno-switch | |||
MORECFLAGS = -Wno-error -ffast-math -O3 | |||
LDFLAGS = -Wl -framework CoreAudio -framework AudioUnit \ | |||
-framework AudioToolbox -framework Carbon -framework CoreMIDI $(ARCH) \ | |||
LIB = -ldl -lm -lpthread | |||
ifdef JACK | |||
CPPFLAGS += -DUSEAPI_JACK | |||
SYSSRC += s_audio_jack.c | |||
LIB += -weak_framework Jackmp | |||
endif | |||
CFLAGS = $(ARCH_CFLAGS) $(WARN_CFLAGS) $(CPPFLAGS) $(MORECFLAGS) | |||
# the sources | |||
SYSSRC += s_midi_pm.c s_audio_pa.c s_audio_paring.c \ | |||
$(PADIR)/src/common/pa_allocation.c \ | |||
$(PADIR)/src/common/pa_converters.c \ | |||
$(PADIR)/src/common/pa_cpuload.c \ | |||
$(PADIR)/src/common/pa_dither.c \ | |||
$(PADIR)/src/common/pa_front.c \ | |||
$(PADIR)/src/common/pa_process.c \ | |||
$(PADIR)/src/common/pa_stream.c \ | |||
$(PADIR)/src/common/pa_trace.c \ | |||
$(PADIR)/src/common/pa_debugprint.c \ | |||
$(PADIR)/src/common/pa_ringbuffer.c \ | |||
$(PADIR)/src/os/unix/pa_unix_util.c \ | |||
$(PADIR)/src/os/mac_osx/pa_mac_hostapis.c \ | |||
$(PADIR)/src/hostapi/coreaudio/pa_mac_core.c \ | |||
$(PADIR)/src/hostapi/coreaudio/pa_mac_core_blocking.c \ | |||
$(PADIR)/src/hostapi/coreaudio/pa_mac_core_utilities.c \ | |||
$(PMDIR)/pm_mac/pmmac.c \ | |||
$(PMDIR)/pm_mac/pmmacosxcm.c \ | |||
$(PMDIR)/pm_mac/finddefault.c \ | |||
$(PMDIR)/pm_mac/readbinaryplist.c \ | |||
$(PMDIR)/pm_common/pmutil.c \ | |||
$(PMDIR)/pm_common/portmidi.c \ | |||
$(PMDIR)/porttime/ptmacosx_cf.c | |||
SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \ | |||
g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c g_clone.c \ | |||
g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ | |||
g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \ | |||
m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \ | |||
m_conf.c m_glob.c m_sched.c \ | |||
s_main.c s_inter.c s_file.c s_print.c \ | |||
s_loader.c s_path.c s_entry.c s_audio.c s_midi.c s_utf8.c \ | |||
d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \ | |||
d_math.c d_fft.c d_fft_fftsg.c d_array.c d_global.c \ | |||
d_delay.c d_resample.c d_soundfile.c \ | |||
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \ | |||
x_time.c x_acoustics.c x_net.c x_text.c x_gui.c x_list.c x_array.c \ | |||
x_scalar.c x_vexp.c x_vexp_if.c x_vexp_fun.c \ | |||
$(SYSSRC) | |||
OBJ = $(SRC:.c=.o) | |||
# get version from m_pd.h to use in doc/1.manual/1.introduction.txt | |||
PD_MAJOR_VERSION := $(shell grep PD_MAJOR_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_MAJOR_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_MINOR_VERSION := $(shell grep PD_MINOR_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_MINOR_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_BUGFIX_VERSION := $(shell grep PD_BUGFIX_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_BUGFIX_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_TEST_VERSION := $(shell grep PD_TEST_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_TEST_VERSION *"\(.*\)".*|\1|' ) | |||
PD_VERSION := $(PD_MAJOR_VERSION).$(PD_MINOR_VERSION).$(PD_BUGFIX_VERSION) | |||
ifneq ($(PD_TEST_VERSION),) | |||
PD_VERSION := $(PD_VERSION)-$(PD_TEST_VERSION) | |||
endif | |||
# | |||
# ------------------ targets ------------------------------------ | |||
# | |||
.PHONY: pd gui externs all | |||
all: pd $(BIN_DIR)/pd-watchdog gui $(BIN_DIR)/pdsend \ | |||
$(BIN_DIR)/pdreceive externs | |||
bin: pd $(BIN_DIR)/pd-watchdog gui $(BIN_DIR)/pdsend \ | |||
$(BIN_DIR)/pdreceive | |||
$(OBJ) : %.o : %.c | |||
$(CC) $(CFLAGS) $(INCLUDE) -c -o $(OBJ_DIR)/$*.o $*.c | |||
pd: $(PDEXEC) | |||
pd-watchdog: $(BIN_DIR)/pd-watchdog | |||
$(BIN_DIR): | |||
test -d $(BIN_DIR) || mkdir -p $(BIN_DIR) | |||
$(BIN_DIR)/pd-watchdog: s_watchdog.c $(BIN_DIR) | |||
$(CC) $(CFLAGS) $(STRIPFLAG) -o $(BIN_DIR)/pd-watchdog s_watchdog.c | |||
$(BIN_DIR)/pdsend: u_pdsend.c $(BIN_DIR) | |||
$(CC) $(CFLAGS) $(STRIPFLAG) -o $(BIN_DIR)/pdsend u_pdsend.c | |||
$(BIN_DIR)/pdreceive: u_pdreceive.c $(BIN_DIR) | |||
$(CC) $(CFLAGS) $(STRIPFLAG) -o $(BIN_DIR)/pdreceive u_pdreceive.c | |||
$(PDEXEC): $(OBJ) $(BIN_DIR) | |||
cd ../obj; $(CC) $(LDFLAGS) $(DBG_CFLAGS) -o $(PDEXEC) $(OBJ) $(LIB) | |||
externs: | |||
make -C ../extra/bonk~ DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/choice DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/fiddle~ DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/loop~ DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/lrshift~ DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/pique DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/sigmund~ DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/pd~ DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/stdout DARWINARCH="$(EXTRAARCH)" d_fat | |||
make -C ../extra/bob~ DARWINARCH="$(EXTRAARCH)" d_fat | |||
BINARYMODE=-m755 | |||
ABOUT_FILE=$(DESTDIR)$(pddocdir)/1.manual/1.introduction.txt | |||
install: all | |||
install -d $(DESTDIR)$(libpdbindir) | |||
-install $(BIN_DIR)/$(GUINAME) $(DESTDIR)$(libpdbindir)/$(GUINAME) | |||
install $(BIN_DIR)/pd-watchdog $(DESTDIR)$(libpdbindir)/pd-watchdog | |||
install -d $(DESTDIR)$(bindir) | |||
install $(BINARYMODE) $(PDEXEC) $(DESTDIR)$(bindir)/pd | |||
install -m755 $(BIN_DIR)/pdsend $(DESTDIR)$(bindir)/pdsend | |||
install -m755 $(BIN_DIR)/pdreceive $(DESTDIR)$(bindir)/pdreceive | |||
install -d $(DESTDIR)$(libpdtcldir) | |||
install ../tcl/* $(DESTDIR)$(libpdtcldir) | |||
for dir in $(shell ls -1 ../doc | grep -v CVS); do \ | |||
echo "installing $$dir"; \ | |||
install -d $(DESTDIR)$(pddocdir)/$$dir ; \ | |||
install -m644 -p ../doc/$$dir/*.* $(DESTDIR)$(pddocdir)/$$dir ; \ | |||
done | |||
for dir in $(shell ls -1 ../doc/7.stuff | grep -v CVS); do \ | |||
echo "installing 7.stuff/$$dir"; \ | |||
install -d $(DESTDIR)$(pddocdir)/7.stuff/$$dir ; \ | |||
install -m644 -p ../doc/7.stuff/$$dir/*.* \ | |||
$(DESTDIR)$(pddocdir)/7.stuff/$$dir ; \ | |||
done | |||
mv $(ABOUT_FILE) $(ABOUT_FILE).tmp | |||
cat $(ABOUT_FILE).tmp | sed 's|PD_VERSION|Pd version $(PD_VERSION)|' \ | |||
> $(ABOUT_FILE) | |||
rm $(ABOUT_FILE).tmp | |||
cp -pr ../extra $(DESTDIR)$(libpddir)/ | |||
rm -f $(DESTDIR)$(libpddir)/extra/*/*.o | |||
install -d $(DESTDIR)$(includedir) | |||
install -m644 m_pd.h $(DESTDIR)$(includedir)/m_pd.h | |||
install -d $(DESTDIR)$(mandir)/man1 | |||
gzip < ../man/pd.1 > $(DESTDIR)$(mandir)/man1/pd.1.gz | |||
chmod 644 $(DESTDIR)$(mandir)/man1/pd.1.gz | |||
gzip < ../man/pdsend.1 > $(DESTDIR)$(mandir)/man1/pdsend.1.gz | |||
chmod 644 $(DESTDIR)$(mandir)/man1/pdsend.1.gz | |||
gzip < ../man/pdreceive.1 > $(DESTDIR)$(mandir)/man1/pdreceive.1.gz | |||
chmod 644 $(DESTDIR)$(mandir)/man1/pdreceive.1.gz | |||
@echo "Pd install succeeded." | |||
local-clean: | |||
-rm -f ../obj/* $(BIN_DIR)/pd $(BIN_DIR)/pdsend \ | |||
$(BIN_DIR)/pdreceive $(BIN_DIR)/pd-watchdog m_stamp.c \ | |||
$(BIN_DIR)/*.tcl | |||
-rm -f `find ../portaudio -name "*.o"` | |||
-rm -f *~ | |||
-(cd ../doc/6.externs; rm -f *.pd_linux) | |||
-rm -f makefile.dependencies | |||
touch makefile.dependencies | |||
chmod 666 makefile.dependencies | |||
extra-clean: | |||
-rm -f `find ../extra/ -name "*.pd_*"` | |||
-rm -f tags | |||
clean: extra-clean local-clean | |||
distclean: clean | |||
-rm -f config.cache config.log config.status makefile tags \ | |||
autom4te.cache/output.* autom4te.cache/traces.* autom4te.cache/requests | |||
-rmdir autom4te.cache | |||
-rm -rf autom4te-*.cache | |||
tags: $(SRC) $(GSRC); ctags *.[ch] | |||
depend: makefile.dependencies | |||
makefile.dependencies: | |||
$(CC) $(CPPFLAGS) -M $(SRC) > makefile.dependencies | |||
uninstall: | |||
rm -f -r $(DESTDIR)$(libpddir) | |||
rm -f $(DESTDIR)$(bindir)/pd | |||
rm -f $(DESTDIR)$(bindir)/pdsend | |||
rm -f $(DESTDIR)$(bindir)/pdreceive | |||
rm -f $(DESTDIR)$(includedir)/m_pd.h | |||
rm -f $(DESTDIR)$(mandir)/man1/pd.1.gz | |||
rm -f $(DESTDIR)$(mandir)/man1/pdsend.1.gz | |||
rm -f $(DESTDIR)$(mandir)/man1/pdreceive.1.gz | |||
include makefile.dependencies |
@@ -0,0 +1,318 @@ | |||
# makefile to compile for windows using the mingw suite. | |||
# To use this makefile to cross-compile from linux, type for example: | |||
# make -f makefile.mingw CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-c++ \ | |||
# WINDRES=i686-w64-mingw32-windres | |||
# Miller's Windows build uses Microsoft Visual C and makefile.msvc: | |||
# http://lists.puredata.info/pipermail/pd-dev/2004-10/002981.html | |||
CC = gcc | |||
CXX = g++ | |||
WINDRES = windres | |||
cvs_root_dir = ../.. | |||
pd_src = $(cvs_root_dir)/pd | |||
DLL_DIR = $(pd_src)/src | |||
BIN_DIR = ../bin | |||
VPATH = $(pd_src)/src | |||
prefix = /usr/local/pd | |||
exec_prefix = $(prefix) | |||
includedir = $(prefix)/include | |||
libdir = $(exec_prefix)/lib | |||
mandir = $(prefix)/man | |||
bindir = $(exec_prefix)/bin | |||
GFLAGS = -DINSTALL_PREFIX=\"$(prefix)\" | |||
# varibles to match packages/Makefile.buildlayout so that they can be easily | |||
# overridden when building Pd-extended builds. <hans@at.or.at> | |||
libpddir = $(prefix) | |||
pddocdir = $(libpddir)/doc | |||
libpdbindir = $(libpddir)/bin | |||
EXECDIR=../bin | |||
PDEXEC = $(EXECDIR)/pd.exe | |||
PDDLL = $(EXECDIR)/pd.dll | |||
PDCOM = $(EXECDIR)/pd.com | |||
PDRECEIVE = $(EXECDIR)/pdreceive.exe | |||
PDSEND = $(EXECDIR)/pdsend.exe | |||
DLLWRAP= dllwrap | |||
MORECFLAGS = -O3 -funroll-loops -fomit-frame-pointer | |||
PADIR = $(pd_src)/portaudio/portaudio | |||
ASIODIR = $(pd_src)/lib/ASIOSDK | |||
ASIOINC = -I$(ASIODIR)/common -I$(ASIODIR)/host -I$(ASIODIR)/host/pc | |||
INCPA = -I$(PADIR)/include -I$(PADIR)/src/common -I$(PADIR)/src/os/win \ | |||
$(ASIOINC) | |||
INCLUDE = -I$(pd_src)/src | |||
GINCLUDE = -I/usr/local/include $(INCLUDE) | |||
LDFLAGS = | |||
LIBS = -lm -lwsock32 -lwinmm -lole32 -lpthread \ | |||
-static-libgcc -static-libstdc++ | |||
OPT_CFLAGS = | |||
WARN_CFLAGS = -Wall -W -Wstrict-prototypes -Wno-unused \ | |||
-Wno-unused-parameter -Wno-parentheses -Wno-switch | |||
# Some old code in asio/ASIOSDK/common/combase.h needs to be ignored, | |||
# we do this by setting the WINVER macro to min Windows XP aka 5.1. | |||
# Also, for SetDllDirectory() s_loader.c, we need a minium of Windows | |||
# XP SP1. WINVER isnt' fine-grained enough for that, so we use the | |||
# next minor version of Windows, 5.2. | |||
ARCH_CFLAGS = -DPD -DPD_INTERNAL -DPA_USE_ASIO -DPA_USE_WMME -DWINVER=0x0502 \ | |||
-DUSEAPI_MMIO -DUSEAPI_PORTAUDIO -mms-bitfields -DWISH='"wish85.exe"' | |||
CFLAGS += $(ARCH_CFLAGS) $(WARN_CFLAGS) $(OPT_CFLAGS) $(MORECFLAGS) | |||
STRIP = strip --strip-unneeded -R .note -R .comment | |||
# the sources | |||
PASRC = s_audio_pa.c s_audio_paring.c \ | |||
s_audio_mmio.c \ | |||
$(PADIR)/src/common/pa_stream.c \ | |||
$(PADIR)/src/common/pa_trace.c \ | |||
$(PADIR)/src/common/pa_process.c \ | |||
$(PADIR)/src/common/pa_front.c \ | |||
$(PADIR)/src/common/pa_dither.c \ | |||
$(PADIR)/src/common/pa_cpuload.c \ | |||
$(PADIR)/src/common/pa_converters.c \ | |||
$(PADIR)/src/common/pa_allocation.c \ | |||
$(PADIR)/src/common/pa_ringbuffer.c \ | |||
$(PADIR)/src/os/win/pa_win_coinitialize.c \ | |||
$(PADIR)/src/os/win/pa_win_hostapis.c \ | |||
$(PADIR)/src/os/win/pa_win_util.c \ | |||
$(PADIR)/src/os/win/pa_win_waveformat.c \ | |||
$(PADIR)/src/hostapi/wmme/pa_win_wmme.c | |||
ASIOSRC = $(PADIR)/src/hostapi/asio/iasiothiscallresolver.cpp \ | |||
$(PADIR)/src/hostapi/asio/pa_asio.cpp \ | |||
$(ASIODIR)/common/asio.cpp \ | |||
$(ASIODIR)/host/asiodrivers.cpp \ | |||
$(ASIODIR)/host/pc/asiolist.cpp | |||
#VSRC = s_audio_vst.c | |||
PMDIR = ../portmidi/portmidi | |||
PMINCLUDE = -I$(PMDIR)/pm_common -I$(PMDIR)/pm_win -I$(PMDIR)/porttime \ | |||
-DNEWBUFFER | |||
PMSRC = s_midi_pm.c \ | |||
$(PMDIR)/pm_common/portmidi.c \ | |||
$(PMDIR)/pm_common/pmutil.c \ | |||
$(PMDIR)/porttime/porttime.c \ | |||
$(PMDIR)/porttime/ptwinmm.c \ | |||
$(PMDIR)/pm_win/pmwin.c \ | |||
$(PMDIR)/pm_win/pmwinmm.c | |||
PMOBJ = $(PMSRC:.c=.o) | |||
HEADERS = g_all_guis.h m_imp.h g_canvas.h m_pd.h s_stuff.h \ | |||
$(wildcard ../portaudio/common/*.h) s_audio_paring.h | |||
SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \ | |||
g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c g_clone.c \ | |||
g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ | |||
g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \ | |||
m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \ | |||
m_conf.c m_glob.c m_sched.c \ | |||
s_main.c s_inter.c s_file.c s_print.c \ | |||
s_loader.c s_path.c s_entry.c s_audio.c s_midi.c s_utf8.c \ | |||
d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \ | |||
d_math.c d_fft.c d_fft_fftsg.c d_array.c d_global.c \ | |||
d_delay.c d_resample.c d_soundfile.c \ | |||
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \ | |||
x_time.c x_acoustics.c x_net.c x_text.c x_gui.c x_list.c x_array.c \ | |||
x_scalar.c x_vexp.c x_vexp_if.c x_vexp_fun.c | |||
SRSRC = u_pdsend.c u_pdreceive.c | |||
OBJ = $(SRC:.c=.o) | |||
SROBJ = $(SRSRC:.c=.o) | |||
PAOBJ = $(PASRC:.c=.o) | |||
ASIOOBJ = $(ASIOSRC:.cpp=.o) | |||
#VOBJ = $(VSRC:.c=.o) | |||
OBJC = $(OBJ) $(PAOBJ) $(ASIOOBJ) $(PMOBJ) | |||
# get version from m_pd.h to use in doc/1.manual/1.introduction.txt | |||
PD_MAJOR_VERSION := $(shell grep PD_MAJOR_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_MAJOR_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_MINOR_VERSION := $(shell grep PD_MINOR_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_MINOR_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_BUGFIX_VERSION := $(shell grep PD_BUGFIX_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_BUGFIX_VERSION *\([0-9]*\).*|\1|' ) | |||
PD_TEST_VERSION := $(shell grep PD_TEST_VERSION m_pd.h | \ | |||
sed 's|^.define *PD_TEST_VERSION *"\(.*\)".*|\1|' ) | |||
PD_VERSION := $(PD_MAJOR_VERSION).$(PD_MINOR_VERSION).$(PD_BUGFIX_VERSION) | |||
ifneq ($(PD_TEST_VERSION),) | |||
PD_VERSION := $(PD_VERSION)-$(PD_TEST_VERSION) | |||
endif | |||
# | |||
# ------------------ targets ------------------------------------ | |||
# | |||
.PHONY: all install clean testbin | |||
all: $(PDDLL) $(PDEXEC) $(PDSEND) $(PDRECEIVE) $(PDCOM) | |||
$(OBJ) : %.o : %.c | |||
$(CC) $(CFLAGS) $(GFLAGS) $(INCLUDE) -c -o $*.o $*.c | |||
$(GOBJ) : %.o : %.c | |||
$(CC) $(CFLAGS) $(GFLAGS) $(GINCLUDE) -c -o $*.o $*.c | |||
$(SROBJ) : %.o : %.c | |||
$(CC) $(CFLAGS) $(GFLAGS) $(INCLUDE) -c -o $*.o $*.c | |||
$(PAOBJ) : %.o : %.c | |||
$(CC) $(CFLAGS) $(GFLAGS) $(INCPA) -c -o $*.o $*.c | |||
$(ASIOOBJ) : %.o : %.cpp | |||
$(CXX) $(CFLAGS) $(INCPA) -c -o $*.o $*.cpp | |||
$(PMOBJ) : %.o : %.c | |||
$(CC) $(CFLAGS) $(GFLAGS) $(PMINCLUDE) -c -o $*.o $*.c | |||
$(VOBJ) : %.o : %.c | |||
$(CC) $(CFLAGS) $(GFLAGS) $(INCLUDE) -c -o $*.o $*.c | |||
$(PDSEND): u_pdsend.o | |||
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PDSEND) u_pdsend.o $(LIBS) | |||
$(STRIP) $(PDSEND) | |||
$(PDRECEIVE): u_pdreceive.o | |||
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PDRECEIVE) u_pdreceive.o $(LIBS) | |||
$(STRIP) $(PDRECEIVE) | |||
$(PDEXEC): s_entry.o pd.res | |||
$(CXX) $(LDFLAGS) -mwindows -o $(PDEXEC) s_entry.o pd.res $(LIBS) pd.a | |||
$(STRIP) -s $(PDEXEC) | |||
$(PDCOM): s_entry.o | |||
$(CXX) $(LDFLAGS) -o $(PDCOM) s_entry.o $(LIBS) pd.a | |||
$(STRIP) -s $(PDCOM) | |||
$(PDDLL): $(OBJC) | |||
$(CXX) -shared $(LDFLAGS) -o $(PDDLL) $(OBJC) $(LIBS) \ | |||
-Wl,--export-all-symbols -Wl,--out-implib=pd.a; | |||
$(STRIP) $(PDDLL) | |||
pd.res: pd.rc | |||
$(WINDRES) pd.rc -O coff -o pd.res | |||
../bin/pdstatic.exe: $(OBJC) | |||
$(CXX) -static \ | |||
$(LDFLAGS) -o ../bin/pdstatic.exe $(OBJC) \ | |||
$(LIBS) -lole32 -static-libgcc -static-libstdc++ | |||
$(STRIP) -s ../bin/pdstatic.exe | |||
#vstschedlib.dll: $(VOBJ) | |||
# $(DLLWRAP) --export-all-symbols --output-def vst.def \ | |||
# --output-lib=vst.a --dllname=vstschedlib.dll s_audio_vst.o pd.a $(LIBS) | |||
externs: | |||
make -C ../extra all | |||
# kludge to put stuff into the pd/bin dir for testing | |||
testbin: $(PDEXEC) $(PDDLL) $(PDCOM) | |||
echo "Copying files to $(BIN_DIR)" | |||
install -d $(BIN_DIR) | |||
install -p $(PDDLL) $(BIN_DIR) | |||
install -p pd.ico $(BIN_DIR) | |||
install -p $(PDCOM) $(BIN_DIR) | |||
install -p $(PDEXEC) $(BIN_DIR) | |||
ABOUT_FILE=$(DESTDIR)$(pddocdir)/1.manual/1.introduction.txt | |||
install: all | |||
# locales | |||
# make libpddir=$(libpddir) -C ../po install | |||
# install extra stuff | |||
# make libpddir=$(libpddir) -C ../extra install | |||
# the real install | |||
install -d $(DESTDIR)$(bindir) | |||
install -p ../tcl/*.tcl $(DESTDIR)$(bindir)/ | |||
install -p $(PDEXEC) $(DESTDIR)$(bindir)/$(PDEXEC) | |||
install -p $(PDCOM) $(DESTDIR)$(bindir)/$(PDCOM) | |||
install -p pd.dll $(DESTDIR)$(bindir)/pd.dll | |||
install -p pd.ico $(DESTDIR)$(bindir)/pd.ico | |||
install -p $(PDSEND) $(DESTDIR)$(bindir)/$(PDSEND) | |||
install -p $(PDRECEIVE) $(DESTDIR)$(bindir)/$(PDRECEIVE) | |||
for dir in $(shell ls -1 ../doc | grep -v CVS); do \ | |||
echo "installing $$dir"; \ | |||
install -d $(DESTDIR)$(pddocdir)/$$dir ; \ | |||
install -p ../doc/$$dir/*.* $(DESTDIR)$(pddocdir)/$$dir ; \ | |||
done | |||
for dir in $(shell ls -1 ../doc/7.stuff | grep -v CVS); do \ | |||
echo "installing 7.stuff/$$dir"; \ | |||
install -d $(DESTDIR)$(pddocdir)/7.stuff/$$dir ; \ | |||
install -p ../doc/7.stuff/$$dir/*.* $(DESTDIR)$(pddocdir)/7.stuff/$$dir ; \ | |||
done | |||
mv $(ABOUT_FILE) $(ABOUT_FILE).tmp | |||
cat $(ABOUT_FILE).tmp | sed 's|PD_VERSION|Pd version $(PD_VERSION)|' \ | |||
> $(ABOUT_FILE) | |||
rm $(ABOUT_FILE).tmp | |||
install -d $(DESTDIR)$(libpddir)/extra | |||
# install -p $(pd_src)/extra/*/*.dll $(DESTDIR)$(libpddir)/extra | |||
install -p $(pd_src)/extra/*.pd $(DESTDIR)$(libpddir)/extra | |||
install -d $(DESTDIR)$(pddocdir)/5.reference | |||
install -p ../extra/*/*.pd $(DESTDIR)$(pddocdir)/5.reference | |||
install -p ../extra/*-help.pd $(DESTDIR)$(pddocdir)/5.reference | |||
install -d $(DESTDIR)$(includedir) | |||
install -p m_pd.h $(DESTDIR)$(includedir)/m_pd.h | |||
install -p s_stuff.h $(DESTDIR)$(includedir)/s_stuff.h | |||
@echo "Pd install succeeded." | |||
clean: | |||
-rm -f -- $(BIN_DIR)/*.* | |||
-rm -f -- *.o *.a *.def | |||
-rm -f -- pd*.exe pd*.dll $(PDCOM) | |||
-rm -f -- $(OBJ) $(GOBJ) $(SROBJ) $(PAOBJ) $(ASIOOBJ) $(PMOBJ) | |||
-rm -f -- $(pd_src)/extra/*/*.dll $(pd_src)/extra/*/*.o | |||
-rm -f makefile.dependencies | |||
distclean: clean | |||
rm -rf -- config.cache config.log config.status makefile tags \ | |||
autom4te-*.cache | |||
tags: $(SRC) $(GSRC); ctags *.[ch] | |||
depend: makefile.dependencies | |||
makefile.dependencies: $(SRC) $(PASRC) $(HEADERS) | |||
$(CC) $(INCLUDE) $(INCPA) $(CFLAGS) -M $(SRC) $(PASRC) $(HEADERS) \ | |||
> makefile.dependencies | |||
uninstall: | |||
-rm $(prefix)/bin/pd*.exe | |||
-rm $(prefix)/bin/pd*.com | |||
-rm $(prefix)/bin/pd*.dll | |||
-rm $(prefix)/bin/*.tcl | |||
test_locations: | |||
@echo "PD_VERSION: $(PD_VERSION)" | |||
@echo "PACKAGE_VERSION: $(PACKAGE_VERSION)" | |||
@echo "CWD $(CWD)" | |||
@echo "DESTDIR $(DESTDIR)" | |||
@echo "PREFIX $(prefix)" | |||
@echo "BINDIR $(bindir)" | |||
@echo "LIBDIR $(libdir)" | |||
@echo "OBJECTSDIR $(objectsdir)" | |||
@echo "PDDOCDIR $(pddocdir)" | |||
@echo "LIBPDDIR $(libpddir)" | |||
@echo "LIBPDBINDIR $(libpdbindir)" | |||
@echo "HELPDIR $(helpdir)" | |||
@echo "MANUALSDIR $(manualsdir)" | |||
@echo "EXAMPLESDIR $(examplesdir)" | |||
include makefile.dependencies |
@@ -0,0 +1,220 @@ | |||
# Makefile for PD using Microsoft Visual C/C++ (MSVC) -- note defines | |||
# which will have to be adapted to whichever specific version of MSVC you | |||
# have lying around. | |||
MSCC = cl | |||
MSLN = link | |||
COPY = copy | |||
DELETE = del | |||
VCSDK = "C:/Program Files/Microsoft SDKs/Windows/v6.0A" | |||
VC9 = "C:/Program Files/Microsoft Visual Studio 9.0/VC" | |||
WISH = wish85.exe | |||
EXTRA_LIBPATH= | |||
EXTRA_INCLUDES= | |||
## the following adds the search paths for compiler/linker | |||
## if the build system hasn't been properly setup by calling | |||
## the 'vcvarsall.bat' (MSVC) resp. 'SetEnv.bat' (MSSDK) scripts. | |||
## the logic checks whether some variables are set/unset | |||
## the code is a bit convoluted because we want it to work | |||
## with both 'GNU make' and 'nmake' | |||
## see https://stackoverflow.com/a/30906085/1169096 | |||
# \ | |||
!ifndef 0 # \ | |||
# nmake code here \ | |||
!IFNDEF VCINSTALLDIR # \ | |||
VCINSTALLDIR = $(VC9) # \ | |||
EXTRA_INCLUDES = /I$(VC9)/Include $(EXTRA_INCLUDES) # \ | |||
EXTRA_LIBPATH = /LIBPATH:$(VC9)/lib $(EXTRA_LIBPATH) # \ | |||
!ENDIF # \ | |||
!IFNDEF WINDOWSSDKDIR # \ | |||
WINDOWSSDKDIR = $(VCSDK) # \ | |||
EXTRA_INCLUDES = /I$(VCSDK)/Include $(EXTRA_INCLUDES) # \ | |||
EXTRA_LIBPATH = /LIBPATH:$(VCSDK)/lib $(EXTRA_LIBPATH)# \ | |||
!ENDIF # \ | |||
!else | |||
# GNU make code here | |||
ifndef VCINSTALLDIR | |||
VCINSTALLDIR = $(VC9) | |||
EXTRA_INCLUDES += /I$(VC9)/Include | |||
EXTRA_LIBPATH += /LIBPATH:$(VC9)/lib | |||
endif | |||
ifndef WINDOWSSDKDIR | |||
WINDOWSSDKDIR = $(VCSDK) | |||
EXTRA_INCLUDES += /I$(VCSDK)/Include | |||
EXTRA_LIBPATH += /LIBPATH:$(VCSDK)/lib | |||
endif | |||
# \ | |||
!endif | |||
PDINCLUDE = /I./ $(EXTRA_INCLUDES) | |||
PDLIB = /NODEFAULTLIB:libcmt /NODEFAULTLIB:libcpmt /NODEFAULTLIB:oldnames \ | |||
/NODEFAULTLIB:libc /NODEFAULTLIB:uuid /NODEFAULTLIB:ole32 \ | |||
$(EXTRA_LIBPATH) \ | |||
kernel32.lib \ | |||
wsock32.lib winmm.lib \ | |||
advapi32.lib setupapi.lib \ | |||
../bin/pthreadVC.lib \ | |||
libcmt.lib oldnames.lib | |||
AFLAGS = /D__i386__ | |||
# MSW, NT: legacy defines of Pd | |||
# WIN32: portmidi, portaudio | |||
# WINDOWS: portaudio | |||
# _WINDOWS: unused! | |||
CFLAGS = /nologo \ | |||
/W3 /Ox $(AFLAGS) \ | |||
/DMSW /DNT /DWIN32 /DWINDOWS /D_WINDOWS \ | |||
/DWISH=\"$(WISH)\" \ | |||
/DPD /DPD_INTERNAL \ | |||
/DUSEAPI_MMIO /DUSEAPI_PORTAUDIO \ | |||
/DPA_LITTLE_ENDIAN /DPA19 \ | |||
/D_CRT_SECURE_NO_WARNINGS | |||
LFLAGS = /nologo | |||
SYSSRC = s_audio_pa.c s_audio_paring.c \ | |||
s_audio_mmio.c s_midi_pm.c | |||
SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \ | |||
g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c g_clone.c \ | |||
g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ | |||
g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \ | |||
m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \ | |||
m_conf.c m_glob.c m_sched.c \ | |||
s_main.c s_inter.c s_file.c s_print.c \ | |||
s_loader.c s_path.c s_entry.c s_audio.c s_midi.c s_utf8.c \ | |||
d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \ | |||
d_math.c d_fft.c d_fft_fftsg.c d_array.c d_global.c \ | |||
d_delay.c d_resample.c d_soundfile.c \ | |||
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \ | |||
x_time.c x_acoustics.c x_net.c x_text.c x_gui.c x_list.c x_array.c \ | |||
x_scalar.c x_vexp.c x_vexp_if.c x_vexp_fun.c \ | |||
$(SYSSRC) | |||
PADIR = ../portaudio/portaudio | |||
INCPA = -I$(PADIR)/include -I$(PADIR)/src/common -I$(PADIR)/src/os/win | |||
PASRC = $(PADIR)/src | |||
PAOBJ = pa_stream.obj pa_trace.obj pa_process.obj \ | |||
pa_front.obj pa_dither.obj pa_cpuload.obj pa_converters.obj \ | |||
pa_allocation.obj pa_ringbuffer.obj \ | |||
pa_win_hostapis.obj pa_win_util.obj pa_win_waveformat.obj \ | |||
pa_win_wmme.obj | |||
# pa_win_wdmks.obj | |||
PMDIR = ../portmidi/portmidi | |||
INCPM = -I$(PMDIR)/pm_common -I$(PMDIR)/pm_win -I$(PMDIR)/porttime -DNEWBUFFER | |||
SRCPM = $(PADIR)/pm_common/portmidi.c \ | |||
$(PMDIR)/pm_common/pmutil.c \ | |||
$(PMDIR)/porttime/porttime.c \ | |||
$(PMDIR)/porttime/ptwinmm.c \ | |||
$(PMDIR)/pm_win/pmwin.c \ | |||
$(PMDIR)/pm_win/pmwinmm.c | |||
PMOBJ = portmidi.obj pmutil.obj porttime.obj ptwinmm.obj pmwin.obj pmwinmm.obj | |||
OBJC = $(SRC:.c=.obj) $(PAOBJ) $(PMOBJ) | |||
GSRC = t_main.c t_tkcmd.c | |||
GOBJ = $(GSRC:.c=.obj) | |||
ALLCF = $(CFLAGS) $(PDINCLUDE) $(INCPA) $(INCPM) | |||
.SUFFIXES: .obj | |||
.c.obj: | |||
$(MSCC) /c $(ALLCF) /Tc$*.c | |||
all: pd ../bin/pdsend.exe ../bin/pdreceive.exe | |||
.PHONY: pd | |||
pd: ../bin/pd.exe ../bin/pd.com | |||
../bin/pd.exe: s_entry.obj ../bin/pd.lib | |||
$(MSLN) $(LFLAGS) /OUT:../bin/pd.exe /INCREMENTAL:NO s_entry.obj \ | |||
../bin/pd.lib $(PDLIB) | |||
../bin/pd.dll ../bin/pd.lib: $(OBJC) | |||
$(MSLN) /DLL /OUT:../bin/pd.dll /EXPORT:sys_main $(LFLAGS) $(OBJC) \ | |||
$(PDLIB) | |||
../bin/pdsend.exe: u_pdsend.obj | |||
$(MSLN) $(LFLAGS) /out:../bin/pdsend.exe /INCREMENTAL:NO \ | |||
u_pdsend.obj $(PDLIB) | |||
../bin/pdreceive.exe: u_pdreceive.obj | |||
$(MSLN) $(LFLAGS) /out:../bin/pdreceive.exe /INCREMENTAL:NO \ | |||
u_pdreceive.obj $(PDLIB) | |||
../bin/pd.com: s_entry_com.obj ../bin/pd.lib | |||
$(MSLN) $(LFLAGS) /out:../bin/pd.com /INCREMENTAL:NO s_entry_com.obj \ | |||
../bin/pd.lib $(PDLIB) | |||
s_entry_com.obj: s_entry.c | |||
$(COPY) s_entry.c s_entry_com.c | |||
$(MSCC) /c -DCOMMANDVERSION s_entry_com.c | |||
$(DELETE) s_entry_com.c | |||
PAAPI = -DPA_USE_WMME | |||
PACF= $(PAAPI) $(ALLCF) | |||
# explicit rules to compile portaudio sources: | |||
pa_stream.obj: $(PASRC)/common/pa_stream.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_stream.c | |||
pa_trace.obj: $(PASRC)/common/pa_trace.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_trace.c | |||
pa_process.obj: $(PASRC)/common/pa_process.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_process.c | |||
pa_front.obj: $(PASRC)/common/pa_front.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_front.c | |||
pa_dither.obj: $(PASRC)/common/pa_dither.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_dither.c | |||
pa_cpuload.obj: $(PASRC)/common/pa_cpuload.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_cpuload.c | |||
pa_converters.obj: $(PASRC)/common/pa_converters.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_converters.c | |||
pa_allocation.obj: $(PASRC)/common/pa_allocation.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_allocation.c | |||
pa_ringbuffer.obj: $(PASRC)/common/pa_ringbuffer.c | |||
$(MSCC) /c $(PACF) $(PASRC)/common/pa_ringbuffer.c | |||
pa_win_hostapis.obj: $(PASRC)/os/win/pa_win_hostapis.c | |||
$(MSCC) /c $(PACF) $(PASRC)/os/win/pa_win_hostapis.c | |||
pa_win_util.obj: $(PASRC)/os/win/pa_win_util.c | |||
$(MSCC) /c $(PACF) $(PASRC)/os/win/pa_win_util.c | |||
pa_win_waveformat.obj: $(PASRC)/os/win/pa_win_waveformat.c | |||
$(MSCC) /c $(PACF) $(PASRC)/os/win/pa_win_waveformat.c | |||
pa_win_coinitialize.obj: $(PASRC)/os/win/pa_win_coinitialize.c | |||
$(MSCC) /c $(PACF) $(PASRC)/os/win/pa_win_coinitialize.c | |||
pa_win_wmme.obj: $(PASRC)/hostapi/wmme/pa_win_wmme.c | |||
$(MSCC) /c $(PACF) $(PASRC)/hostapi/wmme/pa_win_wmme.c | |||
pa_win_wdmks.obj: $(PADIR)/a_win_wdmks/pa_win_wdmks.c | |||
$(MSCC) /c $(PACF) \ | |||
-DWINVER=0x400 -DKSAUDIO_SPEAKER_DIRECTOUT \ | |||
$(PADIR)/pa_win_wdmks/pa_win_wdmks.c | |||
pa_asio.obj: $(PASRC)/hostapi/asio/pa_asio.cpp | |||
$(MSCC) /c $(PACF) $(PASRC)/hostapi/asio/pa_asio.cpp | |||
portmidi.obj: $(PMDIR)/pm_common/portmidi.c | |||
$(MSCC) /c $(PACF) $(PMDIR)/pm_common/portmidi.c | |||
pmutil.obj: $(PMDIR)/pm_common/pmutil.c | |||
$(MSCC) /c $(PACF) $(PMDIR)/pm_common/pmutil.c | |||
pmwin.obj: $(PMDIR)/pm_win/pmwin.c | |||
$(MSCC) /c $(PACF) $(PMDIR)/pm_win/pmwin.c | |||
pmwinmm.obj: $(PMDIR)/pm_win/pmwinmm.c | |||
$(MSCC) /c $(PACF) $(PMDIR)/pm_win/pmwinmm.c | |||
porttime.obj: $(PMDIR)/porttime/porttime.c | |||
$(MSCC) /c $(PACF) $(PMDIR)/porttime/porttime.c | |||
ptwinmm.obj: $(PMDIR)/porttime/ptwinmm.c | |||
$(MSCC) /c $(PACF) $(PMDIR)/porttime/ptwinmm.c | |||
# the following should also clean up "bin" but it doesn't because "bin" holds | |||
# precious stuff from elsewhere (luckily, our stuff matches 'pd*') | |||
clean: | |||
$(DELETE) *.obj | |||
$(DELETE) ../bin/pd*.* |
@@ -0,0 +1,142 @@ | |||
---------------- dolist -------------------- | |||
GUIs: slider, etc "clip (pre-0.46) " (on for old ones, off by default) | |||
toggle to get "track value (pre-0.46)" | |||
x_text.c: | |||
text dimension setting (message or creation arg - how to do it in structs?) | |||
copying ala text_define_topointer | |||
"open" and "save as" messages to open text window | |||
how to integrate message boxes !? | |||
x_array.c: | |||
allow for lying about x and y labels | |||
no-mouse, quantize and clip flags for plotting/mousing | |||
save ticks, labels, other flags (and add dialog to set them) | |||
array y range to reflect y increment sign (so no 1 to -1 range) | |||
array search and array sort objects | |||
maybe: array segment, array spline, array sinesum, etc? or array gen? or | |||
array forward (forwards message to defining array) | |||
Is there a way to generate a pointer to an anonymous array? (do we need that?) | |||
OS specific: | |||
linux: | |||
rpm packages; BSD versions (set up VMs for testing) | |||
windows: | |||
put call to PA_Terminate back in where appropriate (first test on windows) | |||
"-audiodev" with no args in registry can't start up? | |||
mmio out of portaudio but consider adding wdmks | |||
mac: | |||
check if window titles wrong on Macintosh | |||
clicking on windows seems sometimes not to open them | |||
compile for jack on OSX by default (32 bit version at least). | |||
turn on paMacCore_ChangeDeviceParameters for mac (pa_mac_core.h) | |||
problems: | |||
fix behavior when dragging object outside screen (stop the evil auto-scrolls) | |||
pd~ "start" followed by messages gives race condition because of "fromgui" biz | |||
pd~ deadlock protection | |||
find asdf$1 (e.g.) doesn't work | |||
objects on GOP don't erase if you edit the GOP while they're showing | |||
add -stack option to make 'regular' stack larger | |||
menu item to save help patches to directory | |||
look again at array vis/invis conundrum, g_template.c | |||
floor, ciel functions in expr misdeclared | |||
graph names don't appear until graph moved? (invis/vis on new array/rename) | |||
don't filter locked click() through getrect | |||
patcher inlets don't deal with scalars (zbug.pd) | |||
read xx.txt in "bad" gives warnings | |||
Krzysztof's qlist_next reentrancy bug | |||
don't draw in/outlets on gui objects in graph-on-parent | |||
get rid of messages causing renaming; try to prevent patches closing themselves. | |||
scofo reports error on reading score1.txt | |||
better error message for adc~ / dac~ reblocking | |||
fix limitations in number of array elements that can be graphed | |||
more demonstration patches: | |||
vibrato using variable delay | |||
real-time spectrum grapher | |||
document ||, |, etc, better | |||
features: | |||
-nomidibuf flag (Nicola Pandini on pd list Aug 8 2013) | |||
add way to query readsf~ for fill pointer (sf feature request 3598776) | |||
'route' object to sprout inlet if no args (like sel) | |||
optionally suppress leading "." directories and files on "open" | |||
"installation mode": flag or messages to suppress menus&accelerators, | |||
and invisibilize Pd window | |||
sigmund~: sort by pitch; pitch estimate to include pitch height; message | |||
to lie about previous track output | |||
expr to parse exponential notation | |||
mem alignment for SSE | |||
replace gatom_escapit with a quoting mechanism (handle '[', spaces, etc.) | |||
poly inlet to turn stealing on/off, plus mode to handle note-with-duration | |||
integrate video into tilde objects | |||
think of a way to embed abstractions in a patch (zlib?) | |||
delete-in-rectangle message to Pds | |||
put serial object in main dist (see rat@telecoma, Apr. 25; winfried May 22) | |||
see x_list.c for more "list" object ideas | |||
open64() for linux (if 32 bits, close soundfile and open64 it) | |||
paths: | |||
fix declare to update current patch when changed | |||
open_via_path call in d_soundfile.c isn't threadsafe | |||
open/save panel to take messages to set extent list | |||
new open_via_path to take list of extents | |||
editing: | |||
control-enter to deselect an object? | |||
pasting should look at current mouse location | |||
clickless connection (hit 'c' key? see Bouchard paper) | |||
tab to jump to a connected object (first one?) (shift-tab to back up?) | |||
arrow keys to shift connections left and right | |||
menu item to connect selected objects | |||
highlight connections (and I/Os) on mouse motion | |||
select line and hit "insert" to interpolate an object | |||
option-drag an outlet to make a new, connected object | |||
make a way to make multiple connections | |||
"fix width" menu item | |||
close-subwindows menu item | |||
canvas zooming (use tcl/tk canvas scale command?) | |||
data: | |||
add -x [-n?] flag to drawnumbers | |||
flag to disable edits for arrays | |||
make a 2-pass process for finding hot spot closest to any given click | |||
hooks for table mousing, other changes (scalars?) | |||
data to save as succession of "list" messages that textfile can store, etc. | |||
data copy/paste doesn't check templates aren't changed | |||
pointer == and select equivalents | |||
cursor to show (x, y) location and/or what parameter is being set to what | |||
improve typing at drawnumbers | |||
append doesn't do symbols yet. | |||
non-clickable arrays (plus arrays that respond more easily than default) | |||
set -any, get -any | |||
build out scalar object - naming; "scalar set/get" objects | |||
pointer methods to search and delete | |||
optimize by pre-fetching field name offsets in accessor objects | |||
double-click on drawtext in scalar to create editor window | |||
more features: | |||
signal inlets to sense signals; fix +~ etc, vcf~, biquad~, other filters | |||
message dialog not to disappear | |||
show results of opening MIDI on dialog | |||
new: abs~, nexttick~, extend threshold~ and snapshot~ (vthreshold~ etc) | |||
netsend separate thread | |||
in glist_delete, consider why this can't be just "vis 0" -- why do we need it? | |||
closebang and initbang | |||
put in something for tilde order forcing | |||
extensible "toolbar" so people can add external GUI objects | |||
number boxes to darken for typing and/or received messages | |||
new message box look | |||
dialog to give values of $1, ... for the canvas | |||
bang at end of line~, tabwrite~, etc. | |||
should sys_bail kill all "threads" on the way out? | |||
allow backslashes (or else really disallow them) | |||
icon & desktop integration | |||
tools (reassigns meaning of primary click) | |||
code style improvements: | |||
-Wno-unused to -Wno-unused-paramter and clean up unused automatic variables | |||
rewrite t_getbytes properly (m_newmemory.c in pd/attic) | |||
obj_new should do a longjmp on out-of-memory |
@@ -0,0 +1,25 @@ | |||
id ICON "pd.ico" | |||
1 VERSIONINFO | |||
FILEVERSION 0,48,1,0 | |||
PRODUCTVERSION 0,48,1,0 | |||
BEGIN | |||
BLOCK "StringFileInfo" | |||
BEGIN | |||
BLOCK "040904E4" | |||
BEGIN | |||
VALUE "CompanyName", "puredata.info" | |||
VALUE "FileDescription", "Pure Data Application" | |||
VALUE "FileVersion", "0.48-1" | |||
VALUE "InternalName", "pd.exe" | |||
VALUE "LegalCopyright", "Miller Puckette, et al." | |||
VALUE "OriginalFilename", "pd.exe" | |||
VALUE "ProductName", "Pure Data" | |||
VALUE "ProductVersion", "0.48-1" | |||
END | |||
END | |||
BLOCK "VarFileInfo" | |||
BEGIN | |||
VALUE "Translation", 0x409, 1200 | |||
END | |||
END |
@@ -0,0 +1,973 @@ | |||
/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler, | |||
* Winfried Ritsch, Karl MacMillan, and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* this file inputs and outputs audio using the ALSA API available on linux. */ | |||
/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */ | |||
/* support for ALSA MMAP noninterleaved by Winfried Ritsch, IEM */ | |||
#include <alsa/asoundlib.h> | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/types.h> | |||
#include <sys/time.h> | |||
#include <sys/stat.h> | |||
#include <sys/ioctl.h> | |||
#include <fcntl.h> | |||
#include <sched.h> | |||
#include <sys/mman.h> | |||
#include "s_audio_alsa.h" | |||
#include <endian.h> | |||
/* Defines */ | |||
#define DEBUG(x) x | |||
#define DEBUG2(x) {x;} | |||
/* needed for alsa 0.9 compatibility: */ | |||
#if (SND_LIB_MAJOR < 1) | |||
#define ALSAAPI9 | |||
#endif | |||
static void alsa_checkiosync( void); | |||
static void alsa_numbertoname(int iodev, char *devname, int nchar); | |||
static int alsa_jittermax; | |||
#define ALSA_DEFJITTERMAX 3 | |||
/* don't assume we can turn all 31 bits when doing float-to-fix; | |||
otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */ | |||
#define FMAX 0x7ffff000 | |||
#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x)) | |||
static char *alsa_snd_buf; | |||
static int alsa_snd_bufsize; | |||
static int alsa_buf_samps; | |||
static snd_pcm_status_t *alsa_status; | |||
static int alsa_usemmap; | |||
t_alsa_dev alsa_indev[ALSA_MAXDEV]; | |||
t_alsa_dev alsa_outdev[ALSA_MAXDEV]; | |||
int alsa_nindev; | |||
int alsa_noutdev; | |||
/* #define DEBUG_ALSA_XFER */ | |||
#ifdef DEBUG_ALSA_XFER | |||
static int xferno = 0; | |||
static int callno = 0; | |||
#endif | |||
/* report an error condition if an error was flagged in the argument "err". | |||
"fn" is 0 for input, 1 for output, otherwise N/A. "why" indicates where | |||
in the code the error was hit. */ | |||
static void check_error(int err, int fn, const char *why) | |||
{ | |||
if (err < 0) | |||
post("ALSA %serror (%s): %s", | |||
(fn == 1? "output " : (fn == 0 ? "input ": "")), | |||
why, snd_strerror(err)); | |||
} | |||
/* figure out, when opening ALSA device, whether we should use the code in | |||
this file or defer to Winfried Ritch's code to do mmaped transfers (handled | |||
in s_audio_alsamm.c). */ | |||
static int alsaio_canmmap(t_alsa_dev *dev) | |||
{ | |||
snd_pcm_hw_params_t *hw_params; | |||
int err1, err2; | |||
snd_pcm_hw_params_alloca(&hw_params); | |||
err1 = snd_pcm_hw_params_any(dev->a_handle, hw_params); | |||
if (err1 < 0) { | |||
check_error(err1, -1, "snd_pcm_hw_params_any"); | |||
return (0); | |||
} | |||
err1 = snd_pcm_hw_params_set_access(dev->a_handle, | |||
hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); | |||
if (err1 < 0) | |||
{ | |||
err2 = snd_pcm_hw_params_set_access(dev->a_handle, | |||
hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); | |||
} | |||
else err2 = -1; | |||
#if 0 | |||
post("err 1 %d (%s), err2 %d (%s)", err1, snd_strerror(err1), | |||
err2, snd_strerror(err2)); | |||
#endif | |||
return ((err1 < 0) && (err2 >= 0)); | |||
} | |||
/* set up an input or output device. Return 0 on success, -1 on failure. */ | |||
static int alsaio_setup(t_alsa_dev *dev, int out, int *channels, int *rate, | |||
int nfrags, int frag_size) | |||
{ | |||
int bufsizeforthis, err; | |||
snd_pcm_hw_params_t* hw_params; | |||
snd_pcm_sw_params_t* sw_params; | |||
unsigned int tmp_uint; | |||
snd_pcm_uframes_t tmp_snd_pcm_uframes; | |||
snd_pcm_hw_params_alloca(&hw_params); | |||
snd_pcm_sw_params_alloca(&sw_params); | |||
if (sys_verbose) | |||
post((out ? "configuring sound output..." : | |||
"configuring sound input...")); | |||
/* set hardware parameters... */ | |||
/* get the default params */ | |||
err = snd_pcm_hw_params_any(dev->a_handle, hw_params); | |||
check_error(err, out, "snd_pcm_hw_params_any"); | |||
/* try to set interleaved access */ | |||
err = snd_pcm_hw_params_set_access(dev->a_handle, | |||
hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); | |||
if (err < 0) | |||
return (-1); | |||
check_error(err, out, "snd_pcm_hw_params_set_access"); | |||
#if 0 /* enable this to print out which formats are available */ | |||
{ | |||
int i; | |||
for (i = 0; i <= SND_PCM_FORMAT_LAST; i++) | |||
fprintf(stderr, "%d -> %d\n", | |||
i, snd_pcm_hw_params_test_format(dev->a_handle, hw_params, i)); | |||
} | |||
#endif | |||
/* Try to set 32 bit format first */ | |||
err = snd_pcm_hw_params_set_format(dev->a_handle, | |||
hw_params, SND_PCM_FORMAT_S32); | |||
if (err < 0) | |||
{ | |||
err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params, | |||
SND_PCM_FORMAT_S24_3LE); | |||
if (err < 0) | |||
{ | |||
err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params, | |||
SND_PCM_FORMAT_S16); | |||
check_error(err, out, "_pcm_hw_params_set_format"); | |||
dev->a_sampwidth = 2; | |||
} | |||
else dev->a_sampwidth = 3; | |||
} | |||
else dev->a_sampwidth = 4; | |||
if (sys_verbose) | |||
post("Sample width set to %d bytes", dev->a_sampwidth); | |||
/* set the subformat */ | |||
err = snd_pcm_hw_params_set_subformat(dev->a_handle, | |||
hw_params, SND_PCM_SUBFORMAT_STD); | |||
check_error(err, out, "snd_pcm_hw_params_set_subformat"); | |||
/* set the number of channels */ | |||
tmp_uint = *channels; | |||
err = snd_pcm_hw_params_set_channels_near(dev->a_handle, | |||
hw_params, &tmp_uint); | |||
check_error(err, out, "snd_pcm_hw_params_set_channels"); | |||
if (tmp_uint != (unsigned)*channels) | |||
post("ALSA: set %s channels to %d", (out?"output":"input"), tmp_uint); | |||
*channels = tmp_uint; | |||
dev->a_channels = *channels; | |||
/* set the sampling rate */ | |||
err = snd_pcm_hw_params_set_rate_near(dev->a_handle, hw_params, | |||
(unsigned int *)rate, 0); | |||
check_error(err, out, "snd_pcm_hw_params_set_rate_min"); | |||
#if 0 | |||
err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); | |||
post("input sample rate %d", err); | |||
#endif | |||
/* post("frag size %d, nfrags %d", frag_size, nfrags); */ | |||
/* set "period size" */ | |||
tmp_snd_pcm_uframes = frag_size; | |||
err = snd_pcm_hw_params_set_period_size_near(dev->a_handle, | |||
hw_params, &tmp_snd_pcm_uframes, 0); | |||
check_error(err, out, "snd_pcm_hw_params_set_period_size_near"); | |||
/* set the buffer size */ | |||
tmp_snd_pcm_uframes = nfrags * frag_size; | |||
err = snd_pcm_hw_params_set_buffer_size_near(dev->a_handle, | |||
hw_params, &tmp_snd_pcm_uframes); | |||
check_error(err, out, "snd_pcm_hw_params_set_buffer_size_near"); | |||
err = snd_pcm_hw_params(dev->a_handle, hw_params); | |||
check_error(err, out, "snd_pcm_hw_params"); | |||
/* set up the buffer */ | |||
bufsizeforthis = DEFDACBLKSIZE * dev->a_sampwidth * *channels; | |||
if (alsa_snd_buf) | |||
{ | |||
if (alsa_snd_bufsize < bufsizeforthis) | |||
{ | |||
if (!(alsa_snd_buf = realloc(alsa_snd_buf, bufsizeforthis))) | |||
{ | |||
post("out of memory"); | |||
return (-1); | |||
} | |||
memset(alsa_snd_buf, 0, bufsizeforthis); | |||
alsa_snd_bufsize = bufsizeforthis; | |||
} | |||
} | |||
else | |||
{ | |||
if (!(alsa_snd_buf = (void *)malloc(bufsizeforthis))) | |||
{ | |||
post("out of memory"); | |||
return (-1); | |||
} | |||
memset(alsa_snd_buf, 0, bufsizeforthis); | |||
alsa_snd_bufsize = bufsizeforthis; | |||
} | |||
err = snd_pcm_sw_params_current(dev->a_handle, sw_params); | |||
if (err < 0) | |||
{ | |||
post("Unable to determine current swparams for %s: %s\n", | |||
(out ? "output" : "input"), snd_strerror(err)); | |||
return (-1); | |||
} | |||
err = snd_pcm_sw_params_set_stop_threshold(dev->a_handle, sw_params, | |||
0x7fffffff); | |||
if (err < 0) | |||
{ | |||
post("Unable to set start threshold mode for %s: %s\n", | |||
(out ? "output" : "input"), snd_strerror(err)); | |||
return (-1); | |||
} | |||
err = snd_pcm_sw_params_set_avail_min(dev->a_handle, sw_params, 4); | |||
if (err < 0) | |||
{ | |||
post("Unable to set avail min for %s: %s\n", | |||
(out ? "output" : "input"), snd_strerror(err)); | |||
return (-1); | |||
} | |||
err = snd_pcm_sw_params(dev->a_handle, sw_params); | |||
if (err < 0) | |||
{ | |||
post("Unable to set sw params for %s: %s\n", | |||
(out ? "output" : "input"), snd_strerror(err)); | |||
return (-1); | |||
} | |||
return (0); | |||
} | |||
/* return 0 on success */ | |||
int alsa_open_audio(int naudioindev, int *audioindev, int nchindev, | |||
int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, | |||
int *choutdev, int rate, int blocksize) | |||
{ | |||
int err, inchans = 0, outchans = 0, subunitdir; | |||
char devname[512]; | |||
snd_output_t* out; | |||
int frag_size = (blocksize ? blocksize : ALSA_DEFFRAGSIZE); | |||
int nfrags, i, iodev, dev2; | |||
int wantinchans, wantoutchans, device; | |||
nfrags = sys_schedadvance * (float)rate / (1e6 * frag_size); | |||
/* save our belief as to ALSA's buffer size for later */ | |||
alsa_buf_samps = nfrags * frag_size; | |||
alsa_nindev = alsa_noutdev = 0; | |||
alsa_jittermax = ALSA_DEFJITTERMAX; | |||
if (sys_verbose) | |||
post("audio buffer set to %d", (int)(0.001 * sys_schedadvance)); | |||
for (iodev = 0; iodev < naudioindev; iodev++) | |||
{ | |||
alsa_numbertoname(audioindev[iodev], devname, 512); | |||
err = snd_pcm_open(&alsa_indev[alsa_nindev].a_handle, devname, | |||
SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); | |||
check_error(err, 0, "snd_pcm_open"); | |||
if (err < 0) | |||
continue; | |||
alsa_indev[alsa_nindev].a_devno = audioindev[iodev]; | |||
snd_pcm_nonblock(alsa_indev[alsa_nindev].a_handle, 1); | |||
if (sys_verbose) | |||
post("opened input device name %s", devname); | |||
alsa_nindev++; | |||
} | |||
for (iodev = 0; iodev < naudiooutdev; iodev++) | |||
{ | |||
alsa_numbertoname(audiooutdev[iodev], devname, 512); | |||
err = snd_pcm_open(&alsa_outdev[alsa_noutdev].a_handle, devname, | |||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); | |||
check_error(err, 1, "snd_pcm_open"); | |||
if (err < 0) | |||
continue; | |||
alsa_outdev[alsa_noutdev].a_devno = audiooutdev[iodev]; | |||
snd_pcm_nonblock(alsa_outdev[alsa_noutdev].a_handle, 1); | |||
alsa_noutdev++; | |||
} | |||
if (!alsa_nindev && !alsa_noutdev) | |||
goto blewit; | |||
/* If all the open devices support mmap_noninterleaved, let's call | |||
Wini's code in s_audio_alsamm.c */ | |||
alsa_usemmap = 1; | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
if (!alsaio_canmmap(&alsa_indev[iodev])) | |||
alsa_usemmap = 0; | |||
for (iodev = 0; iodev < alsa_noutdev; iodev++) | |||
if (!alsaio_canmmap(&alsa_outdev[iodev])) | |||
alsa_usemmap = 0; | |||
if (alsa_usemmap) | |||
{ | |||
post("using mmap audio interface"); | |||
if (alsamm_open_audio(rate, blocksize)) | |||
goto blewit; | |||
else return (0); | |||
} | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
{ | |||
int channels = chindev[iodev]; | |||
if (alsaio_setup(&alsa_indev[iodev], 0, &channels, &rate, | |||
nfrags, frag_size) < 0) | |||
goto blewit; | |||
inchans += channels; | |||
} | |||
for (iodev = 0; iodev < alsa_noutdev; iodev++) | |||
{ | |||
int channels = choutdev[iodev]; | |||
if (alsaio_setup(&alsa_outdev[iodev], 1, &channels, &rate, | |||
nfrags, frag_size) < 0) | |||
goto blewit; | |||
outchans += channels; | |||
} | |||
if (!inchans && !outchans) | |||
goto blewit; | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
snd_pcm_prepare(alsa_indev[iodev].a_handle); | |||
for (iodev = 0; iodev < alsa_noutdev; iodev++) | |||
snd_pcm_prepare(alsa_outdev[iodev].a_handle); | |||
/* if duplex we can link the channels so they start together */ | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
for (dev2 = 0; dev2 < alsa_noutdev; dev2++) | |||
{ | |||
if (alsa_indev[iodev].a_devno == alsa_outdev[iodev].a_devno) | |||
{ | |||
snd_pcm_link(alsa_indev[iodev].a_handle, | |||
alsa_outdev[iodev].a_handle); | |||
} | |||
} | |||
/* allocate the status variables */ | |||
if (!alsa_status) | |||
{ | |||
err = snd_pcm_status_malloc(&alsa_status); | |||
check_error(err, -1, "snd_pcm_status_malloc"); | |||
} | |||
/* fill the buffer with silence and prime the output FIFOs. This | |||
should automatically start the output devices. */ | |||
memset(alsa_snd_buf, 0, alsa_snd_bufsize); | |||
if (outchans) | |||
{ | |||
i = (frag_size * nfrags)/DEFDACBLKSIZE + 1; | |||
while (i--) | |||
{ | |||
for (iodev = 0; iodev < alsa_noutdev; iodev++) | |||
snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, | |||
DEFDACBLKSIZE); | |||
} | |||
} | |||
if (inchans) | |||
{ | |||
/* some of the ADC devices might already have been started by | |||
starting the outputs above, but others might still need it. */ | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
if (snd_pcm_state(alsa_indev[iodev].a_handle) | |||
!= SND_PCM_STATE_RUNNING) | |||
if ((err = snd_pcm_start(alsa_indev[iodev].a_handle)) < 0) | |||
check_error(err, -1, "input start failed"); | |||
} | |||
return (0); | |||
blewit: | |||
STUFF->st_inchannels = 0; | |||
STUFF->st_outchannels = 0; | |||
alsa_close_audio(); | |||
return (1); | |||
} | |||
void alsa_close_audio(void) | |||
{ | |||
int err, iodev; | |||
if (alsa_usemmap) | |||
{ | |||
alsamm_close_audio(); | |||
return; | |||
} | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
{ | |||
err = snd_pcm_close(alsa_indev[iodev].a_handle); | |||
check_error(err, 0, "snd_pcm_close"); | |||
} | |||
for (iodev = 0; iodev < alsa_noutdev; iodev++) | |||
{ | |||
err = snd_pcm_close(alsa_outdev[iodev].a_handle); | |||
check_error(err, 1, "snd_pcm_close"); | |||
} | |||
alsa_nindev = alsa_noutdev = 0; | |||
} | |||
int alsa_send_dacs(void) | |||
{ | |||
static double timenow; | |||
double timelast; | |||
t_sample *fp, *fp1, *fp2; | |||
int i, j, k, err, iodev, result, ch, resync = 0;; | |||
int chansintogo, chansouttogo; | |||
unsigned int transfersize; | |||
if (alsa_usemmap) | |||
return (alsamm_send_dacs()); | |||
if (!alsa_nindev && !alsa_noutdev) | |||
return (SENDDACS_NO); | |||
chansintogo = STUFF->st_inchannels; | |||
chansouttogo = STUFF->st_outchannels; | |||
transfersize = DEFDACBLKSIZE; | |||
timelast = timenow; | |||
timenow = sys_getrealtime(); | |||
#ifdef DEBUG_ALSA_XFER | |||
if (timenow - timelast > 0.050) | |||
post("long wait between calls: %d", | |||
(int)(1000 * (timenow - timelast))), fflush(stderr); | |||
callno++; | |||
#endif | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
{ | |||
result = snd_pcm_state(alsa_indev[iodev].a_handle); | |||
if (result == SND_PCM_STATE_XRUN) | |||
{ | |||
int res2 = snd_pcm_start(alsa_indev[iodev].a_handle); | |||
fprintf(stderr, "restart alsa input\n"); | |||
if (res2 < 0) | |||
fprintf(stderr, "alsa xrun recovery apparently failed\n"); | |||
} | |||
snd_pcm_status(alsa_indev[iodev].a_handle, alsa_status); | |||
if (snd_pcm_status_get_avail(alsa_status) < transfersize) | |||
return (SENDDACS_NO); | |||
} | |||
for (iodev = 0; iodev < alsa_noutdev; iodev++) | |||
{ | |||
result = snd_pcm_state(alsa_outdev[iodev].a_handle); | |||
if (result == SND_PCM_STATE_XRUN) | |||
{ | |||
int res2 = snd_pcm_start(alsa_outdev[iodev].a_handle); | |||
fprintf(stderr, "restart alsa output\n"); | |||
if (res2 < 0) | |||
fprintf(stderr, "alsa xrun recovery apparently failed\n"); | |||
} | |||
snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status); | |||
if (snd_pcm_status_get_avail(alsa_status) < transfersize) | |||
return (SENDDACS_NO); | |||
} | |||
#ifdef DEBUG_ALSA_XFER | |||
post("xfer %d", transfersize); | |||
#endif | |||
/* do output */ | |||
for (iodev = 0, fp1 = STUFF->st_soundout, ch = 0; | |||
iodev < alsa_noutdev; iodev++) | |||
{ | |||
int thisdevchans = alsa_outdev[iodev].a_channels; | |||
int chans = (chansouttogo < thisdevchans ? chansouttogo : thisdevchans); | |||
chansouttogo -= chans; | |||
if (alsa_outdev[iodev].a_sampwidth == 4) | |||
{ | |||
for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) | |||
for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; | |||
j += thisdevchans, fp2++) | |||
{ | |||
float s1 = *fp2 * INT32_MAX; | |||
((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1); | |||
} | |||
for (; i < thisdevchans; i++, ch++) | |||
for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans) | |||
((t_alsa_sample32 *)alsa_snd_buf)[j] = 0; | |||
} | |||
else if (alsa_outdev[iodev].a_sampwidth == 3) | |||
{ | |||
for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) | |||
for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; | |||
j += thisdevchans, fp2++) | |||
{ | |||
int s = *fp2 * 8388352.; | |||
if (s > 8388351) | |||
s = 8388351; | |||
else if (s < -8388351) | |||
s = -8388351; | |||
#if BYTE_ORDER == LITTLE_ENDIAN | |||
((char *)(alsa_snd_buf))[3*j] = (s & 255); | |||
((char *)(alsa_snd_buf))[3*j+1] = ((s>>8) & 255); | |||
((char *)(alsa_snd_buf))[3*j+2] = ((s>>16) & 255); | |||
#else | |||
fprintf(stderr, "big endian 24-bit not supported"); | |||
#endif | |||
} | |||
for (; i < thisdevchans; i++, ch++) | |||
for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans) | |||
((char *)(alsa_snd_buf))[3*j] = | |||
((char *)(alsa_snd_buf))[3*j+1] = | |||
((char *)(alsa_snd_buf))[3*j+2] = 0; | |||
} | |||
else /* 16 bit samples */ | |||
{ | |||
for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) | |||
for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--; | |||
j += thisdevchans, fp2++) | |||
{ | |||
int s = *fp2 * 32767.; | |||
if (s > 32767) | |||
s = 32767; | |||
else if (s < -32767) | |||
s = -32767; | |||
((t_alsa_sample16 *)alsa_snd_buf)[j] = s; | |||
} | |||
for (; i < thisdevchans; i++, ch++) | |||
for (j = ch, k = DEFDACBLKSIZE; k--; j += thisdevchans) | |||
((t_alsa_sample16 *)alsa_snd_buf)[j] = 0; | |||
} | |||
result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, | |||
transfersize); | |||
if (result != (int)transfersize) | |||
{ | |||
#ifdef DEBUG_ALSA_XFER | |||
if (result >= 0 || errno == EAGAIN) | |||
post("ALSA: write returned %d of %d\n", | |||
result, transfersize); | |||
else post("ALSA: write: %s\n", | |||
snd_strerror(errno)); | |||
#endif | |||
sys_log_error(ERR_DATALATE); | |||
if (result == -EPIPE) | |||
{ | |||
result = snd_pcm_prepare(alsa_indev[iodev].a_handle); | |||
if (result < 0) | |||
fprintf(stderr, "read reset error %d\n", result); | |||
} | |||
else fprintf(stderr, "read other error %d\n", result); | |||
resync = 1; | |||
} | |||
/* zero out the output buffer */ | |||
memset(STUFF->st_soundout, 0, DEFDACBLKSIZE * sizeof(*STUFF->st_soundout) * | |||
STUFF->st_outchannels); | |||
if (sys_getrealtime() - timenow > 0.002) | |||
{ | |||
#ifdef DEBUG_ALSA_XFER | |||
post("output %d took %d msec\n", | |||
callno, (int)(1000 * (timenow - timelast))), fflush(stderr); | |||
#endif | |||
timenow = sys_getrealtime(); | |||
sys_log_error(ERR_DACSLEPT); | |||
} | |||
} | |||
/* do input */ | |||
for (iodev = 0, fp1 = STUFF->st_soundin, ch = 0; iodev < alsa_nindev; iodev++) | |||
{ | |||
int thisdevchans = alsa_indev[iodev].a_channels; | |||
int chans = (chansintogo < thisdevchans ? chansintogo : thisdevchans); | |||
chansouttogo -= chans; | |||
result = snd_pcm_readi(alsa_indev[iodev].a_handle, alsa_snd_buf, | |||
transfersize); | |||
if (result < (int)transfersize) | |||
{ | |||
#ifdef DEBUG_ALSA_XFER | |||
if (result < 0) | |||
post("snd_pcm_read %d %d: %s\n", | |||
callno, xferno, snd_strerror(errno)); | |||
else post("snd_pcm_read %d %d returned only %d\n", | |||
callno, xferno, result); | |||
#endif | |||
sys_log_error(ERR_DATALATE); | |||
if (result == -EPIPE) | |||
{ | |||
result = snd_pcm_prepare(alsa_indev[iodev].a_handle); | |||
if (result < 0) | |||
fprintf(stderr, "read reset error %d\n", result); | |||
} | |||
else fprintf(stderr, "read other error %d\n", result); | |||
resync = 1; | |||
} | |||
if (alsa_indev[iodev].a_sampwidth == 4) | |||
{ | |||
for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) | |||
{ | |||
for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--; | |||
j += thisdevchans, fp2++) | |||
*fp2 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[j] | |||
* (1./ INT32_MAX); | |||
} | |||
} | |||
else if (alsa_indev[iodev].a_sampwidth == 3) | |||
{ | |||
#if BYTE_ORDER == LITTLE_ENDIAN | |||
for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) | |||
{ | |||
for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--; | |||
j += thisdevchans, fp2++) | |||
*fp2 = ((float) ( | |||
(((unsigned char *)alsa_snd_buf)[3*j] << 8) | |||
| (((unsigned char *)alsa_snd_buf)[3*j+1] << 16) | |||
| (((unsigned char *)alsa_snd_buf)[3*j+2] << 24))) | |||
* (1./ INT32_MAX); | |||
} | |||
#else | |||
fprintf(stderr, "big endian 24-bit not supported"); | |||
#endif | |||
} | |||
else | |||
{ | |||
for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) | |||
{ | |||
for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--; | |||
j += thisdevchans, fp2++) | |||
*fp2 = (float) ((t_alsa_sample16 *)alsa_snd_buf)[j] | |||
* 3.051850e-05; | |||
} | |||
} | |||
} | |||
#ifdef DEBUG_ALSA_XFER | |||
xferno++; | |||
#endif | |||
if (sys_getrealtime() - timenow > 0.002) | |||
{ | |||
#ifdef DEBUG_ALSA_XFER | |||
post("alsa_send_dacs took %d msec\n", | |||
(int)(1000 * (sys_getrealtime() - timenow))); | |||
#endif | |||
sys_log_error(ERR_ADCSLEPT); | |||
} | |||
{ | |||
static int checkcountdown = 0; | |||
if (!checkcountdown--) | |||
{ | |||
checkcountdown = 10; | |||
if (alsa_nindev + alsa_noutdev > 1) | |||
alsa_checkiosync(); /* check I/O are in sync */ | |||
} | |||
} | |||
return SENDDACS_YES; | |||
} | |||
void alsa_printstate( void) | |||
{ | |||
int i, result, iodev = 0; | |||
snd_pcm_sframes_t indelay = 0, outdelay = 0; | |||
if (sys_audioapi != API_ALSA) | |||
{ | |||
error("restart-audio: implemented for ALSA only."); | |||
return; | |||
} | |||
if (STUFF->st_inchannels) | |||
{ | |||
result = snd_pcm_delay(alsa_indev[iodev].a_handle, &indelay); | |||
if (result < 0) | |||
post("snd_pcm_delay 1 failed"); | |||
else post("in delay %d", indelay); | |||
} | |||
if (STUFF->st_outchannels) | |||
{ | |||
result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay); | |||
if (result < 0) | |||
post("snd_pcm_delay 2 failed"); | |||
else post("out delay %d", outdelay); | |||
} | |||
post("sum %d (%d mod 64)\n", indelay + outdelay, (indelay+outdelay)%64); | |||
post("buf samples %d", alsa_buf_samps); | |||
} | |||
void alsa_putzeros(int iodev, int n) | |||
{ | |||
int i, result; | |||
memset(alsa_snd_buf, 0, | |||
alsa_outdev[iodev].a_sampwidth * DEFDACBLKSIZE * | |||
alsa_outdev[iodev].a_channels); | |||
for (i = 0; i < n; i++) | |||
{ | |||
result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, | |||
DEFDACBLKSIZE); | |||
#if 0 | |||
if (result != DEFDACBLKSIZE) | |||
post("result %d", result); | |||
#endif | |||
} | |||
/* post ("putzeros %d", n); */ | |||
} | |||
void alsa_getzeros(int iodev, int n) | |||
{ | |||
int i, result; | |||
for (i = 0; i < n; i++) | |||
{ | |||
result = snd_pcm_readi(alsa_indev[iodev].a_handle, alsa_snd_buf, | |||
DEFDACBLKSIZE); | |||
#if 0 | |||
if (result != DEFDACBLKSIZE) | |||
post("result %d", result); | |||
#endif | |||
} | |||
/* post ("getzeros %d", n); */ | |||
} | |||
/* call this only if both input and output are open */ | |||
static void alsa_checkiosync( void) | |||
{ | |||
int i, result, giveup = 50, alreadylogged = 0, iodev = 0, err; | |||
snd_pcm_sframes_t minphase, maxphase, thisphase, outdelay; | |||
while (1) | |||
{ | |||
if (giveup-- <= 0) | |||
{ | |||
post("tried but couldn't sync A/D/A"); | |||
alsa_jittermax += 1; | |||
return; | |||
} | |||
minphase = 0x7fffffff; | |||
maxphase = -0x7fffffff; | |||
for (iodev = 0; iodev < alsa_noutdev; iodev++) | |||
{ | |||
if ((result = snd_pcm_state(alsa_outdev[iodev].a_handle)) | |||
!= SND_PCM_STATE_RUNNING && result != SND_PCM_STATE_XRUN) | |||
{ | |||
if (sys_verbose) | |||
post("restarting output device from state %d", | |||
snd_pcm_state(alsa_outdev[iodev].a_handle)); | |||
if ((err = snd_pcm_start(alsa_outdev[iodev].a_handle)) < 0) | |||
check_error(err, 0, "restart failed"); | |||
} | |||
result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay); | |||
if (result < 0) | |||
{ | |||
snd_pcm_prepare(alsa_outdev[iodev].a_handle); | |||
result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay); | |||
} | |||
#ifdef DEBUG_ALSA_XFER | |||
post("outfifo %d %d %d", | |||
callno, xferno, outdelay); | |||
#endif | |||
if (result < 0) | |||
{ | |||
post("output snd_pcm_delay failed: %s", snd_strerror(result)); | |||
if (snd_pcm_status(alsa_outdev[iodev].a_handle, | |||
alsa_status) < 0) | |||
post("output snd_pcm_status failed"); | |||
else post("astate %d", | |||
snd_pcm_status_get_state(alsa_status)); | |||
return; | |||
} | |||
thisphase = alsa_buf_samps - outdelay; | |||
if (thisphase < minphase) | |||
minphase = thisphase; | |||
if (thisphase > maxphase) | |||
maxphase = thisphase; | |||
if (outdelay < 0) | |||
sys_log_error(ERR_DATALATE), alreadylogged = 1; | |||
} | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
{ | |||
if ((result = snd_pcm_state(alsa_indev[iodev].a_handle)) | |||
!= SND_PCM_STATE_RUNNING && result != SND_PCM_STATE_XRUN) | |||
{ | |||
if (sys_verbose) | |||
post("restarting input device from state %d", | |||
snd_pcm_state(alsa_indev[iodev].a_handle)); | |||
if ((err = snd_pcm_start(alsa_indev[iodev].a_handle)) < 0) | |||
check_error(err, 1, "restart failed"); | |||
} | |||
result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase); | |||
if (result < 0) | |||
{ | |||
snd_pcm_prepare(alsa_indev[iodev].a_handle); | |||
result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase); | |||
} | |||
#ifdef DEBUG_ALSA_XFER | |||
post("infifo %d %d %d", | |||
callno, xferno, thisphase); | |||
#endif | |||
if (result < 0) | |||
{ | |||
post("output snd_pcm_delay failed: %s", snd_strerror(result)); | |||
if (snd_pcm_status(alsa_outdev[iodev].a_handle, | |||
alsa_status) < 0) | |||
post("output snd_pcm_status failed"); | |||
else post("astate %d", | |||
snd_pcm_status_get_state(alsa_status)); | |||
return; | |||
} | |||
if (thisphase < minphase) | |||
minphase = thisphase; | |||
if (thisphase > maxphase) | |||
maxphase = thisphase; | |||
} | |||
/* the "correct" position is for all the phases to be exactly | |||
equal; but since we only make corrections DEFDACBLKSIZE samples | |||
at a time, we just ask that the spread be not more than 3/4 | |||
of a block. */ | |||
if (maxphase <= minphase + (alsa_jittermax * (DEFDACBLKSIZE / 4))) | |||
break; | |||
#ifdef DEBUG_ALSA_XFER | |||
post("resync audio %d %d %d", xferno, minphase, maxphase); | |||
#endif | |||
for (iodev = 0; iodev < alsa_noutdev; iodev++) | |||
{ | |||
result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay); | |||
if (result < 0) | |||
break; | |||
thisphase = alsa_buf_samps - outdelay; | |||
if (thisphase > minphase + DEFDACBLKSIZE) | |||
{ | |||
alsa_putzeros(iodev, 1); | |||
if (!alreadylogged) | |||
sys_log_error(ERR_RESYNC), alreadylogged = 1; | |||
#ifdef DEBUG_ALSA_XFER | |||
post("putz %d %d %d %d", | |||
callno, xferno, (int)thisphase, (int)minphase); | |||
#endif | |||
} | |||
} | |||
for (iodev = 0; iodev < alsa_nindev; iodev++) | |||
{ | |||
result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase); | |||
if (result < 0) | |||
break; | |||
if (thisphase > minphase + DEFDACBLKSIZE) | |||
{ | |||
alsa_getzeros(iodev, 1); | |||
if (!alreadylogged) | |||
sys_log_error(ERR_RESYNC), alreadylogged = 1; | |||
#ifdef DEBUG_ALSA_XFER | |||
post("getz %d %d %d %d", | |||
callno, xferno, (int)thisphase, (int)minphase); | |||
#endif | |||
} | |||
} | |||
/* it's possible we didn't do anything; if so don't repeat */ | |||
if (!alreadylogged) | |||
break; | |||
} | |||
#ifdef DEBUG_ALSA_XFER | |||
if (alreadylogged) | |||
post("done resync"); | |||
#endif | |||
} | |||
static int alsa_nnames = 0; | |||
static char **alsa_names = 0; | |||
void alsa_adddev(char *name) | |||
{ | |||
if (alsa_nnames) | |||
alsa_names = (char **)t_resizebytes(alsa_names, | |||
alsa_nnames * sizeof(char *), | |||
(alsa_nnames+1) * sizeof(char *)); | |||
else alsa_names = (char **)t_getbytes(sizeof(char *)); | |||
alsa_names[alsa_nnames] = gensym(name)->s_name; | |||
alsa_nnames++; | |||
} | |||
static void alsa_numbertoname(int devno, char *devname, int nchar) | |||
{ | |||
int ndev = 0, cardno = -1; | |||
while (!snd_card_next(&cardno) && cardno >= 0) | |||
ndev++; | |||
if (devno < 2*ndev) | |||
{ | |||
if (devno & 1) | |||
snprintf(devname, nchar, "plughw:%d", devno/2); | |||
else snprintf(devname, nchar, "hw:%d", devno/2); | |||
} | |||
else if (devno <2*ndev + alsa_nnames) | |||
snprintf(devname, nchar, "%s", alsa_names[devno - 2*ndev]); | |||
else snprintf(devname, nchar, "???"); | |||
} | |||
/* For each hardware card found, we list two devices, the "hard" and | |||
"plug" one. The card scan is derived from portaudio code. */ | |||
void alsa_getdevs(char *indevlist, int *nindevs, | |||
char *outdevlist, int *noutdevs, int *canmulti, | |||
int maxndev, int devdescsize) | |||
{ | |||
int ndev = 0, cardno = -1, i, j; | |||
*canmulti = 2; /* supports multiple devices */ | |||
while (!snd_card_next(&cardno) && cardno >= 0) | |||
{ | |||
snd_ctl_t *ctl; | |||
snd_ctl_card_info_t *info; | |||
char devname[80]; | |||
const char *desc; | |||
if (2 * ndev + 2 > maxndev) | |||
break; | |||
sprintf(devname, "hw:%d", cardno ); | |||
/* fprintf(stderr, "\ntry %s...\n", devname); */ | |||
if (snd_ctl_open(&ctl, devname, 0) >= 0) | |||
{ | |||
snd_ctl_card_info_malloc(&info); | |||
snd_ctl_card_info(ctl, info); | |||
desc = snd_ctl_card_info_get_name(info); | |||
snprintf(indevlist + 2*ndev * devdescsize, devdescsize, | |||
"%s (hardware)", desc); | |||
snprintf(indevlist + (2*ndev + 1) * devdescsize, devdescsize, | |||
"%s (plug-in)", desc); | |||
snprintf(outdevlist + 2*ndev * devdescsize, devdescsize, | |||
"%s (hardware)", desc); | |||
snprintf(outdevlist + (2*ndev + 1) * devdescsize, devdescsize, | |||
"%s (plug-in)", desc); | |||
indevlist[(2*ndev+1) * devdescsize - 1] = | |||
indevlist[(2*ndev+2) * devdescsize - 1] = | |||
outdevlist[(2*ndev+1) * devdescsize - 1] = | |||
outdevlist[(2*ndev+2) * devdescsize - 1] = 0; | |||
snd_ctl_card_info_free(info); | |||
} | |||
else | |||
{ | |||
fprintf(stderr, "ALSA card scan error\n"); | |||
sprintf(indevlist + 2*ndev * devdescsize, "???"); | |||
sprintf(indevlist + (2*ndev + 1) * devdescsize, "???"); | |||
sprintf(outdevlist + 2*ndev * devdescsize, "???"); | |||
sprintf(outdevlist + (2*ndev + 1) * devdescsize, "???"); | |||
} | |||
/* fprintf(stderr, "name: %s\n", snd_ctl_card_info_get_name(info)); */ | |||
ndev++; | |||
} | |||
for (i = 0, j = 2*ndev; i < alsa_nnames; i++, j++) | |||
{ | |||
if (j >= maxndev) | |||
break; | |||
snprintf(indevlist + j * devdescsize, devdescsize, "%s", | |||
alsa_names[i]); | |||
snprintf(outdevlist + j * devdescsize, devdescsize, "%s", | |||
alsa_names[i]); | |||
indevlist[(i+1) * devdescsize - 1] = | |||
outdevlist[(i+1) * devdescsize - 1] = 0; | |||
} | |||
*nindevs = *noutdevs = j; | |||
} |
@@ -0,0 +1,40 @@ | |||
/* Copyright (c) 1997- Guenter Geiger, Miller Puckette, Larry Troxler, | |||
* Winfried Ritsch, Karl MacMillan, and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
typedef int16_t t_alsa_sample16; | |||
typedef int32_t t_alsa_sample32; | |||
#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16) | |||
#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32) | |||
#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DEFDACBLKSIZE) | |||
#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DEFDACBLKSIZE) | |||
#define ALSA_MAXDEV 4 | |||
#define ALSA_JITTER 1024 | |||
#define ALSA_EXTRABUFFER 2048 | |||
#define ALSA_DEFFRAGSIZE 64 | |||
#define ALSA_DEFNFRAG 12 | |||
#ifndef INT32_MAX | |||
#define INT32_MAX 0x7fffffff | |||
#endif | |||
typedef struct _alsa_dev | |||
{ | |||
snd_pcm_t *a_handle; | |||
int a_devno; | |||
int a_sampwidth; | |||
int a_channels; | |||
char **a_addr; | |||
int a_synced; | |||
} t_alsa_dev; | |||
extern t_alsa_dev alsa_indev[ALSA_MAXDEV]; | |||
extern t_alsa_dev alsa_outdev[ALSA_MAXDEV]; | |||
extern int alsa_nindev; | |||
extern int alsa_noutdev; | |||
int alsamm_open_audio(int rate, int blocksize); | |||
void alsamm_close_audio(void); | |||
int alsamm_send_dacs(void); |
@@ -0,0 +1,43 @@ | |||
/* ------------- routines for Apple AudioUnit in AudioToolbox -------------- */ | |||
#ifdef USEAPI_AUDIOUNIT | |||
/* this is currently a placeholder file while we decide which one of three implementations of this API we use */ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include <AudioToolbox/AudioToolbox.h> | |||
pthread_mutex_t audiounit_mutex; | |||
pthread_cond_t audiounit_sem; | |||
int audiounit_open_audio(int inchans, int outchans, int rate) | |||
{ | |||
return 0; | |||
} | |||
void audiounit_close_audio(void) | |||
{ | |||
} | |||
int audiounit_send_dacs(void) | |||
{ | |||
return 0; | |||
} | |||
void audiounit_getdevs(char *indevlist, int *nindevs, | |||
char *outdevlist, int *noutdevs, int *canmulti, | |||
int maxndev, int devdescsize) | |||
{ | |||
post("device getting not implemented for AudioUnit yet\n"); | |||
} | |||
void audiounit_listdevs( void) | |||
{ | |||
post("device listing not implemented for AudioUnit yet\n"); | |||
} | |||
#endif /* AUDIOUNIT */ |
@@ -0,0 +1,37 @@ | |||
/* | |||
* Copyright (c) 2010 Peter Brinkmann (peter.brinkmann@gmail.com) | |||
* | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. | |||
*/ | |||
#ifdef USEAPI_DUMMY | |||
#include <stdio.h> | |||
int dummy_open_audio(int nin, int nout, int sr) { | |||
return 0; | |||
} | |||
int dummy_close_audio( void) { | |||
return 0; | |||
} | |||
int dummy_send_dacs( void) { | |||
return 0; | |||
} | |||
void dummy_getdevs(char *indevlist, int *nindevs, char *outdevlist, | |||
int *noutdevs, int *canmulti, int maxndev, int devdescsize) { | |||
sprintf(indevlist, "NONE"); | |||
sprintf(outdevlist, "NONE"); | |||
*nindevs = *noutdevs = 1; | |||
*canmulti = 0; | |||
} | |||
void dummy_listdevs( void) { | |||
// do nothing | |||
} | |||
#endif | |||
@@ -0,0 +1,132 @@ | |||
/* Copyright (c) 2006 Guenter Geiger, | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#ifdef USEAPI_ESD | |||
#include <stdio.h> | |||
#include <string.h> /* memset */ | |||
#include <esd.h> | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include "m_fixed.h" | |||
/* exported variables */ | |||
/* private data */ | |||
static int esd_socket_out; | |||
static int esd_channels_out; | |||
static int esd_socket_in; | |||
static int esd_channels_in; | |||
int esd_open_audio(int nindev, int *indev, int nchin, int *chin, | |||
int noutdev, int *outdev, int nchout, int *chout, int rate) | |||
{ | |||
esd_format_t format = ESD_BITS16 | ESD_STEREO | ESD_STREAM | ESD_PLAY; | |||
indev[0] = 0; | |||
nindev = 1; | |||
outdev[0] = 0; | |||
noutdev = 1; | |||
rate = sys_dacsr = ESD_DEFAULT_RATE; | |||
if (*chout == 2) { | |||
esd_socket_out = esd_play_stream_fallback(format, ESD_DEFAULT_RATE, NULL, "pd"); | |||
if (esd_socket_out <= 0) { | |||
fprintf (stderr, "Error at esd open: %d\n", esd_socket_out); | |||
esd_channels_out = *chout = 0; | |||
return 0; | |||
} | |||
esd_channels_out = *chout = 2; | |||
} | |||
if (*chin == 2) { | |||
esd_socket_in = esd_record_stream_fallback(format, ESD_DEFAULT_RATE, NULL, "pd-in"); | |||
if (esd_socket_in <= 0) { | |||
fprintf (stderr, "Error at esd open: %d\n", esd_socket_in); | |||
esd_channels_in = *chin = 0; | |||
return 0; | |||
} | |||
esd_channels_in = *chin = 2; | |||
} | |||
return (0); | |||
} | |||
void esd_close_audio( void) | |||
{ | |||
close(esd_socket_out); | |||
close(esd_socket_in); | |||
} | |||
#define DEFDACBLKSIZE 64 | |||
#define MAXCHANS 2 | |||
static short buf[DEFDACBLKSIZE*MAXCHANS]; | |||
int esd_send_dacs(void) | |||
{ | |||
t_sample* fp1,*fp2; | |||
short* sp; | |||
int i,j; | |||
/* Do input */ | |||
if (esd_channels_in) { | |||
read(esd_socket_in,buf,DEFDACBLKSIZE*esd_channels_out*2); | |||
for (i = DEFDACBLKSIZE, fp1 = sys_soundin, | |||
sp = (short *)buf; i--; fp1++, sp += esd_channels_in) { | |||
for (j=0, fp2 = fp1; j<esd_channels_in; j++, fp2 += DEFDACBLKSIZE) | |||
{ | |||
int s = INVSCALE16(sp[j]); | |||
*fp2 = s; | |||
} | |||
} | |||
} | |||
/* Do output */ | |||
if (esd_channels_out) { | |||
for (i = DEFDACBLKSIZE, fp1 = sys_soundout, | |||
sp = (short *)buf; i--; fp1++, sp += esd_channels_out) { | |||
for (j=0, fp2 = fp1; j<esd_channels_out; j++, fp2 += DEFDACBLKSIZE) | |||
{ | |||
int s = SCALE16(*fp2); | |||
if (s > 32767) s = 32767; | |||
else if (s < -32767) s = -32767; | |||
sp[j] = s; | |||
} | |||
} | |||
write(esd_socket_out,buf,DEFDACBLKSIZE*esd_channels_out*2); | |||
} | |||
memset(sys_soundin,0,DEFDACBLKSIZE*esd_channels_out*2); | |||
memset(sys_soundout,0,DEFDACBLKSIZE*esd_channels_out*4); | |||
return (SENDDACS_YES); | |||
} | |||
void esd_listdevs( void) | |||
{ | |||
post("device listing not implemented for ESD yet\n"); | |||
} | |||
void esd_getdevs(char *indevlist, int *nindevs, | |||
char *outdevlist, int *noutdevs, int *canmulti, | |||
int maxndev, int devdescsize) | |||
{ | |||
int i, ndev; | |||
*canmulti = 1; /* supports multiple devices */ | |||
sprintf(indevlist, "ESD device"); | |||
sprintf(outdevlist, "ESD device"); | |||
*nindevs = *noutdevs = 1; | |||
} | |||
#endif |
@@ -0,0 +1,572 @@ | |||
/* Copyright (c) 2003, Miller Puckette and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* Audio back-end for connecting with the JACK audio interconnect system. | |||
*/ | |||
#ifdef USEAPI_JACK | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#ifdef __APPLE__ | |||
#include <jack/weakjack.h> | |||
#endif | |||
#include <jack/jack.h> | |||
#include <regex.h> | |||
#define MAX_CLIENTS 100 | |||
#define MAX_JACK_PORTS 128 /* higher values seem to give bad xrun problems */ | |||
#define BUF_JACK 4096 | |||
#define JACK_OUT_MAX 64 | |||
static jack_nframes_t jack_out_max; | |||
static jack_nframes_t jack_filled = 0; | |||
static t_sample *jack_outbuf; | |||
static t_sample *jack_inbuf; | |||
static int jack_started = 0; | |||
static jack_port_t *input_port[MAX_JACK_PORTS]; | |||
static jack_port_t *output_port[MAX_JACK_PORTS]; | |||
static int outport_count = 0; | |||
static jack_client_t *jack_client = NULL; | |||
static char * desired_client_name = NULL; | |||
char *jack_client_names[MAX_CLIENTS]; | |||
static int jack_dio_error; | |||
static t_audiocallback jack_callback; | |||
static int jack_should_autoconnect = 1; | |||
pthread_mutex_t jack_mutex; | |||
pthread_cond_t jack_sem; | |||
static int pollprocess(jack_nframes_t nframes, void *arg) | |||
{ | |||
int j; | |||
jack_default_audio_sample_t *out, *in; | |||
pthread_mutex_lock(&jack_mutex); | |||
if (nframes > JACK_OUT_MAX) jack_out_max = nframes; | |||
else jack_out_max = JACK_OUT_MAX; | |||
if (jack_filled >= nframes) | |||
{ | |||
if (jack_filled != nframes) | |||
fprintf(stderr,"Partial read\n"); | |||
/* hmm, how to find out whether 't_sample' and | |||
'jack_default_audio_sample_t' are actually the same type??? */ | |||
if (sizeof(t_sample)==sizeof(jack_default_audio_sample_t)) | |||
{ | |||
for (j = 0; j < STUFF->st_outchannels; j++) | |||
{ | |||
if (out = jack_port_get_buffer(output_port[j], nframes)) | |||
memcpy(out, jack_outbuf + (j * BUF_JACK), | |||
sizeof (jack_default_audio_sample_t) * nframes); | |||
} | |||
for (j = 0; j < STUFF->st_inchannels; j++) | |||
{ | |||
if (in = jack_port_get_buffer(input_port[j], nframes)) | |||
memcpy(jack_inbuf + (j * BUF_JACK), in, | |||
sizeof (jack_default_audio_sample_t) * nframes); | |||
} | |||
} | |||
else | |||
{ | |||
unsigned int frame=0; | |||
t_sample*data; | |||
for (j = 0; j < STUFF->st_outchannels; j++) | |||
{ | |||
if (out = jack_port_get_buffer (output_port[j], nframes)) | |||
{ | |||
data = jack_outbuf + (j * BUF_JACK); | |||
for (frame=0; frame<nframes; frame++) | |||
*out++ = *data++; | |||
} | |||
} | |||
for (j = 0; j < STUFF->st_inchannels; j++) | |||
{ | |||
if (in = jack_port_get_buffer( input_port[j], nframes)) | |||
{ | |||
data = jack_inbuf + (j * BUF_JACK); | |||
for (frame=0; frame<nframes; frame++) | |||
*data++ = *in++; | |||
} | |||
} | |||
} | |||
jack_filled -= nframes; | |||
} | |||
else | |||
{ /* PD could not keep up ! */ | |||
if (jack_started) jack_dio_error = 1; | |||
for (j = 0; j < outport_count; j++) | |||
{ | |||
if (out = jack_port_get_buffer (output_port[j], nframes)) | |||
memset(out, 0, sizeof (float) * nframes); | |||
memset(jack_outbuf + j * BUF_JACK, 0, BUF_JACK * sizeof(t_sample)); | |||
} | |||
jack_filled = 0; | |||
} | |||
pthread_cond_broadcast(&jack_sem); | |||
pthread_mutex_unlock(&jack_mutex); | |||
return 0; | |||
} | |||
static int callbackprocess(jack_nframes_t nframes, void *arg) | |||
{ | |||
int chan, j, k; | |||
unsigned int n; | |||
jack_default_audio_sample_t *out[MAX_JACK_PORTS], *in[MAX_JACK_PORTS], *jp; | |||
if (nframes % DEFDACBLKSIZE) | |||
{ | |||
fprintf(stderr, "jack: nframes %d not a multiple of blocksize %d\n", | |||
nframes, DEFDACBLKSIZE); | |||
nframes -= (nframes % DEFDACBLKSIZE); | |||
} | |||
for (chan = 0; chan < STUFF->st_inchannels; chan++) | |||
in[chan] = jack_port_get_buffer(input_port[chan], nframes); | |||
for (chan = 0; chan < STUFF->st_outchannels; chan++) | |||
out[chan] = jack_port_get_buffer(output_port[chan], nframes); | |||
for (n = 0; n < nframes; n += DEFDACBLKSIZE) | |||
{ | |||
t_sample *fp; | |||
for (chan = 0; chan < STUFF->st_inchannels; chan++) | |||
if (in[chan]) | |||
{ | |||
for (fp = STUFF->st_soundin + chan*DEFDACBLKSIZE, | |||
jp = in[chan] + n, j=0; j < DEFDACBLKSIZE; j++) | |||
*fp++ = *jp++; | |||
} | |||
for (chan = 0; chan < STUFF->st_outchannels; chan++) | |||
{ | |||
for (fp = STUFF->st_soundout + chan*DEFDACBLKSIZE, | |||
j = 0; j < DEFDACBLKSIZE; j++) | |||
*fp++ = 0; | |||
} | |||
(*jack_callback)(); | |||
for (chan = 0; chan < STUFF->st_outchannels; chan++) | |||
if (out[chan]) | |||
{ | |||
for (fp = STUFF->st_soundout + chan*DEFDACBLKSIZE, jp = out[chan] + n, | |||
j=0; j < DEFDACBLKSIZE; j++) | |||
*jp++ = *fp++; | |||
} | |||
} | |||
return 0; | |||
} | |||
static int | |||
jack_srate (jack_nframes_t srate, void *arg) | |||
{ | |||
STUFF->st_dacsr = srate; | |||
return 0; | |||
} | |||
void glob_audio_setapi(void *dummy, t_floatarg f); | |||
static void | |||
jack_shutdown (void *arg) | |||
{ | |||
error("JACK: server shut down"); | |||
jack_deactivate (jack_client); | |||
//jack_client_close(jack_client); /* likely to hang if the server shut down */ | |||
jack_client = NULL; | |||
glob_audio_setapi(NULL, API_NONE); // set pd_whichapi 0 | |||
} | |||
static int jack_xrun(void* arg) { | |||
jack_dio_error = 1; | |||
return 0; | |||
} | |||
static char** jack_get_clients(void) | |||
{ | |||
const char **jack_ports; | |||
int i,j; | |||
int num_clients = 0; | |||
regex_t port_regex; | |||
jack_ports = jack_get_ports( jack_client, "", "", 0 ); | |||
regcomp( &port_regex, "^[^:]*", REG_EXTENDED ); | |||
jack_client_names[0] = NULL; | |||
/* Build a list of clients from the list of ports */ | |||
for( i = 0; jack_ports[i] != NULL; i++ ) | |||
{ | |||
int client_seen; | |||
regmatch_t match_info; | |||
char tmp_client_name[100]; | |||
if(num_clients>=MAX_CLIENTS)break; | |||
/* extract the client name from the port name, using a regex | |||
* that parses the clientname:portname syntax */ | |||
regexec( &port_regex, jack_ports[i], 1, &match_info, 0 ); | |||
memcpy( tmp_client_name, &jack_ports[i][match_info.rm_so], | |||
match_info.rm_eo - match_info.rm_so ); | |||
tmp_client_name[ match_info.rm_eo - match_info.rm_so ] = '\0'; | |||
/* do we know about this port's client yet? */ | |||
client_seen = 0; | |||
for( j = 0; j < num_clients; j++ ) | |||
if( strcmp( tmp_client_name, jack_client_names[j] ) == 0 ) | |||
client_seen = 1; | |||
if( client_seen == 0 ) | |||
{ | |||
jack_client_names[num_clients] = (char*)getbytes(strlen(tmp_client_name) + 1); | |||
/* The alsa_pcm client should go in spot 0. If this | |||
* is the alsa_pcm client AND we are NOT about to put | |||
* it in spot 0 put it in spot 0 and move whatever | |||
* was already in spot 0 to the end. */ | |||
if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && num_clients > 0 ) | |||
{ | |||
char* tmp; | |||
/* alsa_pcm goes in spot 0 */ | |||
tmp = jack_client_names[ num_clients ]; | |||
jack_client_names[ num_clients ] = jack_client_names[0]; | |||
jack_client_names[0] = tmp; | |||
strcpy( jack_client_names[0], tmp_client_name); | |||
} | |||
else | |||
{ | |||
/* put the new client at the end of the client list */ | |||
strcpy( jack_client_names[ num_clients ], tmp_client_name ); | |||
} | |||
num_clients++; | |||
} | |||
} | |||
/* for (i=0;i<num_clients;i++) post("client: %s",jack_client_names[i]); */ | |||
free( jack_ports ); | |||
return jack_client_names; | |||
} | |||
/* | |||
* Wire up all the ports of one client. | |||
* | |||
*/ | |||
static int jack_connect_ports(char* client) | |||
{ | |||
char regex_pattern[100]; /* its always the same, ... */ | |||
int i; | |||
const char **jack_ports; | |||
if (strlen(client) > 96) return -1; | |||
sprintf( regex_pattern, "%s:.*", client ); | |||
jack_ports = jack_get_ports( jack_client, regex_pattern, | |||
NULL, JackPortIsOutput); | |||
if (jack_ports) | |||
{ | |||
for (i=0;jack_ports[i] != NULL && i < STUFF->st_inchannels;i++) | |||
if (jack_connect (jack_client, jack_ports[i], | |||
jack_port_name (input_port[i]))) | |||
error ("JACK: cannot connect input ports %s -> %s", | |||
jack_ports[i],jack_port_name (input_port[i])); | |||
free(jack_ports); | |||
} | |||
jack_ports = jack_get_ports( jack_client, regex_pattern, | |||
NULL, JackPortIsInput); | |||
if (jack_ports) | |||
{ | |||
for (i=0;jack_ports[i] != NULL && i < STUFF->st_outchannels;i++) | |||
if (jack_connect (jack_client, jack_port_name (output_port[i]), | |||
jack_ports[i])) | |||
error( "JACK: cannot connect output ports %s -> %s", | |||
jack_port_name (output_port[i]),jack_ports[i]); | |||
free(jack_ports); | |||
} | |||
return 0; | |||
} | |||
static void pd_jack_error_callback(const char *desc) { | |||
error("JACKerror: %s", desc); | |||
return; | |||
} | |||
int | |||
jack_open_audio(int inchans, int outchans, int rate, t_audiocallback callback) | |||
{ | |||
int j; | |||
char port_name[80] = ""; | |||
char client_name[80] = ""; | |||
int client_iterator = 0; | |||
int new_jack = 0; | |||
int srate; | |||
jack_status_t status; | |||
if (!jack_client_open) | |||
{ | |||
error("Can't open Jack (it seems not to be installed)"); | |||
return 1; | |||
} | |||
jack_dio_error = 0; | |||
if ((inchans == 0) && (outchans == 0)) return 0; | |||
if (outchans > MAX_JACK_PORTS) { | |||
error("JACK: %d output ports not supported, setting to %d", | |||
outchans, MAX_JACK_PORTS); | |||
outchans = MAX_JACK_PORTS; | |||
} | |||
if (inchans > MAX_JACK_PORTS) { | |||
error("JACK: %d input ports not supported, setting to %d", | |||
inchans, MAX_JACK_PORTS); | |||
inchans = MAX_JACK_PORTS; | |||
} | |||
/* try to become a client of the JACK server. (If no JACK server exists, | |||
jack_client_open() will start uone up by default. It's not clear | |||
whether or not this is desirable; see long Pd list thread started by | |||
yvan volochine, June 2013) */ | |||
if (!jack_client) { | |||
if (!desired_client_name || !strlen(desired_client_name)) | |||
jack_client_name("pure_data"); | |||
jack_client = jack_client_open (desired_client_name, JackNoStartServer, | |||
&status, NULL); | |||
if (status & JackFailure) { | |||
error("JACK: Failure. Is JACK running?"); | |||
verbose(1, "JACK: Returned status is: %d", status); | |||
jack_client=NULL; | |||
/* jack spits out enough messages already, do not warn */ | |||
STUFF->st_inchannels = STUFF->st_outchannels = 0; | |||
return 1; | |||
} | |||
if (status & JackNameNotUnique) | |||
jack_client_name(jack_get_client_name(jack_client)); | |||
verbose(1, "JACK: registered as '%s'", desired_client_name); | |||
STUFF->st_inchannels = inchans; | |||
STUFF->st_outchannels = outchans; | |||
if (jack_inbuf) | |||
free(jack_inbuf); | |||
if (STUFF->st_inchannels) | |||
jack_inbuf = calloc(sizeof(t_sample), STUFF->st_inchannels * BUF_JACK); | |||
if (jack_outbuf) | |||
free(jack_outbuf); | |||
if (STUFF->st_outchannels) | |||
jack_outbuf = calloc(sizeof(t_sample), STUFF->st_outchannels * BUF_JACK); | |||
jack_get_clients(); | |||
/* set JACK callback functions */ | |||
jack_callback = callback; | |||
jack_set_process_callback(jack_client, | |||
(callback? callbackprocess : pollprocess), 0); | |||
jack_set_error_function (pd_jack_error_callback); | |||
#ifdef JACK_XRUN | |||
jack_set_xrun_callback (jack_client, jack_xrun, NULL); | |||
#endif | |||
/* tell the JACK server to call `srate()' whenever | |||
the sample rate of the system changes. | |||
*/ | |||
jack_set_sample_rate_callback (jack_client, jack_srate, 0); | |||
/* tell the JACK server to call `jack_shutdown()' if | |||
it ever shuts down, either entirely, or if it | |||
just decides to stop calling us. | |||
*/ | |||
jack_on_shutdown (jack_client, jack_shutdown, 0); | |||
for (j=0; j<STUFF->st_inchannels; j++) | |||
input_port[j]=NULL; | |||
for (j=0; j<STUFF->st_outchannels; j++) | |||
output_port[j] = NULL; | |||
new_jack = 1; | |||
} | |||
/* display the current sample rate. once the client is activated | |||
(see below), you should rely on your own sample rate | |||
callback (see above) for this value. | |||
*/ | |||
srate = jack_get_sample_rate (jack_client); | |||
STUFF->st_dacsr = srate; | |||
/* create the ports */ | |||
for (j = 0; j < inchans; j++) | |||
{ | |||
sprintf(port_name, "input%d", j); | |||
if (!input_port[j]) input_port[j] = jack_port_register (jack_client, | |||
port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
if (!input_port[j]) | |||
{ | |||
error("JACK: can only register %d input ports (of %d requested)", | |||
j, inchans); | |||
STUFF->st_inchannels = inchans = j; | |||
break; | |||
} | |||
} | |||
for (j = 0; j < outchans; j++) | |||
{ | |||
sprintf(port_name, "output%d", j); | |||
if (!output_port[j]) output_port[j] = jack_port_register (jack_client, | |||
port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
if (!output_port[j]) | |||
{ | |||
error("JACK: can only register %d output ports (of %d requested)", | |||
j, outchans); | |||
STUFF->st_outchannels = outchans = j; | |||
break; | |||
} | |||
} | |||
outport_count = outchans; | |||
/* tell the JACK server that we are ready to roll */ | |||
if (new_jack) | |||
{ | |||
if (jack_activate (jack_client)) { | |||
error("cannot activate client"); | |||
STUFF->st_inchannels = STUFF->st_outchannels = 0; | |||
return 1; | |||
} | |||
for (j = 0; j < outchans; j++) | |||
memset(jack_outbuf + j * BUF_JACK, 0, | |||
BUF_JACK * sizeof(t_sample)); | |||
if (jack_client_names[0] && jack_should_autoconnect) | |||
jack_connect_ports(jack_client_names[0]); | |||
pthread_mutex_init(&jack_mutex, NULL); | |||
pthread_cond_init(&jack_sem, NULL); | |||
} | |||
return 0; | |||
} | |||
void jack_close_audio(void) | |||
{ | |||
if (jack_client){ | |||
jack_deactivate (jack_client); | |||
jack_client_close(jack_client); | |||
} | |||
jack_client=NULL; | |||
jack_started = 0; | |||
pthread_cond_broadcast(&jack_sem); | |||
pthread_cond_destroy(&jack_sem); | |||
pthread_mutex_destroy(&jack_mutex); | |||
if (jack_inbuf) | |||
free(jack_inbuf), jack_inbuf = 0; | |||
if (jack_outbuf) | |||
free(jack_outbuf), jack_outbuf = 0; | |||
} | |||
int jack_send_dacs(void) | |||
{ | |||
t_sample * fp; | |||
int j; | |||
int rtnval = SENDDACS_YES; | |||
int timenow; | |||
int timeref = sys_getrealtime(); | |||
if (!jack_client) return SENDDACS_NO; | |||
if (!STUFF->st_inchannels && !STUFF->st_outchannels) return (SENDDACS_NO); | |||
if (jack_dio_error) | |||
{ | |||
sys_log_error(ERR_RESYNC); | |||
jack_dio_error = 0; | |||
} | |||
pthread_mutex_lock(&jack_mutex); | |||
if (jack_filled >= jack_out_max) | |||
pthread_cond_wait(&jack_sem,&jack_mutex); | |||
if (!jack_client) | |||
{ | |||
pthread_mutex_unlock(&jack_mutex); | |||
return SENDDACS_NO; | |||
} | |||
jack_started = 1; | |||
fp = STUFF->st_soundout; | |||
for (j = 0; j < STUFF->st_outchannels; j++) | |||
{ | |||
memcpy(jack_outbuf + (j * BUF_JACK) + jack_filled, fp, | |||
DEFDACBLKSIZE*sizeof(t_sample)); | |||
fp += DEFDACBLKSIZE; | |||
} | |||
fp = STUFF->st_soundin; | |||
for (j = 0; j < STUFF->st_inchannels; j++) | |||
{ | |||
memcpy(fp, jack_inbuf + (j * BUF_JACK) + jack_filled, | |||
DEFDACBLKSIZE*sizeof(t_sample)); | |||
fp += DEFDACBLKSIZE; | |||
} | |||
jack_filled += DEFDACBLKSIZE; | |||
pthread_mutex_unlock(&jack_mutex); | |||
if ((timenow = sys_getrealtime()) - timeref > 0.002) | |||
{ | |||
rtnval = SENDDACS_SLEPT; | |||
} | |||
memset(STUFF->st_soundout, 0, DEFDACBLKSIZE*sizeof(t_sample)*STUFF->st_outchannels); | |||
return rtnval; | |||
} | |||
void jack_getdevs(char *indevlist, int *nindevs, | |||
char *outdevlist, int *noutdevs, int *canmulti, | |||
int maxndev, int devdescsize) | |||
{ | |||
int i, ndev; | |||
*canmulti = 0; /* supports multiple devices */ | |||
ndev = 1; | |||
for (i = 0; i < ndev; i++) | |||
{ | |||
sprintf(indevlist + i * devdescsize, "JACK"); | |||
sprintf(outdevlist + i * devdescsize, "JACK"); | |||
} | |||
*nindevs = *noutdevs = ndev; | |||
} | |||
void jack_listdevs( void) | |||
{ | |||
post("device listing not implemented for jack yet\n"); | |||
} | |||
void jack_autoconnect(int v) | |||
{ | |||
jack_should_autoconnect = v; | |||
} | |||
void jack_client_name(char *name) | |||
{ | |||
if (desired_client_name) { | |||
free(desired_client_name); | |||
desired_client_name = NULL; | |||
} | |||
if (name) { | |||
desired_client_name = (char*)getbytes(strlen(name) + 1); | |||
strcpy(desired_client_name, name); | |||
} | |||
} | |||
#endif /* JACK */ |
@@ -0,0 +1,794 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized | |||
"wave" devices, which is how ADAT boards appear to the WAVE API. */ | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include <stdio.h> | |||
#include <windows.h> | |||
#include <mmsystem.h> | |||
/* ------------------------- audio -------------------------- */ | |||
static void nt_close_midiin(void); | |||
static void nt_noresync( void); | |||
static void postflags(void); | |||
#define NAPORTS 16 /* wini hack for multiple ADDA devices */ | |||
#define CHANNELS_PER_DEVICE 2 | |||
#define DEFAULTCHANS 2 | |||
#define DEFAULTSRATE 44100 | |||
#define SAMPSIZE 2 | |||
int nt_realdacblksize; | |||
#define DEFREALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */ | |||
#define MAXBUFFER 100 /* number of buffers in use at maximum advance */ | |||
#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */ | |||
static int nt_naudiobuffer = DEFBUFFER; | |||
static int nt_whichapi = API_MMIO; | |||
static int nt_meters; /* true if we're metering */ | |||
static float nt_inmax; /* max input amplitude */ | |||
static float nt_outmax; /* max output amplitude */ | |||
static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */ | |||
typedef struct _sbuf | |||
{ | |||
HANDLE hData; | |||
HPSTR lpData; // pointer to waveform data memory | |||
HANDLE hWaveHdr; | |||
WAVEHDR *lpWaveHdr; // pointer to header structure | |||
} t_sbuf; | |||
t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */ | |||
HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */ | |||
static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */ | |||
t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */ | |||
HWAVEIN ntsnd_indev[NAPORTS]; /* input device */ | |||
static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */ | |||
static void nt_waveinerror(char *s, int err) | |||
{ | |||
char t[256]; | |||
waveInGetErrorText(err, t, 256); | |||
fprintf(stderr, s, t); | |||
} | |||
static void nt_waveouterror(char *s, int err) | |||
{ | |||
char t[256]; | |||
waveOutGetErrorText(err, t, 256); | |||
fprintf(stderr, s, t); | |||
} | |||
static void wave_prep(t_sbuf *bp, int setdone) | |||
{ | |||
WAVEHDR *wh; | |||
short *sp; | |||
int i; | |||
/* | |||
* Allocate and lock memory for the waveform data. The memory | |||
* for waveform data must be globally allocated with | |||
* GMEM_MOVEABLE and GMEM_SHARE flags. | |||
*/ | |||
if (!(bp->hData = | |||
GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, | |||
(DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize)))) | |||
printf("alloc 1 failed\n"); | |||
if (!(bp->lpData = | |||
(HPSTR) GlobalLock(bp->hData))) | |||
printf("lock 1 failed\n"); | |||
/* Allocate and lock memory for the header. */ | |||
if (!(bp->hWaveHdr = | |||
GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR)))) | |||
printf("alloc 2 failed\n"); | |||
if (!(wh = bp->lpWaveHdr = | |||
(WAVEHDR *) GlobalLock(bp->hWaveHdr))) | |||
printf("lock 2 failed\n"); | |||
for (i = CHANNELS_PER_DEVICE * nt_realdacblksize, | |||
sp = (short *)bp->lpData; i--; ) | |||
*sp++ = 0; | |||
wh->lpData = bp->lpData; | |||
wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize); | |||
wh->dwFlags = 0; | |||
wh->dwLoops = 0L; | |||
wh->lpNext = 0; | |||
wh->reserved = 0; | |||
/* optionally (for writing) set DONE flag as if we had queued them */ | |||
if (setdone) | |||
wh->dwFlags = WHDR_DONE; | |||
} | |||
static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER; | |||
int mmio_do_open_audio(void) | |||
{ | |||
PCMWAVEFORMAT form; | |||
int i, j; | |||
UINT mmresult; | |||
int nad, nda; | |||
static int naudioprepped = 0, nindevsprepped = 0, noutdevsprepped = 0; | |||
if (sys_verbose) | |||
post("%d devices in, %d devices out", | |||
nt_nwavein, nt_nwaveout); | |||
form.wf.wFormatTag = WAVE_FORMAT_PCM; | |||
form.wf.nChannels = CHANNELS_PER_DEVICE; | |||
form.wf.nSamplesPerSec = STUFF->st_dacsr; | |||
form.wf.nAvgBytesPerSec = STUFF->st_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE); | |||
form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE; | |||
form.wBitsPerSample = 8 * SAMPSIZE; | |||
if (nt_nwavein <= 1 && nt_nwaveout <= 1) | |||
nt_noresync(); | |||
if (nindevsprepped < nt_nwavein) | |||
{ | |||
for (i = nindevsprepped; i < nt_nwavein; i++) | |||
for (j = 0; j < naudioprepped; j++) | |||
wave_prep(&ntsnd_invec[i][j], 0); | |||
nindevsprepped = nt_nwavein; | |||
} | |||
if (noutdevsprepped < nt_nwaveout) | |||
{ | |||
for (i = noutdevsprepped; i < nt_nwaveout; i++) | |||
for (j = 0; j < naudioprepped; j++) | |||
wave_prep(&ntsnd_outvec[i][j], 1); | |||
noutdevsprepped = nt_nwaveout; | |||
} | |||
if (naudioprepped < nt_naudiobuffer) | |||
{ | |||
for (j = naudioprepped; j < nt_naudiobuffer; j++) | |||
{ | |||
for (i = 0; i < nt_nwavein; i++) | |||
wave_prep(&ntsnd_invec[i][j], 0); | |||
for (i = 0; i < nt_nwaveout; i++) | |||
wave_prep(&ntsnd_outvec[i][j], 1); | |||
} | |||
naudioprepped = nt_naudiobuffer; | |||
} | |||
for (nad=0; nad < nt_nwavein; nad++) | |||
{ | |||
/* Open waveform device(s), sucessively numbered, for input */ | |||
mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad, | |||
(WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL); | |||
if (sys_verbose) | |||
printf("opened adc device %d with return %d\n", | |||
nt_whichadc+nad,mmresult); | |||
if (mmresult != MMSYSERR_NOERROR) | |||
{ | |||
nt_waveinerror("waveInOpen: %s\n", mmresult); | |||
nt_nwavein = nad; /* nt_nwavein = 0 wini */ | |||
} | |||
else | |||
{ | |||
for (i = 0; i < nt_naudiobuffer; i++) | |||
{ | |||
mmresult = waveInPrepareHeader(ntsnd_indev[nad], | |||
ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR)); | |||
if (mmresult != MMSYSERR_NOERROR) | |||
nt_waveinerror("waveinprepareheader: %s\n", mmresult); | |||
mmresult = waveInAddBuffer(ntsnd_indev[nad], | |||
ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR)); | |||
if (mmresult != MMSYSERR_NOERROR) | |||
nt_waveinerror("waveInAddBuffer: %s\n", mmresult); | |||
} | |||
} | |||
} | |||
/* quickly start them all together */ | |||
for (nad = 0; nad < nt_nwavein; nad++) | |||
waveInStart(ntsnd_indev[nad]); | |||
for (nda = 0; nda < nt_nwaveout; nda++) | |||
{ | |||
/* Open a waveform device for output in sucessiv device numbering*/ | |||
mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda, | |||
(WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL); | |||
if (sys_verbose) | |||
fprintf(stderr,"opened dac device %d, with return %d\n", | |||
nt_whichdac +nda, mmresult); | |||
if (mmresult != MMSYSERR_NOERROR) | |||
{ | |||
fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda); | |||
nt_waveouterror("waveOutOpen device: %s\n", mmresult); | |||
nt_nwaveout = nda; | |||
} | |||
} | |||
return (0); | |||
} | |||
void mmio_close_audio( void) | |||
{ | |||
int errcode; | |||
int nda, nad; | |||
if (sys_verbose) | |||
post("closing audio..."); | |||
for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */ | |||
{ | |||
errcode = waveOutReset(ntsnd_outdev[nda]); | |||
if (errcode != MMSYSERR_NOERROR) | |||
printf("error resetting output %d: %d\n", nda, errcode); | |||
errcode = waveOutClose(ntsnd_outdev[nda]); | |||
if (errcode != MMSYSERR_NOERROR) | |||
printf("error closing output %d: %d\n",nda , errcode); | |||
} | |||
nt_nwaveout = 0; | |||
for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */ | |||
{ | |||
errcode = waveInReset(ntsnd_indev[nad]); | |||
if (errcode != MMSYSERR_NOERROR) | |||
printf("error resetting input: %d\n", errcode); | |||
errcode = waveInClose(ntsnd_indev[nad]); | |||
if (errcode != MMSYSERR_NOERROR) | |||
printf("error closing input: %d\n", errcode); | |||
} | |||
nt_nwavein = 0; | |||
} | |||
#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */ | |||
#define DACJITTER 10 | |||
static int nt_adcjitterbufsallowed = ADCJITTER; | |||
static int nt_dacjitterbufsallowed = DACJITTER; | |||
/* ------------- MIDI time stamping from audio clock ------------ */ | |||
#ifdef MIDI_TIMESTAMP | |||
static double nt_hibuftime; | |||
static double initsystime = -1; | |||
/* call this whenever we reset audio */ | |||
static void nt_resetmidisync(void) | |||
{ | |||
initsystime = clock_getsystime(); | |||
nt_hibuftime = sys_getrealtime(); | |||
} | |||
/* call this whenever we're idled waiting for audio to be ready. | |||
The routine maintains a high and low water point for the difference | |||
between real and DAC time. */ | |||
static void nt_midisync(void) | |||
{ | |||
double jittersec, diff; | |||
if (initsystime == -1) nt_resetmidisync(); | |||
jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ? | |||
nt_dacjitterbufsallowed : nt_adcjitterbufsallowed) | |||
* nt_realdacblksize / STUFF->st_getsr(); | |||
diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime); | |||
if (diff > nt_hibuftime) nt_hibuftime = diff; | |||
if (diff < nt_hibuftime - jittersec) | |||
{ | |||
post("jitter excess %d %f", dac, diff); | |||
nt_resetmidisync(); | |||
} | |||
} | |||
static double nt_midigettimefor(LARGE_INTEGER timestamp) | |||
{ | |||
/* this is broken now... used to work when "timestamp" was derived from | |||
QueryPerformanceCounter() instead of the gates approved | |||
timeGetSystemTime() call in the MIDI callback routine below. */ | |||
return (nt_tixtotime(timestamp) - nt_hibuftime); | |||
} | |||
#endif /* MIDI_TIMESTAMP */ | |||
static int nt_fill = 0; | |||
#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x)) | |||
#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x)) | |||
#define MAXRESYNC 500 | |||
#if 0 /* this is used for debugging */ | |||
static void nt_printaudiostatus(void) | |||
{ | |||
int nad, nda; | |||
for (nad = 0; nad < nt_nwavein; nad++) | |||
{ | |||
int phase = ntsnd_inphase[nad]; | |||
int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0; | |||
int firstphasedone = -1, firstphasebusy = -1; | |||
for (count = 0; count < nt_naudiobuffer; count++) | |||
{ | |||
int donethis = | |||
(ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE); | |||
int donenext = | |||
(ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE); | |||
if (donethis && !donenext) | |||
{ | |||
if (firstphasebusy >= 0) goto multipleadc; | |||
firstphasebusy = count; | |||
} | |||
if (!donethis && donenext) | |||
{ | |||
if (firstphasedone >= 0) goto multipleadc; | |||
firstphasedone = count; | |||
} | |||
phase2 = phase3; | |||
phase3 = WRAPFWD(phase2 + 1); | |||
} | |||
post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy, | |||
firstphasedone); | |||
continue; | |||
multipleadc: | |||
startpost("nad %d phase %d: oops:", nad, phase); | |||
for (count = 0; count < nt_naudiobuffer; count++) | |||
{ | |||
char buf[80]; | |||
sprintf(buf, " %d", | |||
(ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE)); | |||
poststring(buf); | |||
} | |||
endpost(); | |||
} | |||
for (nda = 0; nda < nt_nwaveout; nda++) | |||
{ | |||
int phase = ntsnd_outphase[nad]; | |||
int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0; | |||
int firstphasedone = -1, firstphasebusy = -1; | |||
for (count = 0; count < nt_naudiobuffer; count++) | |||
{ | |||
int donethis = | |||
(ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE); | |||
int donenext = | |||
(ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE); | |||
if (donethis && !donenext) | |||
{ | |||
if (firstphasebusy >= 0) goto multipledac; | |||
firstphasebusy = count; | |||
} | |||
if (!donethis && donenext) | |||
{ | |||
if (firstphasedone >= 0) goto multipledac; | |||
firstphasedone = count; | |||
} | |||
phase2 = phase3; | |||
phase3 = WRAPFWD(phase2 + 1); | |||
} | |||
if (firstphasebusy < 0) post("nda %d phase %d all %d", | |||
nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE)); | |||
else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy, | |||
firstphasedone); | |||
continue; | |||
multipledac: | |||
startpost("nda %d phase %d: oops:", nda, phase); | |||
for (count = 0; count < nt_naudiobuffer; count++) | |||
{ | |||
char buf[80]; | |||
sprintf(buf, " %d", | |||
(ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE)); | |||
poststring(buf); | |||
} | |||
endpost(); | |||
} | |||
} | |||
#endif /* 0 */ | |||
/* this is a hack to avoid ever resyncing audio pointers in case for whatever | |||
reason the sync testing below gives false positives. */ | |||
static int nt_resync_cancelled; | |||
static void nt_noresync( void) | |||
{ | |||
nt_resync_cancelled = 1; | |||
} | |||
static void nt_resyncaudio(void) | |||
{ | |||
UINT mmresult; | |||
int nad, nda, count; | |||
if (nt_resync_cancelled) | |||
return; | |||
/* for each open input device, eat all buffers which are marked | |||
ready. The next one will thus be "busy". */ | |||
post("resyncing audio"); | |||
for (nad = 0; nad < nt_nwavein; nad++) | |||
{ | |||
int phase = ntsnd_inphase[nad]; | |||
for (count = 0; count < MAXRESYNC; count++) | |||
{ | |||
WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; | |||
if (!(inwavehdr->dwFlags & WHDR_DONE)) break; | |||
if (inwavehdr->dwFlags & WHDR_PREPARED) | |||
waveInUnprepareHeader(ntsnd_indev[nad], | |||
inwavehdr, sizeof(WAVEHDR)); | |||
inwavehdr->dwFlags = 0L; | |||
waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR)); | |||
mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr, | |||
sizeof(WAVEHDR)); | |||
if (mmresult != MMSYSERR_NOERROR) | |||
nt_waveinerror("waveInAddBuffer: %s\n", mmresult); | |||
ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1); | |||
} | |||
if (count == MAXRESYNC) post("resync error 1"); | |||
} | |||
/* Each output buffer which is "ready" is filled with zeros and | |||
queued. */ | |||
for (nda = 0; nda < nt_nwaveout; nda++) | |||
{ | |||
int phase = ntsnd_outphase[nda]; | |||
for (count = 0; count < MAXRESYNC; count++) | |||
{ | |||
WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; | |||
if (!(outwavehdr->dwFlags & WHDR_DONE)) break; | |||
if (outwavehdr->dwFlags & WHDR_PREPARED) | |||
waveOutUnprepareHeader(ntsnd_outdev[nda], | |||
outwavehdr, sizeof(WAVEHDR)); | |||
outwavehdr->dwFlags = 0L; | |||
memset((char *)(ntsnd_outvec[nda][phase].lpData), | |||
0, (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize)); | |||
waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr, | |||
sizeof(WAVEHDR)); | |||
mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr, | |||
sizeof(WAVEHDR)); | |||
if (mmresult != MMSYSERR_NOERROR) | |||
nt_waveouterror("waveOutAddBuffer: %s\n", mmresult); | |||
ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1); | |||
} | |||
if (count == MAXRESYNC) post("resync error 2"); | |||
} | |||
#ifdef MIDI_TIMESTAMP | |||
nt_resetmidisync(); | |||
#endif | |||
} | |||
#define LATE 0 | |||
#define RESYNC 1 | |||
#define NOTHING 2 | |||
static int nt_errorcount; | |||
static int nt_resynccount; | |||
static double nt_nextreporttime = -1; | |||
void nt_logerror(int which) | |||
{ | |||
#if 0 | |||
post("error %d %d", count, which); | |||
if (which < NOTHING) nt_errorcount++; | |||
if (which == RESYNC) nt_resynccount++; | |||
if (sys_getrealtime() > nt_nextreporttime) | |||
{ | |||
post("%d audio I/O error%s", nt_errorcount, | |||
(nt_errorcount > 1 ? "s" : "")); | |||
if (nt_resynccount) post("DAC/ADC sync error"); | |||
nt_errorcount = nt_resynccount = 0; | |||
nt_nextreporttime = sys_getrealtime() - 5; | |||
} | |||
#endif | |||
} | |||
/* system buffer with t_sample types for one tick */ | |||
int mmio_send_dacs(void) | |||
{ | |||
HMMIO hmmio; | |||
UINT mmresult; | |||
HANDLE hFormat; | |||
int i, j; | |||
short *sp1, *sp2; | |||
float *fp1, *fp2; | |||
int nextfill, doxfer = 0; | |||
int nda, nad; | |||
if (!nt_nwavein && !nt_nwaveout) return (0); | |||
if (nt_meters) | |||
{ | |||
int i, n; | |||
float maxsamp; | |||
for (i = 0, n = 2 * nt_nwavein * DEFDACBLKSIZE, maxsamp = nt_inmax; | |||
i < n; i++) | |||
{ | |||
float f = STUFF->st_soundin[i]; | |||
if (f > maxsamp) maxsamp = f; | |||
else if (-f > maxsamp) maxsamp = -f; | |||
} | |||
nt_inmax = maxsamp; | |||
for (i = 0, n = 2 * nt_nwaveout * DEFDACBLKSIZE, maxsamp = nt_outmax; | |||
i < n; i++) | |||
{ | |||
float f = STUFF->st_soundout[i]; | |||
if (f > maxsamp) maxsamp = f; | |||
else if (-f > maxsamp) maxsamp = -f; | |||
} | |||
nt_outmax = maxsamp; | |||
} | |||
/* the "fill pointer" nt_fill controls where in the next | |||
I/O buffers we will write and/or read. If it's zero, we | |||
first check whether the buffers are marked "done". */ | |||
if (!nt_fill) | |||
{ | |||
for (nad = 0; nad < nt_nwavein; nad++) | |||
{ | |||
int phase = ntsnd_inphase[nad]; | |||
WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; | |||
if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle; | |||
} | |||
for (nda = 0; nda < nt_nwaveout; nda++) | |||
{ | |||
int phase = ntsnd_outphase[nda]; | |||
WAVEHDR *outwavehdr = | |||
ntsnd_outvec[nda][phase].lpWaveHdr; | |||
if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle; | |||
} | |||
for (nad = 0; nad < nt_nwavein; nad++) | |||
{ | |||
int phase = ntsnd_inphase[nad]; | |||
WAVEHDR *inwavehdr = | |||
ntsnd_invec[nad][phase].lpWaveHdr; | |||
if (inwavehdr->dwFlags & WHDR_PREPARED) | |||
waveInUnprepareHeader(ntsnd_indev[nad], | |||
inwavehdr, sizeof(WAVEHDR)); | |||
} | |||
for (nda = 0; nda < nt_nwaveout; nda++) | |||
{ | |||
int phase = ntsnd_outphase[nda]; | |||
WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; | |||
if (outwavehdr->dwFlags & WHDR_PREPARED) | |||
waveOutUnprepareHeader(ntsnd_outdev[nda], | |||
outwavehdr, sizeof(WAVEHDR)); | |||
} | |||
} | |||
/* Convert audio output to fixed-point and put it in the output | |||
buffer. */ | |||
for (nda = 0, fp1 = STUFF->st_soundout; nda < nt_nwaveout; nda++) | |||
{ | |||
int phase = ntsnd_outphase[nda]; | |||
for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) + | |||
CHANNELS_PER_DEVICE * nt_fill; | |||
i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++) | |||
{ | |||
for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE; | |||
j++, fp2++, sp2 += CHANNELS_PER_DEVICE) | |||
{ | |||
int x1 = 32767.f * *fp2; | |||
if (x1 > 32767) x1 = 32767; | |||
else if (x1 < -32767) x1 = -32767; | |||
*sp2 = x1; | |||
} | |||
} | |||
} | |||
memset(STUFF->st_soundout, 0, | |||
(DEFDACBLKSIZE *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout); | |||
/* vice versa for the input buffer */ | |||
for (nad = 0, fp1 = STUFF->st_soundin; nad < nt_nwavein; nad++) | |||
{ | |||
int phase = ntsnd_inphase[nad]; | |||
for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) + | |||
CHANNELS_PER_DEVICE * nt_fill; | |||
i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++) | |||
{ | |||
for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE; | |||
j++, fp2++, sp2 += CHANNELS_PER_DEVICE) | |||
{ | |||
*fp2 = ((float)(1./32767.)) * (float)(*sp2); | |||
} | |||
} | |||
} | |||
nt_fill = nt_fill + DEFDACBLKSIZE; | |||
if (nt_fill == nt_realdacblksize) | |||
{ | |||
nt_fill = 0; | |||
for (nad = 0; nad < nt_nwavein; nad++) | |||
{ | |||
int phase = ntsnd_inphase[nad]; | |||
HWAVEIN device = ntsnd_indev[nad]; | |||
WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; | |||
waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR)); | |||
mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR)); | |||
if (mmresult != MMSYSERR_NOERROR) | |||
nt_waveinerror("waveInAddBuffer: %s\n", mmresult); | |||
ntsnd_inphase[nad] = WRAPFWD(phase + 1); | |||
} | |||
for (nda = 0; nda < nt_nwaveout; nda++) | |||
{ | |||
int phase = ntsnd_outphase[nda]; | |||
HWAVEOUT device = ntsnd_outdev[nda]; | |||
WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; | |||
waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR)); | |||
mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR)); | |||
if (mmresult != MMSYSERR_NOERROR) | |||
nt_waveouterror("waveOutWrite: %s\n", mmresult); | |||
ntsnd_outphase[nda] = WRAPFWD(phase + 1); | |||
} | |||
/* check for DAC underflow or ADC overflow. */ | |||
for (nad = 0; nad < nt_nwavein; nad++) | |||
{ | |||
int phase = WRAPBACK(ntsnd_inphase[nad] - 2); | |||
WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr; | |||
if (inwavehdr->dwFlags & WHDR_DONE) goto late; | |||
} | |||
for (nda = 0; nda < nt_nwaveout; nda++) | |||
{ | |||
int phase = WRAPBACK(ntsnd_outphase[nda] - 2); | |||
WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr; | |||
if (outwavehdr->dwFlags & WHDR_DONE) goto late; | |||
} | |||
} | |||
return (1); | |||
late: | |||
nt_logerror(LATE); | |||
nt_resyncaudio(); | |||
return (1); | |||
idle: | |||
/* If more than nt_adcjitterbufsallowed ADC buffers are ready | |||
on any input device, resynchronize */ | |||
for (nad = 0; nad < nt_nwavein; nad++) | |||
{ | |||
int phase = ntsnd_inphase[nad]; | |||
WAVEHDR *inwavehdr = | |||
ntsnd_invec[nad] | |||
[WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr; | |||
if (inwavehdr->dwFlags & WHDR_DONE) | |||
{ | |||
nt_resyncaudio(); | |||
return (0); | |||
} | |||
} | |||
/* test dac sync the same way */ | |||
for (nda = 0; nda < nt_nwaveout; nda++) | |||
{ | |||
int phase = ntsnd_outphase[nda]; | |||
WAVEHDR *outwavehdr = | |||
ntsnd_outvec[nda] | |||
[WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr; | |||
if (outwavehdr->dwFlags & WHDR_DONE) | |||
{ | |||
nt_resyncaudio(); | |||
return (0); | |||
} | |||
} | |||
#ifdef MIDI_TIMESTAMP | |||
nt_midisync(); | |||
#endif | |||
return (0); | |||
} | |||
/* ------------------- public routines -------------------------- */ | |||
int mmio_open_audio(int naudioindev, int *audioindev, | |||
int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, | |||
int nchoutdev, int *choutdev, int rate, int blocksize) | |||
{ | |||
int nbuf; | |||
nt_realdacblksize = (blocksize ? blocksize : DEFREALDACBLKSIZE); | |||
nbuf = sys_advance_samples/nt_realdacblksize; | |||
if (nbuf >= MAXBUFFER) | |||
{ | |||
fprintf(stderr, "pd: audio buffering maxed out to %d\n", | |||
(int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.))); | |||
nbuf = MAXBUFFER; | |||
} | |||
else if (nbuf < 4) nbuf = 4; | |||
/* fprintf(stderr, "%d audio buffers\n", nbuf); */ | |||
nt_naudiobuffer = nbuf; | |||
if (nt_adcjitterbufsallowed > nbuf - 2) | |||
nt_adcjitterbufsallowed = nbuf - 2; | |||
if (nt_dacjitterbufsallowed > nbuf - 2) | |||
nt_dacjitterbufsallowed = nbuf - 2; | |||
nt_nwavein = STUFF->st_inchannels / 2; | |||
nt_nwaveout = STUFF->st_outchannels / 2; | |||
nt_whichadc = (naudioindev < 1 ? | |||
(nt_nwavein > 1 ? WAVE_MAPPER : -1) : audioindev[0]); | |||
nt_whichdac = (naudiooutdev < 1 ? | |||
(nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]); | |||
if (naudiooutdev > 1 || naudioindev > 1) | |||
post("separate audio device choice not supported; using sequential devices."); | |||
return (mmio_do_open_audio()); | |||
} | |||
void mmio_reportidle(void) | |||
{ | |||
} | |||
#if 0 | |||
/* list the audio and MIDI device names */ | |||
void mmio_listdevs(void) | |||
{ | |||
UINT wRtn, ndevices; | |||
unsigned int i; | |||
ndevices = waveInGetNumDevs(); | |||
for (i = 0; i < ndevices; i++) | |||
{ | |||
WAVEINCAPS wicap; | |||
wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, | |||
sizeof(wicap)); | |||
if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn); | |||
else fprintf(stderr, | |||
"audio input device #%d: %s\n", i+1, wicap.szPname); | |||
} | |||
ndevices = waveOutGetNumDevs(); | |||
for (i = 0; i < ndevices; i++) | |||
{ | |||
WAVEOUTCAPS wocap; | |||
wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, | |||
sizeof(wocap)); | |||
if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn); | |||
else fprintf(stderr, | |||
"audio output device #%d: %s\n", i+1, wocap.szPname); | |||
} | |||
} | |||
#endif | |||
void mmio_getdevs(char *indevlist, int *nindevs, | |||
char *outdevlist, int *noutdevs, int *canmulti, | |||
int maxndev, int devdescsize) | |||
{ | |||
int wRtn, ndev, i; | |||
*canmulti = 2; /* supports multiple devices */ | |||
ndev = waveInGetNumDevs(); | |||
if (ndev > maxndev) | |||
ndev = maxndev; | |||
*nindevs = ndev; | |||
for (i = 0; i < ndev; i++) | |||
{ | |||
WAVEINCAPS wicap; | |||
wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap)); | |||
_snprintf(indevlist + i * devdescsize, devdescsize, "%s", | |||
(wRtn ? "???" : wicap.szPname)); | |||
outdevlist[(i+1) * devdescsize - 1] = 0; | |||
} | |||
ndev = waveOutGetNumDevs(); | |||
if (ndev > maxndev) | |||
ndev = maxndev; | |||
*noutdevs = ndev; | |||
for (i = 0; i < ndev; i++) | |||
{ | |||
WAVEOUTCAPS wocap; | |||
wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap)); | |||
_snprintf(outdevlist + i * devdescsize, devdescsize, "%s", | |||
(wRtn ? "???" : wocap.szPname)); | |||
outdevlist[(i+1) * devdescsize - 1] = 0; | |||
} | |||
} |
@@ -0,0 +1,795 @@ | |||
/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler, | |||
* Winfried Ritsch, Karl MacMillan, and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* this file inputs and outputs audio using the OSS API available on linux. */ | |||
#include <sys/soundcard.h> | |||
#ifndef SNDCTL_DSP_GETISPACE | |||
#define SNDCTL_DSP_GETISPACE SOUND_PCM_GETISPACE | |||
#endif | |||
#ifndef SNDCTL_DSP_GETOSPACE | |||
#define SNDCTL_DSP_GETOSPACE SOUND_PCM_GETOSPACE | |||
#endif | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/types.h> | |||
#include <sys/time.h> | |||
#include <sys/stat.h> | |||
#include <sys/ioctl.h> | |||
#include <fcntl.h> | |||
#include <sched.h> | |||
#include <sys/mman.h> | |||
/* Defines */ | |||
#define DEBUG(x) x | |||
#define DEBUG2(x) {x;} | |||
#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */ | |||
#define OSS_MAXDEV 4 /* maximum number of input or output devices */ | |||
#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */ | |||
#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */ | |||
#define OSS_DEFAULTCH 2 | |||
#define RME_DEFAULTCH 8 /* need this even if RME undefined */ | |||
typedef int16_t t_oss_int16; | |||
typedef int32_t t_oss_int32; | |||
#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32) | |||
#define OSS_BYTESPERCHAN(width) (DEFDACBLKSIZE * (width)) | |||
#define OSS_XFERSAMPS(chans) (DEFDACBLKSIZE* (chans)) | |||
#define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width)) | |||
/* GLOBALS */ | |||
static int linux_meters; /* true if we're metering */ | |||
static t_sample linux_inmax; /* max input amplitude */ | |||
static t_sample linux_outmax; /* max output amplitude */ | |||
static int linux_fragsize = 0; /* for block mode; block size (sample frames) */ | |||
extern int audio_blocksize; /* stolen from s_audio.c */ | |||
/* our device handles */ | |||
typedef struct _oss_dev | |||
{ | |||
int d_fd; | |||
unsigned int d_space; /* bytes available for writing/reading */ | |||
int d_bufsize; /* total buffer size in blocks for this device */ | |||
int d_dropcount; /* # of buffers to drop for resync (output only) */ | |||
unsigned int d_nchannels; /* number of channels for this device */ | |||
unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */ | |||
} t_oss_dev; | |||
static t_oss_dev linux_dacs[OSS_MAXDEV]; | |||
static t_oss_dev linux_adcs[OSS_MAXDEV]; | |||
static int linux_noutdevs = 0; | |||
static int linux_nindevs = 0; | |||
/* OSS-specific private variables */ | |||
static int oss_blockmode = 1; /* flag to use "blockmode" */ | |||
static char ossdsp[] = "/dev/dsp%d"; | |||
/* don't assume we can turn all 31 bits when doing float-to-fix; | |||
otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */ | |||
#define FMAX 0x7ffff000 | |||
#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x)) | |||
/* ---------------- public routines ----------------------- */ | |||
static int oss_ndev = 0; | |||
/* find out how many OSS devices we have. Since this has to | |||
open the devices to find out if they're there, we have | |||
to be called before audio is actually started up. So we | |||
cache the results, which in effect are the number of available | |||
devices. */ | |||
void oss_init(void) | |||
{ | |||
int fd, i; | |||
static int countedthem = 0; | |||
if (countedthem) | |||
return; | |||
for (i = 0; i < 10; i++) | |||
{ | |||
char devname[100]; | |||
if (i == 0) | |||
strcpy(devname, "/dev/dsp"); | |||
else sprintf(devname, "/dev/dsp%d", i); | |||
if ( (fd = open(devname, O_WRONLY|O_NONBLOCK)) != -1) | |||
{ | |||
oss_ndev++; | |||
close(fd); | |||
} | |||
else break; | |||
} | |||
countedthem = 1; | |||
} | |||
typedef struct _multidev { | |||
int fd; | |||
int channels; | |||
int format; | |||
} t_multidev; | |||
int oss_reset(int fd) { | |||
int err; | |||
if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0) | |||
error("OSS: Could not reset"); | |||
return err; | |||
} | |||
void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize, | |||
int suggestedblocksize) | |||
{ | |||
int orig, param, nblk, fd = dev->d_fd, wantformat; | |||
int nchannels = dev->d_nchannels; | |||
int advwas = sys_schedadvance; | |||
audio_buf_info ainfo; | |||
/* we only know how to do 2 byte samples */ | |||
wantformat = AFMT_S16_NE; | |||
dev->d_bytespersamp = 2; | |||
param = wantformat; | |||
if (ioctl(fd, SNDCTL_DSP_SETFMT, ¶m) == -1) | |||
fprintf(stderr,"OSS: Could not set DSP format\n"); | |||
else if (wantformat != param) | |||
fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n", | |||
wantformat, param); | |||
/* sample rate */ | |||
orig = param = srate; | |||
if (ioctl(fd, SNDCTL_DSP_SPEED, ¶m) == -1) | |||
fprintf(stderr,"OSS: Could not set sampling rate for device\n"); | |||
else if( orig != param ) | |||
fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n", | |||
orig, param ); | |||
if (oss_blockmode && !skipblocksize) | |||
{ | |||
int fragbytes, logfragsize, nfragment; | |||
/* setting fragment count and size. */ | |||
linux_fragsize = suggestedblocksize; | |||
if (!linux_fragsize) | |||
{ | |||
linux_fragsize = OSS_DEFFRAGSIZE; | |||
while (linux_fragsize > DEFDACBLKSIZE | |||
&& linux_fragsize * 6 > sys_advance_samples) | |||
linux_fragsize = linux_fragsize/2; | |||
} | |||
/* post("adv_samples %d", sys_advance_samples); */ | |||
nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize; | |||
fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels); | |||
logfragsize = ilog2(fragbytes); | |||
if (fragbytes != (1 << logfragsize)) | |||
post("warning: OSS takes only power of 2 blocksize; using %d", | |||
(1 << logfragsize)/(dev->d_bytespersamp * nchannels)); | |||
if (sys_verbose) | |||
post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes); | |||
param = orig = (nfragment<<16) + logfragsize; | |||
if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, ¶m) == -1) | |||
error("OSS: Could not set or read fragment size\n"); | |||
if (param != orig) | |||
{ | |||
nfragment = ((param >> 16) & 0xffff); | |||
logfragsize = (param & 0xffff); | |||
post("warning: actual fragments %d, blocksize %d", | |||
nfragment, (1 << logfragsize)); | |||
} | |||
if (sys_verbose) | |||
post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance)); | |||
} | |||
if (dac) | |||
{ | |||
/* use "free space" to learn the buffer size. Normally you | |||
should set this to your own desired value; but this seems not | |||
to be implemented uniformly across different sound cards. LATER | |||
we should figure out what to do if the requested scheduler advance | |||
is greater than this buffer size; for now, we just print something | |||
out. */ | |||
int defect; | |||
if (ioctl(fd, SNDCTL_DSP_GETOSPACE,&ainfo) < 0) | |||
fprintf(stderr,"OSS: ioctl on output device failed"); | |||
dev->d_bufsize = ainfo.bytes; | |||
defect = sys_advance_samples * (dev->d_bytespersamp * nchannels) | |||
- dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp); | |||
if (defect > 0) | |||
{ | |||
if (sys_verbose || defect > (dev->d_bufsize >> 2)) | |||
fprintf(stderr, | |||
"OSS: requested audio buffer size %d limited to %d\n", | |||
sys_advance_samples * (dev->d_bytespersamp * nchannels), | |||
dev->d_bufsize); | |||
sys_advance_samples = | |||
(dev->d_bufsize - OSS_XFERSAMPS(nchannels)) / | |||
(dev->d_bytespersamp *nchannels); | |||
} | |||
} | |||
} | |||
static int oss_setchannels(int fd, int wantchannels, char *devname) | |||
{ | |||
int param; | |||
if (sys_verbose) | |||
post("setchan %d", wantchannels); | |||
if (ioctl(fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) | |||
{ | |||
if (sys_verbose) | |||
error("OSS: SOUND_DSP_READ_CHANNELS failed %s", devname); | |||
} | |||
else | |||
{ | |||
if (sys_verbose) | |||
post("channels originally %d for %s", param, devname); | |||
if (param == wantchannels) | |||
{ | |||
if (sys_verbose) | |||
post("number of channels doesn't need setting\n"); | |||
return (wantchannels); | |||
} | |||
} | |||
param = wantchannels; | |||
whynot: | |||
while (param > 1) | |||
{ | |||
int save = param; | |||
if (ioctl(fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) | |||
error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname); | |||
else if (param == save) | |||
return (param); | |||
param = save - 1; | |||
} | |||
return (0); | |||
} | |||
int oss_open_audio(int nindev, int *indev, int nchin, int *chin, | |||
int noutdev, int *outdev, int nchout, int *chout, int rate, | |||
int blocksize) | |||
{ | |||
int capabilities = 0; | |||
int inchannels = 0, outchannels = 0; | |||
char devname[20]; | |||
int n, i, fd, flags; | |||
char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; | |||
int num_devs = 0; | |||
int wantmore=0; | |||
int spread = 0; | |||
audio_buf_info ainfo; | |||
linux_nindevs = linux_noutdevs = 0; | |||
/* mark devices unopened */ | |||
for (i = 0; i < OSS_MAXDEV; i++) | |||
linux_adcs[i].d_fd = linux_dacs[i].d_fd = -1; | |||
/* open output devices */ | |||
wantmore=0; | |||
if (noutdev < 0 || nindev < 0) | |||
bug("linux_open_audio"); | |||
for (n = 0; n < noutdev; n++) | |||
{ | |||
int gotchans, j, inindex = -1; | |||
int thisdevice = (outdev[n] >= 0 ? outdev[n] : 0); | |||
int wantchannels = (nchout>n) ? chout[n] : wantmore; | |||
fd = -1; | |||
if (!wantchannels) | |||
goto end_out_loop; | |||
if (thisdevice > 0) | |||
sprintf(devname, "/dev/dsp%d", thisdevice); | |||
else sprintf(devname, "/dev/dsp"); | |||
/* search for input request for same device. Succeed only | |||
if the number of channels matches. */ | |||
for (j = 0; j < nindev; j++) | |||
if (indev[j] == thisdevice && chin[j] == wantchannels) | |||
inindex = j; | |||
/* if the same device is requested for input and output, | |||
try to open it read/write */ | |||
if (inindex >= 0) | |||
{ | |||
sys_setalarm(1000000); | |||
if ((fd = open(devname, O_RDWR | O_NDELAY)) == -1) | |||
{ | |||
post("%s (read/write): %s", devname, strerror(errno)); | |||
post("(now will try write-only...)"); | |||
} | |||
else | |||
{ | |||
if (fcntl(fd, F_SETFD, 1) < 0) | |||
post("couldn't set close-on-exec flag on audio"); | |||
if ((flags = fcntl(fd, F_GETFL)) < 0) | |||
post("couldn't get audio device flags"); | |||
else if (fcntl(fd, F_SETFL, flags & (~O_NDELAY)) < 0) | |||
post("couldn't set audio device flags"); | |||
if (sys_verbose) | |||
post("opened %s for reading and writing\n", devname); | |||
linux_adcs[inindex].d_fd = fd; | |||
} | |||
} | |||
/* if that didn't happen or if it failed, try write-only */ | |||
if (fd == -1) | |||
{ | |||
sys_setalarm(1000000); | |||
if ((fd = open(devname, O_WRONLY | O_NDELAY)) == -1) | |||
{ | |||
post("%s (writeonly): %s", | |||
devname, strerror(errno)); | |||
break; | |||
} | |||
if (fcntl(fd, F_SETFD, 1) < 0) | |||
post("couldn't set close-on-exec flag on audio"); | |||
if ((flags = fcntl(fd, F_GETFL)) < 0) | |||
post("couldn't get audio device flags"); | |||
else if (fcntl(fd, F_SETFL, flags & (~O_NDELAY)) < 0) | |||
post("couldn't set audio device flags"); | |||
if (sys_verbose) | |||
post("opened %s for writing only\n", devname); | |||
} | |||
if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1) | |||
error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname); | |||
gotchans = oss_setchannels(fd, | |||
(wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, | |||
devname); | |||
if (sys_verbose) | |||
post("opened audio output on %s; got %d channels", | |||
devname, gotchans); | |||
if (gotchans < 2) | |||
{ | |||
/* can't even do stereo? just give up. */ | |||
close(fd); | |||
} | |||
else | |||
{ | |||
linux_dacs[linux_noutdevs].d_nchannels = gotchans; | |||
linux_dacs[linux_noutdevs].d_fd = fd; | |||
oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0, blocksize); | |||
linux_noutdevs++; | |||
outchannels += gotchans; | |||
if (inindex >= 0) | |||
{ | |||
linux_adcs[inindex].d_nchannels = gotchans; | |||
chin[inindex] = gotchans; | |||
} | |||
} | |||
/* LATER think about spreading large numbers of channels over | |||
various dsp's and vice-versa */ | |||
wantmore = wantchannels - gotchans; | |||
end_out_loop: ; | |||
} | |||
/* open input devices */ | |||
wantmore = 0; | |||
for (n = 0; n < nindev; n++) | |||
{ | |||
int gotchans=0; | |||
int thisdevice = (indev[n] >= 0 ? indev[n] : 0); | |||
int wantchannels = (nchin>n)?chin[n]:wantmore; | |||
int alreadyopened = 0; | |||
if (!wantchannels) | |||
goto end_in_loop; | |||
if (thisdevice > 0) | |||
sprintf(devname, "/dev/dsp%d", thisdevice); | |||
else sprintf(devname, "/dev/dsp"); | |||
sys_setalarm(1000000); | |||
/* perhaps it's already open from the above? */ | |||
if (linux_adcs[n].d_fd >= 0) | |||
{ | |||
fd = linux_adcs[n].d_fd; | |||
alreadyopened = 1; | |||
if (sys_verbose) | |||
post("already opened it"); | |||
} | |||
else | |||
{ | |||
/* otherwise try to open it here. */ | |||
if ((fd = open(devname, O_RDONLY | O_NDELAY)) == -1) | |||
{ | |||
post("%s (readonly): %s", devname, strerror(errno)); | |||
goto end_in_loop; | |||
} | |||
if (fcntl(fd, F_SETFD, 1) < 0) | |||
post("couldn't set close-on-exec flag on audio"); | |||
if ((flags = fcntl(fd, F_GETFL)) < 0) | |||
post("couldn't get audio device flags"); | |||
else if (fcntl(fd, F_SETFL, flags & (~O_NDELAY)) < 0) | |||
post("couldn't set audio device flags"); | |||
if (sys_verbose) | |||
post("opened %s for reading only\n", devname); | |||
} | |||
linux_adcs[linux_nindevs].d_fd = fd; | |||
gotchans = oss_setchannels(fd, | |||
(wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, | |||
devname); | |||
if (sys_verbose) | |||
post("opened audio input device %s; got %d channels", | |||
devname, gotchans); | |||
if (gotchans < 1) | |||
{ | |||
close(fd); | |||
goto end_in_loop; | |||
} | |||
linux_adcs[linux_nindevs].d_nchannels = gotchans; | |||
oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened, | |||
blocksize); | |||
inchannels += gotchans; | |||
linux_nindevs++; | |||
wantmore = wantchannels-gotchans; | |||
/* LATER think about spreading large numbers of channels over | |||
various dsp's and vice-versa */ | |||
end_in_loop: ; | |||
} | |||
/* We have to do a read to start the engine. This is | |||
necessary because sys_send_dacs waits until the input | |||
buffer is filled and only reads on a filled buffer. | |||
This is good, because it's a way to make sure that we | |||
will not block. But I wonder why we only have to read | |||
from one of the devices and not all of them??? */ | |||
if (linux_nindevs) | |||
{ | |||
if (sys_verbose) | |||
fprintf(stderr,("OSS: issuing first ADC 'read' ... ")); | |||
read(linux_adcs[0].d_fd, buf, | |||
linux_adcs[0].d_bytespersamp * | |||
linux_adcs[0].d_nchannels * DEFDACBLKSIZE); | |||
if (sys_verbose) | |||
fprintf(stderr, "...done.\n"); | |||
} | |||
/* now go and fill all the output buffers. */ | |||
for (i = 0; i < linux_noutdevs; i++) | |||
{ | |||
int j; | |||
memset(buf, 0, linux_dacs[i].d_bytespersamp * | |||
linux_dacs[i].d_nchannels * DEFDACBLKSIZE); | |||
for (j = 0; j < sys_advance_samples/DEFDACBLKSIZE; j++) | |||
write(linux_dacs[i].d_fd, buf, | |||
linux_dacs[i].d_bytespersamp * | |||
linux_dacs[i].d_nchannels * DEFDACBLKSIZE); | |||
} | |||
sys_setalarm(0); | |||
STUFF->st_inchannels = inchannels; | |||
STUFF->st_outchannels = outchannels; | |||
return (0); | |||
} | |||
void oss_close_audio( void) | |||
{ | |||
int i; | |||
for (i=0;i<linux_nindevs;i++) | |||
close(linux_adcs[i].d_fd); | |||
for (i=0;i<linux_noutdevs;i++) | |||
close(linux_dacs[i].d_fd); | |||
linux_nindevs = linux_noutdevs = 0; | |||
} | |||
static int linux_dacs_write(int fd,void* buf,long bytes) | |||
{ | |||
return write(fd, buf, bytes); | |||
} | |||
static int linux_adcs_read(int fd,void* buf,long bytes) | |||
{ | |||
return read(fd, buf, bytes); | |||
} | |||
/* query audio devices for "available" data size. */ | |||
static void oss_calcspace(void) | |||
{ | |||
int dev; | |||
audio_buf_info ainfo; | |||
for (dev=0; dev < linux_noutdevs; dev++) | |||
{ | |||
if (ioctl(linux_dacs[dev].d_fd, SNDCTL_DSP_GETOSPACE, &ainfo) < 0) | |||
fprintf(stderr,"OSS: ioctl on output device %d failed",dev); | |||
linux_dacs[dev].d_space = ainfo.bytes; | |||
} | |||
for (dev = 0; dev < linux_nindevs; dev++) | |||
{ | |||
if (ioctl(linux_adcs[dev].d_fd, SNDCTL_DSP_GETISPACE,&ainfo) < 0) | |||
fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed", | |||
dev, linux_adcs[dev].d_fd); | |||
linux_adcs[dev].d_space = ainfo.bytes; | |||
} | |||
} | |||
void linux_audiostatus(void) | |||
{ | |||
int dev; | |||
if (!oss_blockmode) | |||
{ | |||
oss_calcspace(); | |||
for (dev=0; dev < linux_noutdevs; dev++) | |||
fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space); | |||
for (dev = 0; dev < linux_nindevs; dev++) | |||
fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space); | |||
} | |||
} | |||
/* this call resyncs audio output and input which will cause discontinuities | |||
in audio output and/or input. */ | |||
static void oss_doresync( void) | |||
{ | |||
int dev, zeroed = 0, wantsize; | |||
char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; | |||
audio_buf_info ainfo; | |||
/* 1. if any input devices are ahead (have more than 1 buffer stored), | |||
drop one or more buffers worth */ | |||
for (dev = 0; dev < linux_nindevs; dev++) | |||
{ | |||
if (linux_adcs[dev].d_space == 0) | |||
{ | |||
linux_adcs_read(linux_adcs[dev].d_fd, buf, | |||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | |||
linux_adcs[dev].d_bytespersamp)); | |||
} | |||
else while (linux_adcs[dev].d_space > | |||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | |||
linux_adcs[dev].d_bytespersamp)) | |||
{ | |||
linux_adcs_read(linux_adcs[dev].d_fd, buf, | |||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | |||
linux_adcs[dev].d_bytespersamp)); | |||
if (ioctl(linux_adcs[dev].d_fd, SNDCTL_DSP_GETISPACE, &ainfo) < 0) | |||
{ | |||
fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed", | |||
dev, linux_adcs[dev].d_fd); | |||
break; | |||
} | |||
linux_adcs[dev].d_space = ainfo.bytes; | |||
} | |||
} | |||
/* 2. if any output devices are behind, feed them zeros to catch them | |||
up */ | |||
for (dev = 0; dev < linux_noutdevs; dev++) | |||
{ | |||
while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize - | |||
sys_advance_samples * (linux_dacs[dev].d_nchannels * | |||
linux_dacs[dev].d_bytespersamp)) | |||
{ | |||
if (!zeroed) | |||
{ | |||
unsigned int i; | |||
for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels); | |||
i++) | |||
buf[i] = 0; | |||
zeroed = 1; | |||
} | |||
linux_dacs_write(linux_dacs[dev].d_fd, buf, | |||
OSS_XFERSIZE(linux_dacs[dev].d_nchannels, | |||
linux_dacs[dev].d_bytespersamp)); | |||
if (ioctl(linux_dacs[dev].d_fd, SNDCTL_DSP_GETOSPACE, &ainfo) < 0) | |||
{ | |||
fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed", | |||
dev, linux_dacs[dev].d_fd); | |||
break; | |||
} | |||
linux_dacs[dev].d_space = ainfo.bytes; | |||
} | |||
} | |||
/* 3. if any DAC devices are too far ahead, plan to drop the | |||
number of frames which will let the others catch up. */ | |||
for (dev = 0; dev < linux_noutdevs; dev++) | |||
{ | |||
if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize - | |||
(sys_advance_samples - 1) * linux_dacs[dev].d_nchannels * | |||
linux_dacs[dev].d_bytespersamp) | |||
{ | |||
linux_dacs[dev].d_dropcount = sys_advance_samples - 1 - | |||
(linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) / | |||
(linux_dacs[dev].d_nchannels * | |||
linux_dacs[dev].d_bytespersamp) ; | |||
} | |||
else linux_dacs[dev].d_dropcount = 0; | |||
} | |||
} | |||
int oss_send_dacs(void) | |||
{ | |||
t_sample *fp1, *fp2; | |||
long fill; | |||
int i, j, dev, rtnval = SENDDACS_YES; | |||
char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; | |||
t_oss_int16 *sp; | |||
t_oss_int32 *lp; | |||
/* the maximum number of samples we should have in the ADC buffer */ | |||
int idle = 0; | |||
int thischan; | |||
double timeref, timenow; | |||
if (!linux_nindevs && !linux_noutdevs) | |||
return (SENDDACS_NO); | |||
if (!oss_blockmode) | |||
{ | |||
/* determine whether we're idle. This is true if either (1) | |||
some input device has less than one buffer to read or (2) some | |||
output device has fewer than (sys_advance_samples) blocks buffered | |||
already. */ | |||
oss_calcspace(); | |||
for (dev=0; dev < linux_noutdevs; dev++) | |||
if (linux_dacs[dev].d_dropcount || | |||
(linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space > | |||
sys_advance_samples * linux_dacs[dev].d_bytespersamp * | |||
linux_dacs[dev].d_nchannels)) | |||
idle = 1; | |||
for (dev=0; dev < linux_nindevs; dev++) | |||
if (linux_adcs[dev].d_space < | |||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | |||
linux_adcs[dev].d_bytespersamp)) | |||
idle = 1; | |||
} | |||
if (idle && !oss_blockmode) | |||
{ | |||
/* sometimes---rarely---when the ADC available-byte-count is | |||
zero, it's genuine, but usually it's because we're so | |||
late that the ADC has overrun its entire kernel buffer. We | |||
distinguish between the two by waiting 2 msec and asking again. | |||
There should be an error flag we could check instead; look for this | |||
someday... */ | |||
for (dev = 0;dev < linux_nindevs; dev++) | |||
if (linux_adcs[dev].d_space == 0) | |||
{ | |||
audio_buf_info ainfo; | |||
sys_microsleep(2000); | |||
oss_calcspace(); | |||
if (linux_adcs[dev].d_space != 0) continue; | |||
/* here's the bad case. Give up and resync. */ | |||
sys_log_error(ERR_DATALATE); | |||
oss_doresync(); | |||
return (SENDDACS_NO); | |||
} | |||
/* check for slippage between devices, either because | |||
data got lost in the driver from a previous late condition, or | |||
because the devices aren't synced. When we're idle, no | |||
input device should have more than one buffer readable and | |||
no output device should have less than sys_advance_samples-1 | |||
*/ | |||
for (dev=0; dev < linux_noutdevs; dev++) | |||
if (!linux_dacs[dev].d_dropcount && | |||
(linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space < | |||
(sys_advance_samples - 2) * | |||
(linux_dacs[dev].d_bytespersamp * | |||
linux_dacs[dev].d_nchannels))) | |||
goto badsync; | |||
for (dev=0; dev < linux_nindevs; dev++) | |||
if (linux_adcs[dev].d_space > 3 * | |||
OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | |||
linux_adcs[dev].d_bytespersamp)) | |||
goto badsync; | |||
/* return zero to tell the scheduler we're idle. */ | |||
return (SENDDACS_NO); | |||
badsync: | |||
sys_log_error(ERR_RESYNC); | |||
oss_doresync(); | |||
return (SENDDACS_NO); | |||
} | |||
/* do output */ | |||
timeref = sys_getrealtime(); | |||
for (dev=0, thischan = 0; dev < linux_noutdevs; dev++) | |||
{ | |||
int nchannels = linux_dacs[dev].d_nchannels; | |||
if (linux_dacs[dev].d_dropcount) | |||
linux_dacs[dev].d_dropcount--; | |||
else | |||
{ | |||
if (linux_dacs[dev].d_bytespersamp == 2) | |||
{ | |||
for (i = DEFDACBLKSIZE, fp1 = STUFF->st_soundout + | |||
DEFDACBLKSIZE*thischan, | |||
sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) | |||
{ | |||
for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE) | |||
{ | |||
int s = *fp2 * 32767.; | |||
if (s > 32767) s = 32767; | |||
else if (s < -32767) s = -32767; | |||
sp[j] = s; | |||
} | |||
} | |||
} | |||
linux_dacs_write(linux_dacs[dev].d_fd, buf, | |||
OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp)); | |||
if ((timenow = sys_getrealtime()) - timeref > 0.002) | |||
{ | |||
if (!oss_blockmode) | |||
sys_log_error(ERR_DACSLEPT); | |||
else rtnval = SENDDACS_SLEPT; | |||
} | |||
timeref = timenow; | |||
} | |||
thischan += nchannels; | |||
} | |||
memset(STUFF->st_soundout, 0, | |||
STUFF->st_outchannels * (sizeof(t_sample) * DEFDACBLKSIZE)); | |||
/* do input */ | |||
for (dev = 0, thischan = 0; dev < linux_nindevs; dev++) | |||
{ | |||
int nchannels = linux_adcs[dev].d_nchannels; | |||
linux_adcs_read(linux_adcs[dev].d_fd, buf, | |||
OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp)); | |||
if ((timenow = sys_getrealtime()) - timeref > 0.002) | |||
{ | |||
if (!oss_blockmode) | |||
sys_log_error(ERR_ADCSLEPT); | |||
else | |||
rtnval = SENDDACS_SLEPT; | |||
} | |||
timeref = timenow; | |||
if (linux_adcs[dev].d_bytespersamp == 2) | |||
{ | |||
for (i = DEFDACBLKSIZE,fp1 = STUFF->st_soundin + thischan*DEFDACBLKSIZE, | |||
sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) | |||
{ | |||
for (j=0;j<nchannels;j++) | |||
fp1[j*DEFDACBLKSIZE] = (float)sp[j]*(float)3.051850e-05; | |||
} | |||
} | |||
thischan += nchannels; | |||
} | |||
return (rtnval); | |||
} | |||
void oss_getdevs(char *indevlist, int *nindevs, | |||
char *outdevlist, int *noutdevs, int *canmulti, | |||
int maxndev, int devdescsize) | |||
{ | |||
int i, ndev; | |||
*canmulti = 2; /* supports multiple devices */ | |||
if ((ndev = oss_ndev) > maxndev) | |||
ndev = maxndev; | |||
for (i = 0; i < ndev; i++) | |||
{ | |||
sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1); | |||
sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1); | |||
} | |||
*nindevs = *noutdevs = ndev; | |||
} |
@@ -0,0 +1,642 @@ | |||
/* Copyright (c) 2001 Miller Puckette and others. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's | |||
the main way in for Mac OS and, with Michael Casey's help, also into | |||
ASIO in Windows. | |||
Both blocking and non-blocking call styles are supported. If non-blocking | |||
is requested, either we call portaudio in non-blocking mode, or else we | |||
call portaudio in callback mode and manage our own FIFO se we can offer | |||
Pd "blocking" I/O calls. To do the latter we define FAKEBLOCKING; this | |||
works better in MAXOSX (gets 40 msec lower latency!) and might also in | |||
Windows. If FAKEBLOCKING is defined we can choose between two methods | |||
for waiting on the (presumebly other-thread) I/O to complete, either | |||
correct thread synchronization (by defining THREADSIGNAL) or just sleeping | |||
and polling; the latter seems to work better so far. | |||
*/ | |||
/* dolist... | |||
switch to usleep in s_inter.c | |||
*/ | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <fcntl.h> | |||
#include <portaudio.h> | |||
#ifdef _MSC_VER | |||
#define snprintf _snprintf | |||
#endif | |||
#ifndef _WIN32 /* for the "dup2" workaround -- do we still need it? */ | |||
#include <unistd.h> | |||
#endif | |||
#ifdef _WIN32 | |||
# include <malloc.h> /* MSVC or mingw on windows */ | |||
#elif defined(__linux__) || defined(__APPLE__) | |||
# include <alloca.h> /* linux, mac, mingw, cygwin */ | |||
#else | |||
# include <stdlib.h> /* BSDs for example */ | |||
#endif | |||
#if 1 | |||
#define FAKEBLOCKING | |||
#endif | |||
#if defined (FAKEBLOCKING) && defined(_WIN32) | |||
#include <windows.h> /* for Sleep() */ | |||
#endif | |||
/* define this to enable thread signaling instead of polling */ | |||
/* #define THREADSIGNAL */ | |||
/* LATER try to figure out how to handle default devices in portaudio; | |||
the way s_audio.c handles them isn't going to work here. */ | |||
/* public interface declared in m_imp.h */ | |||
/* implementation */ | |||
static PaStream *pa_stream; | |||
static int pa_inchans, pa_outchans; | |||
static float *pa_soundin, *pa_soundout; | |||
static t_audiocallback pa_callback; | |||
static int pa_started; | |||
static int pa_nbuffers; | |||
static int pa_dio_error; | |||
#ifdef FAKEBLOCKING | |||
#include "s_audio_paring.h" | |||
static PA_VOLATILE char *pa_outbuf; | |||
static PA_VOLATILE sys_ringbuf pa_outring; | |||
static PA_VOLATILE char *pa_inbuf; | |||
static PA_VOLATILE sys_ringbuf pa_inring; | |||
#ifdef THREADSIGNAL | |||
#include <pthread.h> | |||
pthread_mutex_t pa_mutex; | |||
pthread_cond_t pa_sem; | |||
#endif /* THREADSIGNAL */ | |||
#endif /* FAKEBLOCKING */ | |||
static void pa_init(void) /* Initialize PortAudio */ | |||
{ | |||
static int initialized; | |||
if (!initialized) | |||
{ | |||
#ifdef __APPLE__ | |||
/* for some reason, on the Mac Pa_Initialize() closes file descriptor | |||
1 (standard output) As a workaround, dup it to another number and dup2 | |||
it back afterward. */ | |||
int newfd = dup(1); | |||
int another = open("/dev/null", 0); | |||
dup2(another, 1); | |||
int err = Pa_Initialize(); | |||
close(1); | |||
close(another); | |||
if (newfd >= 0) | |||
{ | |||
fflush(stdout); | |||
dup2(newfd, 1); | |||
close(newfd); | |||
} | |||
#else | |||
int err = Pa_Initialize(); | |||
#endif | |||
if ( err != paNoError ) | |||
{ | |||
post("Error opening audio: %s", err, Pa_GetErrorText(err)); | |||
return; | |||
} | |||
initialized = 1; | |||
} | |||
} | |||
static int pa_lowlevel_callback(const void *inputBuffer, | |||
void *outputBuffer, unsigned long nframes, | |||
const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags myflags, | |||
void *userData) | |||
{ | |||
int i; | |||
unsigned int n, j; | |||
float *fbuf, *fp2, *fp3, *soundiop; | |||
if (nframes % DEFDACBLKSIZE) | |||
{ | |||
post("warning: audio nframes %ld not a multiple of blocksize %d", | |||
nframes, (int)DEFDACBLKSIZE); | |||
nframes -= (nframes % DEFDACBLKSIZE); | |||
} | |||
for (n = 0; n < nframes; n += DEFDACBLKSIZE) | |||
{ | |||
if (inputBuffer != NULL) | |||
{ | |||
fbuf = ((float *)inputBuffer) + n*pa_inchans; | |||
soundiop = pa_soundin; | |||
for (i = 0, fp2 = fbuf; i < pa_inchans; i++, fp2++) | |||
for (j = 0, fp3 = fp2; j < DEFDACBLKSIZE; | |||
j++, fp3 += pa_inchans) | |||
*soundiop++ = *fp3; | |||
} | |||
else memset((void *)pa_soundin, 0, | |||
DEFDACBLKSIZE * pa_inchans * sizeof(float)); | |||
memset((void *)pa_soundout, 0, | |||
DEFDACBLKSIZE * pa_outchans * sizeof(float)); | |||
(*pa_callback)(); | |||
if (outputBuffer != NULL) | |||
{ | |||
fbuf = ((float *)outputBuffer) + n*pa_outchans; | |||
soundiop = pa_soundout; | |||
for (i = 0, fp2 = fbuf; i < pa_outchans; i++, fp2++) | |||
for (j = 0, fp3 = fp2; j < DEFDACBLKSIZE; | |||
j++, fp3 += pa_outchans) | |||
*fp3 = *soundiop++; | |||
} | |||
} | |||
return 0; | |||
} | |||
#ifdef FAKEBLOCKING | |||
/* callback for "non-callback" case in which we actualy open portaudio | |||
in callback mode but fake "blocking mode". We communicate with the | |||
main thread via FIFO. First read the audio output FIFO (which | |||
we sync on, not waiting for it but supplying zeros to the audio output if | |||
there aren't enough samples in the FIFO when we are called), then write | |||
to the audio input FIFO. The main thread will wait for the input fifo. | |||
We can either throw it a pthreads condition or just allow the main thread | |||
to poll for us; so far polling seems to work better. */ | |||
static int pa_fifo_callback(const void *inputBuffer, | |||
void *outputBuffer, unsigned long nframes, | |||
const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags myflags, | |||
void *userData) | |||
{ | |||
/* callback routine for non-callback client... throw samples into | |||
and read them out of a FIFO */ | |||
int ch; | |||
long fiforoom; | |||
float *fbuf; | |||
#if CHECKFIFOS | |||
if (pa_inchans * sys_ringbuf_getreadavailable(&pa_outring) != | |||
pa_outchans * sys_ringbuf_getwriteavailable(&pa_inring)) | |||
post("warning: in and out rings unequal (%d, %d)", | |||
sys_ringbuf_getreadavailable(&pa_outring), | |||
sys_ringbuf_getwriteavailable(&pa_inring)); | |||
#endif | |||
fiforoom = sys_ringbuf_getreadavailable(&pa_outring); | |||
if ((unsigned)fiforoom >= nframes*pa_outchans*sizeof(float)) | |||
{ | |||
if (outputBuffer) | |||
sys_ringbuf_read(&pa_outring, outputBuffer, | |||
nframes*pa_outchans*sizeof(float), pa_outbuf); | |||
else if (pa_outchans) | |||
post("audio error: no outputBuffer but output channels"); | |||
if (inputBuffer) | |||
sys_ringbuf_write(&pa_inring, inputBuffer, | |||
nframes*pa_inchans*sizeof(float), pa_inbuf); | |||
else if (pa_inchans) | |||
post("audio error: no inputBuffer but input channels"); | |||
} | |||
else | |||
{ /* PD could not keep up; generate zeros */ | |||
if (pa_started) | |||
pa_dio_error = 1; | |||
if (outputBuffer) | |||
{ | |||
for (ch = 0; ch < pa_outchans; ch++) | |||
{ | |||
unsigned long frame; | |||
fbuf = ((float *)outputBuffer) + ch; | |||
for (frame = 0; frame < nframes; frame++, fbuf += pa_outchans) | |||
*fbuf = 0; | |||
} | |||
} | |||
} | |||
#ifdef THREADSIGNAL | |||
pthread_mutex_lock(&pa_mutex); | |||
pthread_cond_signal(&pa_sem); | |||
pthread_mutex_unlock(&pa_mutex); | |||
#endif | |||
return 0; | |||
} | |||
#endif /* FAKEBLOCKING */ | |||
PaError pa_open_callback(double sampleRate, int inchannels, int outchannels, | |||
int framesperbuf, int nbuffers, int indeviceno, int outdeviceno, PaStreamCallback *callbackfn) | |||
{ | |||
long bytesPerSample; | |||
PaError err; | |||
PaStreamParameters instreamparams, outstreamparams; | |||
PaStreamParameters*p_instreamparams=0, *p_outstreamparams=0; | |||
/* fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n", | |||
nchannels, flags, nbuffers, framesperbuf); */ | |||
instreamparams.device = indeviceno; | |||
instreamparams.channelCount = inchannels; | |||
instreamparams.sampleFormat = paFloat32; | |||
instreamparams.hostApiSpecificStreamInfo = 0; | |||
outstreamparams.device = outdeviceno; | |||
outstreamparams.channelCount = outchannels; | |||
outstreamparams.sampleFormat = paFloat32; | |||
outstreamparams.hostApiSpecificStreamInfo = 0; | |||
#ifdef FAKEBLOCKING | |||
instreamparams.suggestedLatency = outstreamparams.suggestedLatency = 0; | |||
#else | |||
instreamparams.suggestedLatency = outstreamparams.suggestedLatency = | |||
nbuffers*framesperbuf/sampleRate; | |||
#endif /* FAKEBLOCKING */ | |||
if( inchannels>0 && indeviceno >= 0) | |||
p_instreamparams=&instreamparams; | |||
if( outchannels>0 && outdeviceno >= 0) | |||
p_outstreamparams=&outstreamparams; | |||
err=Pa_IsFormatSupported(p_instreamparams, p_outstreamparams, sampleRate); | |||
if (paFormatIsSupported != err) | |||
{ | |||
/* check whether we have to change the numbers of channel and/or samplerate */ | |||
const PaDeviceInfo* info = 0; | |||
double inRate=0, outRate=0; | |||
if (inchannels>0) | |||
{ | |||
if (NULL != (info = Pa_GetDeviceInfo( instreamparams.device ))) | |||
{ | |||
inRate=info->defaultSampleRate; | |||
if(info->maxInputChannels<inchannels) | |||
instreamparams.channelCount=info->maxInputChannels; | |||
} | |||
} | |||
if (outchannels>0) | |||
{ | |||
if (NULL != (info = Pa_GetDeviceInfo( outstreamparams.device ))) | |||
{ | |||
outRate=info->defaultSampleRate; | |||
if(info->maxOutputChannels<outchannels) | |||
outstreamparams.channelCount=info->maxOutputChannels; | |||
} | |||
} | |||
if (err == paInvalidSampleRate) | |||
{ | |||
sampleRate=outRate; | |||
} | |||
err=Pa_IsFormatSupported(p_instreamparams, p_outstreamparams, | |||
sampleRate); | |||
if (paFormatIsSupported != err) | |||
goto error; | |||
} | |||
err = Pa_OpenStream( | |||
&pa_stream, | |||
p_instreamparams, | |||
p_outstreamparams, | |||
sampleRate, | |||
framesperbuf, | |||
paNoFlag, /* portaudio will clip for us */ | |||
callbackfn, | |||
0); | |||
if (err != paNoError) | |||
goto error; | |||
err = Pa_StartStream(pa_stream); | |||
if (err != paNoError) | |||
{ | |||
post("error opening failed; closing audio stream: %s", | |||
Pa_GetErrorText(err)); | |||
pa_close_audio(); | |||
goto error; | |||
} | |||
STUFF->st_dacsr=sampleRate; | |||
return paNoError; | |||
error: | |||
pa_stream = NULL; | |||
return err; | |||
} | |||
int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, | |||
t_sample *soundout, int framesperbuf, int nbuffers, | |||
int indeviceno, int outdeviceno, t_audiocallback callbackfn) | |||
{ | |||
PaError err; | |||
int j, devno, pa_indev = -1, pa_outdev = -1; | |||
pa_callback = callbackfn; | |||
/* fprintf(stderr, "open callback %d\n", (callbackfn != 0)); */ | |||
pa_init(); | |||
/* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */ | |||
if (pa_stream) | |||
pa_close_audio(); | |||
if (inchans > 0) | |||
{ | |||
for (j = 0, devno = 0; j < Pa_GetDeviceCount(); j++) | |||
{ | |||
const PaDeviceInfo *info = Pa_GetDeviceInfo(j); | |||
if (info->maxInputChannels > 0) | |||
{ | |||
if (devno == indeviceno) | |||
{ | |||
if (inchans > info->maxInputChannels) | |||
inchans = info->maxInputChannels; | |||
pa_indev = j; | |||
break; | |||
} | |||
devno++; | |||
} | |||
} | |||
} | |||
if (outchans > 0) | |||
{ | |||
for (j = 0, devno = 0; j < Pa_GetDeviceCount(); j++) | |||
{ | |||
const PaDeviceInfo *info = Pa_GetDeviceInfo(j); | |||
if (info->maxOutputChannels > 0) | |||
{ | |||
if (devno == outdeviceno) | |||
{ | |||
if (outchans > info->maxOutputChannels) | |||
outchans = info->maxOutputChannels; | |||
pa_outdev = j; | |||
break; | |||
} | |||
devno++; | |||
} | |||
} | |||
} | |||
if (inchans > 0 && pa_indev == -1) | |||
inchans = 0; | |||
if (outchans > 0 && pa_outdev == -1) | |||
outchans = 0; | |||
if (sys_verbose) | |||
{ | |||
post("input device %d, channels %d", pa_indev, inchans); | |||
post("output device %d, channels %d", pa_outdev, outchans); | |||
post("framesperbuf %d, nbufs %d", framesperbuf, nbuffers); | |||
post("rate %d", rate); | |||
} | |||
pa_inchans = STUFF->st_inchannels = inchans; | |||
pa_outchans = STUFF->st_outchannels = outchans; | |||
pa_soundin = soundin; | |||
pa_soundout = soundout; | |||
#ifdef FAKEBLOCKING | |||
if (pa_inbuf) | |||
free((char *)pa_inbuf), pa_inbuf = 0; | |||
if (pa_outbuf) | |||
free((char *)pa_outbuf), pa_outbuf = 0; | |||
#endif | |||
if (! inchans && !outchans) | |||
return (0); | |||
if (callbackfn) | |||
{ | |||
pa_callback = callbackfn; | |||
err = pa_open_callback(rate, inchans, outchans, | |||
framesperbuf, nbuffers, pa_indev, pa_outdev, pa_lowlevel_callback); | |||
} | |||
else | |||
{ | |||
#ifdef FAKEBLOCKING | |||
if (pa_inchans) | |||
{ | |||
pa_inbuf = malloc(nbuffers*framesperbuf*pa_inchans*sizeof(float)); | |||
sys_ringbuf_init(&pa_inring, | |||
nbuffers*framesperbuf*pa_inchans*sizeof(float), pa_inbuf, | |||
nbuffers*framesperbuf*pa_inchans*sizeof(float)); | |||
} | |||
if (pa_outchans) | |||
{ | |||
pa_outbuf = malloc(nbuffers*framesperbuf*pa_outchans*sizeof(float)); | |||
sys_ringbuf_init(&pa_outring, | |||
nbuffers*framesperbuf*pa_outchans*sizeof(float), pa_outbuf, 0); | |||
} | |||
err = pa_open_callback(rate, inchans, outchans, | |||
framesperbuf, nbuffers, pa_indev, pa_outdev, pa_fifo_callback); | |||
#else | |||
err = pa_open_callback(rate, inchans, outchans, | |||
framesperbuf, nbuffers, pa_indev, pa_outdev, 0); | |||
#endif | |||
} | |||
pa_started = 0; | |||
pa_nbuffers = nbuffers; | |||
if ( err != paNoError ) | |||
{ | |||
post("Error opening audio: %s", Pa_GetErrorText(err)); | |||
/* Pa_Terminate(); */ | |||
return (1); | |||
} | |||
else if (sys_verbose) | |||
post("... opened OK."); | |||
return (0); | |||
} | |||
void pa_close_audio( void) | |||
{ | |||
if (pa_stream) | |||
{ | |||
Pa_AbortStream(pa_stream); | |||
Pa_CloseStream(pa_stream); | |||
} | |||
pa_stream = 0; | |||
#ifdef FAKEBLOCKING | |||
if (pa_inbuf) | |||
free((char *)pa_inbuf), pa_inbuf = 0; | |||
if (pa_outbuf) | |||
free((char *)pa_outbuf), pa_outbuf = 0; | |||
#endif | |||
} | |||
int pa_send_dacs(void) | |||
{ | |||
t_sample *fp; | |||
float *fp2, *fp3; | |||
float *conversionbuf; | |||
int j, k; | |||
int rtnval = SENDDACS_YES; | |||
#ifndef FAKEBLOCKING | |||
double timebefore; | |||
#endif /* FAKEBLOCKING */ | |||
if ((!STUFF->st_inchannels && !STUFF->st_outchannels) || !pa_stream) | |||
return (SENDDACS_NO); | |||
conversionbuf = (float *)alloca((STUFF->st_inchannels > STUFF->st_outchannels? | |||
STUFF->st_inchannels:STUFF->st_outchannels) * DEFDACBLKSIZE * sizeof(float)); | |||
#ifdef FAKEBLOCKING | |||
if (!STUFF->st_inchannels) /* if no input channels sync on output */ | |||
{ | |||
#ifdef THREADSIGNAL | |||
pthread_mutex_lock(&pa_mutex); | |||
#endif | |||
while (sys_ringbuf_getwriteavailable(&pa_outring) < | |||
(long)(STUFF->st_outchannels * DEFDACBLKSIZE * sizeof(float))) | |||
{ | |||
rtnval = SENDDACS_SLEPT; | |||
#ifdef THREADSIGNAL | |||
pthread_cond_wait(&pa_sem, &pa_mutex); | |||
#else | |||
#ifdef _WIN32 | |||
Sleep(1); | |||
#else | |||
usleep(1000); | |||
#endif /* _WIN32 */ | |||
#endif /* THREADSIGNAL */ | |||
} | |||
#ifdef THREADSIGNAL | |||
pthread_mutex_unlock(&pa_mutex); | |||
#endif | |||
} | |||
/* write output */ | |||
if (STUFF->st_outchannels) | |||
{ | |||
for (j = 0, fp = STUFF->st_soundout, fp2 = conversionbuf; | |||
j < STUFF->st_outchannels; j++, fp2++) | |||
for (k = 0, fp3 = fp2; k < DEFDACBLKSIZE; | |||
k++, fp++, fp3 += STUFF->st_outchannels) | |||
*fp3 = *fp; | |||
sys_ringbuf_write(&pa_outring, conversionbuf, | |||
STUFF->st_outchannels*(DEFDACBLKSIZE*sizeof(float)), pa_outbuf); | |||
} | |||
if (STUFF->st_inchannels) /* if there is input sync on it */ | |||
{ | |||
#ifdef THREADSIGNAL | |||
pthread_mutex_lock(&pa_mutex); | |||
#endif | |||
while (sys_ringbuf_getreadavailable(&pa_inring) < | |||
(long)(STUFF->st_inchannels * DEFDACBLKSIZE * sizeof(float))) | |||
{ | |||
rtnval = SENDDACS_SLEPT; | |||
#ifdef THREADSIGNAL | |||
pthread_cond_wait(&pa_sem, &pa_mutex); | |||
#else | |||
#ifdef _WIN32 | |||
Sleep(1); | |||
#else | |||
usleep(1000); | |||
#endif /* _WIN32 */ | |||
#endif /* THREADSIGNAL */ | |||
} | |||
#ifdef THREADSIGNAL | |||
pthread_mutex_unlock(&pa_mutex); | |||
#endif | |||
} | |||
if (STUFF->st_inchannels) | |||
{ | |||
sys_ringbuf_read(&pa_inring, conversionbuf, | |||
STUFF->st_inchannels*(DEFDACBLKSIZE*sizeof(float)), pa_inbuf); | |||
for (j = 0, fp = STUFF->st_soundin, fp2 = conversionbuf; | |||
j < STUFF->st_inchannels; j++, fp2++) | |||
for (k = 0, fp3 = fp2; k < DEFDACBLKSIZE; | |||
k++, fp++, fp3 += STUFF->st_inchannels) | |||
*fp = *fp3; | |||
} | |||
#else /* FAKEBLOCKING */ | |||
timebefore = sys_getrealtime(); | |||
/* write output */ | |||
if (STUFF->st_outchannels) | |||
{ | |||
if (!pa_started) | |||
{ | |||
memset(conversionbuf, 0, | |||
STUFF->st_outchannels * DEFDACBLKSIZE * sizeof(float)); | |||
for (j = 0; j < pa_nbuffers-1; j++) | |||
Pa_WriteStream(pa_stream, conversionbuf, DEFDACBLKSIZE); | |||
} | |||
for (j = 0, fp = STUFF->st_soundout, fp2 = conversionbuf; | |||
j < STUFF->st_outchannels; j++, fp2++) | |||
for (k = 0, fp3 = fp2; k < DEFDACBLKSIZE; | |||
k++, fp++, fp3 += STUFF->st_outchannels) | |||
*fp3 = *fp; | |||
Pa_WriteStream(pa_stream, conversionbuf, DEFDACBLKSIZE); | |||
} | |||
if (STUFF->st_inchannels) | |||
{ | |||
Pa_ReadStream(pa_stream, conversionbuf, DEFDACBLKSIZE); | |||
for (j = 0, fp = STUFF->st_soundin, fp2 = conversionbuf; | |||
j < STUFF->st_inchannels; j++, fp2++) | |||
for (k = 0, fp3 = fp2; k < DEFDACBLKSIZE; | |||
k++, fp++, fp3 += STUFF->st_inchannels) | |||
*fp = *fp3; | |||
} | |||
if (sys_getrealtime() - timebefore > 0.002) | |||
{ | |||
rtnval = SENDDACS_SLEPT; | |||
} | |||
#endif /* FAKEBLOCKING */ | |||
pa_started = 1; | |||
memset(STUFF->st_soundout, 0, | |||
DEFDACBLKSIZE*sizeof(t_sample)*STUFF->st_outchannels); | |||
return (rtnval); | |||
} | |||
/* scanning for devices */ | |||
void pa_getdevs(char *indevlist, int *nindevs, | |||
char *outdevlist, int *noutdevs, int *canmulti, | |||
int maxndev, int devdescsize) | |||
{ | |||
int i, nin = 0, nout = 0, ndev; | |||
*canmulti = 1; /* one dev each for input and output */ | |||
pa_init(); | |||
ndev = Pa_GetDeviceCount(); | |||
for (i = 0; i < ndev; i++) | |||
{ | |||
const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i); | |||
if (pdi->maxInputChannels > 0 && nin < maxndev) | |||
{ | |||
/* LATER figure out how to get API name correctly */ | |||
snprintf(indevlist + nin * devdescsize, devdescsize, | |||
#ifdef _WIN32 | |||
"%s:%s", (pdi->hostApi == 0 ? "MMIO" : (pdi->hostApi == 1 ? "ASIO" : "?")), | |||
#else | |||
#ifdef __APPLE__ | |||
"%s", | |||
#else | |||
"(%d) %s", pdi->hostApi, | |||
#endif | |||
#endif | |||
pdi->name); | |||
nin++; | |||
} | |||
if (pdi->maxOutputChannels > 0 && nout < maxndev) | |||
{ | |||
snprintf(outdevlist + nout * devdescsize, devdescsize, | |||
#ifdef _WIN32 | |||
"%s:%s", (pdi->hostApi == 0 ? "MMIO" : (pdi->hostApi == 1 ? "ASIO" : "?")), | |||
#else | |||
#ifdef __APPLE__ | |||
"%s", | |||
#else | |||
"(%d) %s", pdi->hostApi, | |||
#endif | |||
#endif | |||
pdi->name); | |||
nout++; | |||
} | |||
} | |||
*nindevs = nin; | |||
*noutdevs = nout; | |||
} |
@@ -0,0 +1,255 @@ | |||
/* | |||
* ringbuffer.c | |||
* Ring Buffer utility.. | |||
* | |||
* Author: Phil Burk, http://www.softsynth.com | |||
* | |||
* This program uses the PortAudio Portable Audio Library. | |||
* For more information see: http://www.audiomulch.com/portaudio/ | |||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files | |||
* (the "Software"), to deal in the Software without restriction, | |||
* including without limitation the rights to use, copy, modify, merge, | |||
* publish, distribute, sublicense, and/or sell copies of the Software, | |||
* and to permit persons to whom the Software is furnished to do so, | |||
* subject to the following conditions: | |||
* | |||
* The above copyright notice and this permission notice shall be | |||
* included in all copies or substantial portions of the Software. | |||
* | |||
* Any person wishing to distribute modifications to the Software is | |||
* requested to send the modifications to the original developer so that | |||
* they can be incorporated into the canonical version. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | |||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
* | |||
* modified 2002/07/13 by olaf.matthes@gmx.de to allow any number if channels | |||
* | |||
* extensively hacked by msp@ucsd.edu for various reasons | |||
* | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <math.h> | |||
#include "s_audio_paring.h" | |||
#include <string.h> | |||
/* Clear buffer. Should only be called when buffer is NOT being read. */ | |||
static void sys_ringbuf_Flush(PA_VOLATILE sys_ringbuf *rbuf, | |||
PA_VOLATILE void *dataPtr, long nfill); | |||
/* Get address of region(s) to which we can write data. | |||
** If the region is contiguous, size2 will be zero. | |||
** If non-contiguous, size2 will be the size of second region. | |||
** Returns room available to be written or numBytes, whichever is smaller. | |||
*/ | |||
static long sys_ringbuf_GetWriteRegions(PA_VOLATILE sys_ringbuf *rbuf, | |||
long numBytes, PA_VOLATILE void **dataPtr1, long *sizePtr1, | |||
PA_VOLATILE void **dataPtr2, long *sizePtr2, PA_VOLATILE char *buffer); | |||
static long sys_ringbuf_AdvanceWriteIndex(PA_VOLATILE sys_ringbuf *rbuf, | |||
long numBytes); | |||
/* Get address of region(s) from which we can read data. | |||
** If the region is contiguous, size2 will be zero. | |||
** If non-contiguous, size2 will be the size of second region. | |||
** Returns room available to be read or numBytes, whichever is smaller. | |||
*/ | |||
static long sys_ringbuf_GetReadRegions(PA_VOLATILE sys_ringbuf *rbuf, | |||
long numBytes, PA_VOLATILE void **dataPtr1, long *sizePtr1, | |||
PA_VOLATILE void **dataPtr2, long *sizePtr2, PA_VOLATILE char *buffer); | |||
static long sys_ringbuf_AdvanceReadIndex(PA_VOLATILE sys_ringbuf *rbuf, | |||
long numBytes ); | |||
/*************************************************************************** | |||
* Initialize FIFO. | |||
*/ | |||
long sys_ringbuf_init(PA_VOLATILE sys_ringbuf *rbuf, long numBytes, | |||
PA_VOLATILE char *dataPtr, long nfill) | |||
{ | |||
rbuf->bufferSize = numBytes; | |||
sys_ringbuf_Flush(rbuf, dataPtr, nfill); | |||
return 0; | |||
} | |||
/*************************************************************************** | |||
** Return number of bytes available for reading. */ | |||
long sys_ringbuf_getreadavailable(PA_VOLATILE sys_ringbuf *rbuf) | |||
{ | |||
long ret = rbuf->writeIndex - rbuf->readIndex; | |||
if (ret < 0) | |||
ret += 2 * rbuf->bufferSize; | |||
if (ret < 0 || ret > rbuf->bufferSize) | |||
fprintf(stderr, | |||
"consistency check failed: sys_ringbuf_getreadavailable\n"); | |||
return ( ret ); | |||
} | |||
/*************************************************************************** | |||
** Return number of bytes available for writing. */ | |||
long sys_ringbuf_getwriteavailable(PA_VOLATILE sys_ringbuf *rbuf) | |||
{ | |||
return ( rbuf->bufferSize - sys_ringbuf_getreadavailable(rbuf)); | |||
} | |||
/*************************************************************************** | |||
** Clear buffer. Should only be called when buffer is NOT being read. */ | |||
static void sys_ringbuf_Flush(PA_VOLATILE sys_ringbuf *rbuf, | |||
PA_VOLATILE void *dataPtr, long nfill) | |||
{ | |||
PA_VOLATILE char *s; | |||
long n; | |||
rbuf->readIndex = 0; | |||
rbuf->writeIndex = nfill; | |||
for (n = nfill, s = dataPtr; n--; s++) | |||
*s = 0; | |||
} | |||
/*************************************************************************** | |||
** Get address of region(s) to which we can write data. | |||
** If the region is contiguous, size2 will be zero. | |||
** If non-contiguous, size2 will be the size of second region. | |||
** Returns room available to be written or numBytes, whichever is smaller. | |||
*/ | |||
static long sys_ringbuf_GetWriteRegions(PA_VOLATILE sys_ringbuf *rbuf, | |||
long numBytes, PA_VOLATILE void **dataPtr1, long *sizePtr1, | |||
PA_VOLATILE void **dataPtr2, long *sizePtr2, PA_VOLATILE char *buffer) | |||
{ | |||
long index; | |||
long available = sys_ringbuf_getwriteavailable( rbuf ); | |||
if( numBytes > available ) numBytes = available; | |||
/* Check to see if write is not contiguous. */ | |||
index = rbuf->writeIndex; | |||
while (index >= rbuf->bufferSize) | |||
index -= rbuf->bufferSize; | |||
if( (index + numBytes) > rbuf->bufferSize ) | |||
{ | |||
/* Write data in two blocks that wrap the buffer. */ | |||
long firstHalf = rbuf->bufferSize - index; | |||
*dataPtr1 = &buffer[index]; | |||
*sizePtr1 = firstHalf; | |||
*dataPtr2 = &buffer[0]; | |||
*sizePtr2 = numBytes - firstHalf; | |||
} | |||
else | |||
{ | |||
*dataPtr1 = &buffer[index]; | |||
*sizePtr1 = numBytes; | |||
*dataPtr2 = NULL; | |||
*sizePtr2 = 0; | |||
} | |||
return numBytes; | |||
} | |||
/*************************************************************************** | |||
*/ | |||
static long sys_ringbuf_AdvanceWriteIndex(PA_VOLATILE sys_ringbuf *rbuf, | |||
long numBytes) | |||
{ | |||
long ret = (rbuf->writeIndex + numBytes); | |||
if ( ret >= 2 * rbuf->bufferSize) | |||
ret -= 2 * rbuf->bufferSize; /* check for end of buffer */ | |||
return rbuf->writeIndex = ret; | |||
} | |||
/*************************************************************************** | |||
** Get address of region(s) from which we can read data. | |||
** If the region is contiguous, size2 will be zero. | |||
** If non-contiguous, size2 will be the size of second region. | |||
** Returns room available to be written or numBytes, whichever is smaller. | |||
*/ | |||
static long sys_ringbuf_GetReadRegions(PA_VOLATILE sys_ringbuf *rbuf, | |||
long numBytes, PA_VOLATILE void **dataPtr1, long *sizePtr1, | |||
PA_VOLATILE void **dataPtr2, long *sizePtr2, PA_VOLATILE char *buffer) | |||
{ | |||
long index; | |||
long available = sys_ringbuf_getreadavailable( rbuf ); | |||
if( numBytes > available ) numBytes = available; | |||
/* Check to see if read is not contiguous. */ | |||
index = rbuf->readIndex; | |||
while (index >= rbuf->bufferSize) | |||
index -= rbuf->bufferSize; | |||
if( (index + numBytes) > rbuf->bufferSize ) | |||
{ | |||
/* Write data in two blocks that wrap the buffer. */ | |||
long firstHalf = rbuf->bufferSize - index; | |||
*dataPtr1 = &buffer[index]; | |||
*sizePtr1 = firstHalf; | |||
*dataPtr2 = &buffer[0]; | |||
*sizePtr2 = numBytes - firstHalf; | |||
} | |||
else | |||
{ | |||
*dataPtr1 = &buffer[index]; | |||
*sizePtr1 = numBytes; | |||
*dataPtr2 = NULL; | |||
*sizePtr2 = 0; | |||
} | |||
return numBytes; | |||
} | |||
/*************************************************************************** | |||
*/ | |||
static long sys_ringbuf_AdvanceReadIndex(PA_VOLATILE sys_ringbuf *rbuf, | |||
long numBytes) | |||
{ | |||
long ret = (rbuf->readIndex + numBytes); | |||
if( ret >= 2 * rbuf->bufferSize) | |||
ret -= 2 * rbuf->bufferSize; | |||
return rbuf->readIndex = ret; | |||
} | |||
/*************************************************************************** | |||
** Return bytes written. */ | |||
long sys_ringbuf_write(PA_VOLATILE sys_ringbuf *rbuf, const void *data, | |||
long numBytes, PA_VOLATILE char *buffer) | |||
{ | |||
long size1, size2, numWritten; | |||
PA_VOLATILE void *data1, *data2; | |||
numWritten = sys_ringbuf_GetWriteRegions( rbuf, numBytes, &data1, &size1, | |||
&data2, &size2, buffer); | |||
if( size2 > 0 ) | |||
{ | |||
memcpy((void *)data1, data, size1 ); | |||
data = ((char *)data) + size1; | |||
memcpy((void *)data2, data, size2 ); | |||
} | |||
else | |||
{ | |||
memcpy((void *)data1, data, size1 ); | |||
} | |||
sys_ringbuf_AdvanceWriteIndex( rbuf, numWritten ); | |||
return numWritten; | |||
} | |||
/*************************************************************************** | |||
** Return bytes read. */ | |||
long sys_ringbuf_read(PA_VOLATILE sys_ringbuf *rbuf, void *data, long numBytes, | |||
PA_VOLATILE char *buffer) | |||
{ | |||
long size1, size2, numRead; | |||
PA_VOLATILE void *data1, *data2; | |||
numRead = sys_ringbuf_GetReadRegions( rbuf, numBytes, &data1, &size1, | |||
&data2, &size2, buffer); | |||
if( size2 > 0 ) | |||
{ | |||
memcpy(data, (void *)data1, size1 ); | |||
data = ((char *)data) + size1; | |||
memcpy(data, (void *)data2, size2 ); | |||
} | |||
else | |||
{ | |||
memcpy( data, (void *)data1, size1 ); | |||
} | |||
sys_ringbuf_AdvanceReadIndex( rbuf, numRead ); | |||
return numRead; | |||
} |
@@ -0,0 +1,75 @@ | |||
#ifndef _RINGBUFFER_H | |||
#define _RINGBUFFER_H | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif /* __cplusplus */ | |||
/* | |||
* ringbuffer.h | |||
* Ring Buffer utility.. | |||
* | |||
* Author: Phil Burk, http://www.softsynth.com | |||
* | |||
* This program is distributed with the PortAudio Portable Audio Library. | |||
* For more information see: http://www.audiomulch.com/portaudio/ | |||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files | |||
* (the "Software"), to deal in the Software without restriction, | |||
* including without limitation the rights to use, copy, modify, merge, | |||
* publish, distribute, sublicense, and/or sell copies of the Software, | |||
* and to permit persons to whom the Software is furnished to do so, | |||
* subject to the following conditions: | |||
* | |||
* The above copyright notice and this permission notice shall be | |||
* included in all copies or substantial portions of the Software. | |||
* | |||
* Any person wishing to distribute modifications to the Software is | |||
* requested to send the modifications to the original developer so that | |||
* they can be incorporated into the canonical version. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | |||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
* | |||
*/ | |||
/* If it's ever desired to use shared memory so that one process reads and | |||
another one writes to the same ring buffer, define this as 'volatile' : */ | |||
#define PA_VOLATILE | |||
typedef struct | |||
{ | |||
long bufferSize; /* Number of bytes in FIFO. | |||
Set by sys_ringbuf_init */ | |||
PA_VOLATILE long writeIndex; /* Index of next writable byte. | |||
Set by sys_ringbuf_AdvanceWriteIndex */ | |||
PA_VOLATILE long readIndex; /* Index of next readable byte. | |||
Set by sys_ringbuf_AdvanceReadIndex */ | |||
} sys_ringbuf; | |||
/* Initialize Ring Buffer. */ | |||
long sys_ringbuf_init(PA_VOLATILE sys_ringbuf *rbuf, long numBytes, | |||
PA_VOLATILE char *dataPtr, long nfill); | |||
/* Return number of bytes available for writing. */ | |||
long sys_ringbuf_getwriteavailable(PA_VOLATILE sys_ringbuf *rbuf); | |||
/* Return number of bytes available for read. */ | |||
long sys_ringbuf_getreadavailable(PA_VOLATILE sys_ringbuf *rbuf); | |||
/* Return bytes written. */ | |||
long sys_ringbuf_write(PA_VOLATILE sys_ringbuf *rbuf, const void *data, | |||
long numBytes, PA_VOLATILE char *buffer); | |||
/* Return bytes read. */ | |||
long sys_ringbuf_read(PA_VOLATILE sys_ringbuf *rbuf, void *data, long numBytes, | |||
PA_VOLATILE char *buffer); | |||
#ifdef __cplusplus | |||
} | |||
#endif /* __cplusplus */ | |||
#endif /* _RINGBUFFER_H */ |
@@ -0,0 +1,36 @@ | |||
/* In MSW, this is all there is to pd; the rest sits in a "pdlib" dll so | |||
that externs can link back to functions defined in pd. */ | |||
int sys_main(int argc, char **argv); | |||
/* | |||
* gcc does not support the __try stuff, only MSVC. Also, MinGW allows you to | |||
* use main() instead of WinMain(). <hans@at.or.at> | |||
*/ | |||
#if defined(_MSC_VER) && !defined(COMMANDVERSION) | |||
#include <windows.h> | |||
#include <stdio.h> | |||
int WINAPI WinMain(HINSTANCE hInstance, | |||
HINSTANCE hPrevInstance, | |||
LPSTR lpCmdLine, | |||
int nCmdShow) | |||
{ | |||
__try { | |||
sys_main(__argc,__argv); | |||
} | |||
__finally | |||
{ | |||
printf("caught an exception; stopping\n"); | |||
} | |||
return (0); | |||
} | |||
#else /* not _MSC_VER ... */ | |||
int main(int argc, char **argv) | |||
{ | |||
return (sys_main(argc, argv)); | |||
} | |||
#endif /* _MSC_VER */ | |||
@@ -0,0 +1,697 @@ | |||
/* Copyright (c) 1997-2004 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
/* | |||
* this file implements a mechanism for storing and retrieving preferences. | |||
* Should later be renamed "preferences.c" or something. | |||
* | |||
* In unix this is handled by the "~/.pdsettings" file, in windows by | |||
* the registry, and in MacOS by the Preferences system. | |||
*/ | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include <errno.h> | |||
#ifdef HAVE_UNISTD_H | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <fcntl.h> | |||
#include <unistd.h> | |||
#endif | |||
#ifdef _WIN32 | |||
#include <windows.h> | |||
#include <tchar.h> | |||
#include <io.h> | |||
#endif | |||
#ifdef _MSC_VER /* This is only for Microsoft's compiler, not cygwin, e.g. */ | |||
#define snprintf _snprintf | |||
#endif | |||
void sys_doflags( void); | |||
static PERTHREAD char *sys_prefbuf; | |||
static PERTHREAD int sys_prefbufsize; | |||
static PERTHREAD FILE *sys_prefsavefp; | |||
static void sys_initloadpreferences_file(const char *filename) | |||
{ | |||
int fd; | |||
long length; | |||
if ((fd = open(filename, 0)) < 0) | |||
{ | |||
if (sys_verbose) | |||
perror(filename); | |||
return; | |||
} | |||
length = lseek(fd, 0, 2); | |||
if (length < 0) | |||
{ | |||
if (sys_verbose) | |||
perror(filename); | |||
close(fd); | |||
return; | |||
} | |||
lseek(fd, 0, 0); | |||
if (!(sys_prefbuf = malloc(length + 2))) | |||
{ | |||
error("couldn't allocate memory for preferences buffer"); | |||
close(fd); | |||
return; | |||
} | |||
sys_prefbuf[0] = '\n'; | |||
if (read(fd, sys_prefbuf+1, length) < length) | |||
{ | |||
perror(filename); | |||
sys_prefbuf[0] = 0; | |||
close(fd); | |||
return; | |||
} | |||
sys_prefbuf[length+1] = 0; | |||
close(fd); | |||
if (sys_verbose) | |||
post("success reading preferences from: %s", filename); | |||
} | |||
static int sys_getpreference_file(const char *key, char *value, int size) | |||
{ | |||
char searchfor[80], *where, *whereend; | |||
if (!sys_prefbuf) | |||
return (0); | |||
sprintf(searchfor, "\n%s:", key); | |||
where = strstr(sys_prefbuf, searchfor); | |||
if (!where) | |||
return (0); | |||
where += strlen(searchfor); | |||
while (*where == ' ' || *where == '\t') | |||
where++; | |||
for (whereend = where; *whereend && *whereend != '\n'; whereend++) | |||
; | |||
if (*whereend == '\n') | |||
whereend--; | |||
if (whereend > where + size - 1) | |||
whereend = where + size - 1; | |||
strncpy(value, where, whereend+1-where); | |||
value[whereend+1-where] = 0; | |||
return (1); | |||
} | |||
static void sys_doneloadpreferences_file( void) | |||
{ | |||
if (sys_prefbuf) | |||
free(sys_prefbuf); | |||
} | |||
static void sys_initsavepreferences_file(const char *filename) | |||
{ | |||
if ((sys_prefsavefp = fopen(filename, "w")) == NULL) | |||
pd_error(0, "%s: %s", filename, strerror(errno)); | |||
} | |||
static void sys_putpreference_file(const char *key, const char *value) | |||
{ | |||
if (sys_prefsavefp) | |||
fprintf(sys_prefsavefp, "%s: %s\n", | |||
key, value); | |||
} | |||
static void sys_donesavepreferences_file( void) | |||
{ | |||
if (sys_prefsavefp) | |||
{ | |||
fclose(sys_prefsavefp); | |||
sys_prefsavefp = 0; | |||
} | |||
} | |||
/***** linux/android/BSD etc: read and write to ~/.pdsettings file ******/ | |||
#if !defined(_WIN32) && !defined(__APPLE__) | |||
static void sys_initloadpreferences( void) | |||
{ | |||
char filenamebuf[MAXPDSTRING], *homedir = getenv("HOME"); | |||
int fd, length; | |||
char user_prefs_file[MAXPDSTRING]; /* user prefs file */ | |||
/* default prefs embedded in the package */ | |||
char default_prefs_file[MAXPDSTRING]; | |||
struct stat statbuf; | |||
snprintf(default_prefs_file, MAXPDSTRING, "%s/default.pdsettings", | |||
sys_libdir->s_name); | |||
snprintf(user_prefs_file, MAXPDSTRING, "%s/.pdsettings", | |||
(homedir ? homedir : ".")); | |||
if (stat(user_prefs_file, &statbuf) == 0) | |||
strncpy(filenamebuf, user_prefs_file, MAXPDSTRING); | |||
else if (stat(default_prefs_file, &statbuf) == 0) | |||
strncpy(filenamebuf, default_prefs_file, MAXPDSTRING); | |||
else return; | |||
filenamebuf[MAXPDSTRING-1] = 0; | |||
sys_initloadpreferences_file(filenamebuf); | |||
} | |||
static int sys_getpreference(const char *key, char *value, int size) | |||
{ | |||
return (sys_getpreference_file(key, value, size)); | |||
} | |||
static void sys_doneloadpreferences( void) | |||
{ | |||
sys_doneloadpreferences_file(); | |||
} | |||
static void sys_initsavepreferences( void) | |||
{ | |||
char filenamebuf[MAXPDSTRING], | |||
*homedir = getenv("HOME"); | |||
FILE *fp; | |||
if (!homedir) | |||
return; | |||
snprintf(filenamebuf, MAXPDSTRING, "%s/.pdsettings", homedir); | |||
filenamebuf[MAXPDSTRING-1] = 0; | |||
sys_initsavepreferences_file(filenamebuf); | |||
} | |||
static void sys_putpreference(const char *key, const char *value) | |||
{ | |||
sys_putpreference_file(key, value); | |||
} | |||
static void sys_donesavepreferences( void) | |||
{ | |||
sys_donesavepreferences_file(); | |||
} | |||
#else /* !defined(_WIN32) && !defined(__APPLE__) */ | |||
static void sys_initloadpreferences( void) | |||
{ | |||
if (sys_prefbuf) | |||
bug("sys_initloadpreferences"); | |||
} | |||
static void sys_doneloadpreferences( void) | |||
{ | |||
if (sys_prefbuf) | |||
sys_doneloadpreferences_file(); | |||
} | |||
static void sys_initsavepreferences( void) | |||
{ | |||
if (sys_prefsavefp) | |||
bug("sys_initsavepreferences"); | |||
} | |||
static void sys_donesavepreferences( void) | |||
{ | |||
if (sys_prefsavefp) | |||
sys_donesavepreferences_file(); | |||
} | |||
static int sys_getpreference(const char *key, char *value, int size) | |||
{ | |||
if (sys_prefbuf) | |||
return (sys_getpreference_file(key, value, size)); | |||
else | |||
{ | |||
#ifdef _WIN32 | |||
HKEY hkey; | |||
DWORD bigsize = size; | |||
LONG err = RegOpenKeyEx(HKEY_CURRENT_USER, | |||
"Software\\Pure-Data", 0, KEY_QUERY_VALUE, &hkey); | |||
if (err != ERROR_SUCCESS) | |||
return (0); | |||
err = RegQueryValueEx(hkey, key, 0, 0, value, &bigsize); | |||
if (err != ERROR_SUCCESS) | |||
{ | |||
RegCloseKey(hkey); | |||
return (0); | |||
} | |||
RegCloseKey(hkey); | |||
return (1); | |||
#endif /* _WIN32 */ | |||
#ifdef __APPLE__ | |||
char cmdbuf[256]; | |||
int nread = 0, nleft = size; | |||
char embedded_prefs[MAXPDSTRING]; | |||
char user_prefs[MAXPDSTRING]; | |||
char *homedir = getenv("HOME"); | |||
struct stat statbuf; | |||
/* the 'defaults' command expects the filename without .plist at the | |||
end */ | |||
snprintf(embedded_prefs, MAXPDSTRING, "%s/../org.puredata.pd", | |||
sys_libdir->s_name); | |||
snprintf(user_prefs, MAXPDSTRING, | |||
"%s/Library/Preferences/org.puredata.pd.plist", homedir); | |||
if (stat(user_prefs, &statbuf) == 0) | |||
snprintf(cmdbuf, 256, "defaults read org.puredata.pd %s 2> /dev/null\n", | |||
key); | |||
else snprintf(cmdbuf, 256, "defaults read %s %s 2> /dev/null\n", | |||
embedded_prefs, key); | |||
FILE *fp = popen(cmdbuf, "r"); | |||
while (nread < size) | |||
{ | |||
int newread = fread(value+nread, 1, size-nread, fp); | |||
if (newread <= 0) | |||
break; | |||
nread += newread; | |||
} | |||
pclose(fp); | |||
if (nread < 1) | |||
return (0); | |||
if (nread >= size) | |||
nread = size-1; | |||
value[nread] = 0; | |||
if (value[nread-1] == '\n') /* remove newline character at end */ | |||
value[nread-1] = 0; | |||
return(1); | |||
#endif /* __APPLE__ */ | |||
} | |||
} | |||
static void sys_putpreference(const char *key, const char *value) | |||
{ | |||
if (sys_prefsavefp) | |||
sys_putpreference_file(key, value); | |||
else | |||
{ | |||
#ifdef _WIN32 | |||
HKEY hkey; | |||
LONG err = RegCreateKeyEx(HKEY_CURRENT_USER, | |||
"Software\\Pure-Data", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, | |||
NULL, &hkey, NULL); | |||
if (err != ERROR_SUCCESS) | |||
{ | |||
error("unable to create registry entry: %s\n", key); | |||
return; | |||
} | |||
err = RegSetValueEx(hkey, key, 0, REG_EXPAND_SZ, value, strlen(value)+1); | |||
if (err != ERROR_SUCCESS) | |||
error("unable to set registry entry: %s\n", key); | |||
RegCloseKey(hkey); | |||
#endif /* _WIN32 */ | |||
#ifdef __APPLE__ | |||
char cmdbuf[MAXPDSTRING]; | |||
snprintf(cmdbuf, MAXPDSTRING, | |||
"defaults write org.puredata.pd %s \"%s\" 2> /dev/null\n", key, value); | |||
system(cmdbuf); | |||
#endif /* __APPLE__ */ | |||
} | |||
} | |||
#endif /* !defined(_WIN32) && !defined(__APPLE__) */ | |||
void sys_loadpreferences(const char *filename, int startingup) | |||
{ | |||
int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | |||
int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | |||
int nmidiindev, midiindev[MAXMIDIINDEV]; | |||
int nmidioutdev, midioutdev[MAXMIDIOUTDEV]; | |||
int i, rate = 0, advance = -1, callback = 0, blocksize = 0, | |||
api, midiapi, nolib, maxi; | |||
char prefbuf[MAXPDSTRING], keybuf[80]; | |||
if (*filename) | |||
sys_initloadpreferences_file(filename); | |||
else sys_initloadpreferences(); | |||
/* load audio preferences */ | |||
if (sys_getpreference("audioapi", prefbuf, MAXPDSTRING) | |||
&& sscanf(prefbuf, "%d", &api) > 0) | |||
sys_set_audio_api(api); | |||
/* JMZ/MB: brackets for initializing */ | |||
if (sys_getpreference("noaudioin", prefbuf, MAXPDSTRING) && | |||
(!strcmp(prefbuf, ".") || !strcmp(prefbuf, "True"))) | |||
naudioindev = 0; | |||
else | |||
{ | |||
for (i = 0, naudioindev = 0; i < MAXAUDIOINDEV; i++) | |||
{ | |||
/* first try to find a name - if that matches an existing | |||
device use it. Otherwise fall back to device number. */ | |||
int devn; | |||
/* read in device number and channel count */ | |||
sprintf(keybuf, "audioindev%d", i+1); | |||
if (!sys_getpreference(keybuf, prefbuf, MAXPDSTRING)) | |||
break; | |||
if (sscanf(prefbuf, "%d %d", &audioindev[i], &chindev[i]) < 2) | |||
break; | |||
/* possibly override device number if the device name was | |||
also saved and if it matches one we have now */ | |||
sprintf(keybuf, "audioindevname%d", i+1); | |||
if (sys_getpreference(keybuf, prefbuf, MAXPDSTRING) | |||
&& (devn = sys_audiodevnametonumber(0, prefbuf)) >= 0) | |||
audioindev[i] = devn; | |||
naudioindev++; | |||
} | |||
/* if no preferences at all, set -1 for default behavior */ | |||
if (naudioindev == 0) | |||
naudioindev = -1; | |||
} | |||
/* JMZ/MB: brackets for initializing */ | |||
if (sys_getpreference("noaudioout", prefbuf, MAXPDSTRING) && | |||
(!strcmp(prefbuf, ".") || !strcmp(prefbuf, "True"))) | |||
naudiooutdev = 0; | |||
else | |||
{ | |||
for (i = 0, naudiooutdev = 0; i < MAXAUDIOOUTDEV; i++) | |||
{ | |||
int devn; | |||
sprintf(keybuf, "audiooutdev%d", i+1); | |||
if (!sys_getpreference(keybuf, prefbuf, MAXPDSTRING)) | |||
break; | |||
if (sscanf(prefbuf, "%d %d", &audiooutdev[i], &choutdev[i]) < 2) | |||
break; | |||
sprintf(keybuf, "audiooutdevname%d", i+1); | |||
if (sys_getpreference(keybuf, prefbuf, MAXPDSTRING) | |||
&& (devn = sys_audiodevnametonumber(1, prefbuf)) >= 0) | |||
audiooutdev[i] = devn; | |||
naudiooutdev++; | |||
} | |||
if (naudiooutdev == 0) | |||
naudiooutdev = -1; | |||
} | |||
if (sys_getpreference("rate", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &rate); | |||
if (sys_getpreference("audiobuf", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &advance); | |||
if (sys_getpreference("callback", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &callback); | |||
if (sys_getpreference("blocksize", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &blocksize); | |||
sys_set_audio_settings(naudioindev, audioindev, naudioindev, chindev, | |||
naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, | |||
callback, blocksize); | |||
/* load MIDI preferences */ | |||
if (sys_getpreference("midiapi", prefbuf, MAXPDSTRING) | |||
&& sscanf(prefbuf, "%d", &midiapi) > 0) | |||
sys_set_midi_api(midiapi); | |||
/* JMZ/MB: brackets for initializing */ | |||
if (sys_getpreference("nomidiin", prefbuf, MAXPDSTRING) && | |||
(!strcmp(prefbuf, ".") || !strcmp(prefbuf, "True"))) | |||
nmidiindev = 0; | |||
else for (i = 0, nmidiindev = 0; i < MAXMIDIINDEV; i++) | |||
{ | |||
/* first try to find a name - if that matches an existing device | |||
use it. Otherwise fall back to device number. */ | |||
int devn; | |||
sprintf(keybuf, "midiindevname%d", i+1); | |||
if (sys_getpreference(keybuf, prefbuf, MAXPDSTRING) | |||
&& (devn = sys_mididevnametonumber(0, prefbuf)) >= 0) | |||
midiindev[i] = devn; | |||
else | |||
{ | |||
sprintf(keybuf, "midiindev%d", i+1); | |||
if (!sys_getpreference(keybuf, prefbuf, MAXPDSTRING)) | |||
break; | |||
if (sscanf(prefbuf, "%d", &midiindev[i]) < 1) | |||
break; | |||
} | |||
nmidiindev++; | |||
} | |||
/* JMZ/MB: brackets for initializing */ | |||
if (sys_getpreference("nomidiout", prefbuf, MAXPDSTRING) && | |||
(!strcmp(prefbuf, ".") || !strcmp(prefbuf, "True"))) | |||
nmidioutdev = 0; | |||
else for (i = 0, nmidioutdev = 0; i < MAXMIDIOUTDEV; i++) | |||
{ | |||
int devn; | |||
sprintf(keybuf, "midioutdevname%d", i+1); | |||
if (sys_getpreference(keybuf, prefbuf, MAXPDSTRING) | |||
&& (devn = sys_mididevnametonumber(1, prefbuf)) >= 0) | |||
midioutdev[i] = devn; | |||
else | |||
{ | |||
sprintf(keybuf, "midioutdev%d", i+1); | |||
if (!sys_getpreference(keybuf, prefbuf, MAXPDSTRING)) | |||
break; | |||
if (sscanf(prefbuf, "%d", &midioutdev[i]) < 1) | |||
break; | |||
} | |||
nmidioutdev++; | |||
} | |||
sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev, 0); | |||
/* search path */ | |||
if (sys_getpreference("npath", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &maxi); | |||
else maxi = 0x7fffffff; | |||
for (i = 0; i<maxi; i++) | |||
{ | |||
sprintf(keybuf, "path%d", i+1); | |||
if (!sys_getpreference(keybuf, prefbuf, MAXPDSTRING)) | |||
break; | |||
STUFF->st_searchpath = | |||
namelist_append_files(STUFF->st_searchpath, prefbuf); | |||
} | |||
if (sys_getpreference("standardpath", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &sys_usestdpath); | |||
if (sys_getpreference("verbose", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &sys_verbose); | |||
/* startup settings */ | |||
if (sys_getpreference("nloadlib", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &maxi); | |||
else maxi = 0x7fffffff; | |||
for (i = 0; i<maxi; i++) | |||
{ | |||
sprintf(keybuf, "loadlib%d", i+1); | |||
if (!sys_getpreference(keybuf, prefbuf, MAXPDSTRING)) | |||
break; | |||
STUFF->st_externlist = namelist_append_files(STUFF->st_externlist, prefbuf); | |||
} | |||
if (sys_getpreference("defeatrt", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &sys_defeatrt); | |||
if (sys_getpreference("flags", prefbuf, MAXPDSTRING) && | |||
strcmp(prefbuf, ".")) | |||
{ | |||
sys_flags = gensym(prefbuf); | |||
if (startingup) | |||
sys_doflags(); | |||
} | |||
if (sys_defeatrt) | |||
sys_hipriority = 0; | |||
else | |||
#if defined(__linux__) || defined(__CYGWIN__) | |||
sys_hipriority = 1; | |||
#else | |||
#if defined(_WIN32) || defined(ANDROID) | |||
sys_hipriority = 0; | |||
#else | |||
sys_hipriority = 1; | |||
#endif | |||
#endif | |||
if (sys_getpreference("zoom", prefbuf, MAXPDSTRING)) | |||
sscanf(prefbuf, "%d", &sys_zoom_open); | |||
sys_doneloadpreferences(); | |||
} | |||
void sys_savepreferences(const char *filename) | |||
{ | |||
int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV]; | |||
int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV]; | |||
int i, rate, advance, callback, blocksize; | |||
char buf1[MAXPDSTRING], buf2[MAXPDSTRING]; | |||
int nmidiindev, midiindev[MAXMIDIINDEV]; | |||
int nmidioutdev, midioutdev[MAXMIDIOUTDEV]; | |||
if (filename && *filename) | |||
sys_initsavepreferences_file(filename); | |||
else sys_initsavepreferences(); | |||
/* audio settings */ | |||
sprintf(buf1, "%d", sys_audioapi); | |||
sys_putpreference("audioapi", buf1); | |||
sys_get_audio_params(&naudioindev, audioindev, chindev, | |||
&naudiooutdev, audiooutdev, choutdev, &rate, &advance, &callback, | |||
&blocksize); | |||
sys_putpreference("noaudioin", (naudioindev <= 0 ? "True" : "False")); | |||
for (i = 0; i < naudioindev; i++) | |||
{ | |||
sprintf(buf1, "audioindev%d", i+1); | |||
sprintf(buf2, "%d %d", audioindev[i], chindev[i]); | |||
sys_putpreference(buf1, buf2); | |||
sprintf(buf1, "audioindevname%d", i+1); | |||
sys_audiodevnumbertoname(0, audioindev[i], buf2, MAXPDSTRING); | |||
if (! *buf2) | |||
strcat(buf2, "?"); | |||
sys_putpreference(buf1, buf2); | |||
} | |||
sys_putpreference("noaudioout", (naudiooutdev <= 0 ? "True" : "False")); | |||
for (i = 0; i < naudiooutdev; i++) | |||
{ | |||
sprintf(buf1, "audiooutdev%d", i+1); | |||
sprintf(buf2, "%d %d", audiooutdev[i], choutdev[i]); | |||
sys_putpreference(buf1, buf2); | |||
sprintf(buf1, "audiooutdevname%d", i+1); | |||
sys_audiodevnumbertoname(1, audiooutdev[i], buf2, MAXPDSTRING); | |||
if (! *buf2) | |||
strcat(buf2, "?"); | |||
sys_putpreference(buf1, buf2); | |||
} | |||
sprintf(buf1, "%d", advance); | |||
sys_putpreference("audiobuf", buf1); | |||
sprintf(buf1, "%d", rate); | |||
sys_putpreference("rate", buf1); | |||
sprintf(buf1, "%d", callback); | |||
sys_putpreference("callback", buf1); | |||
sprintf(buf1, "%d", blocksize); | |||
sys_putpreference("blocksize", buf1); | |||
/* MIDI settings */ | |||
sprintf(buf1, "%d", sys_midiapi); | |||
sys_putpreference("midiapi", buf1); | |||
sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev); | |||
sys_putpreference("nomidiin", (nmidiindev <= 0 ? "True" : "False")); | |||
for (i = 0; i < nmidiindev; i++) | |||
{ | |||
sprintf(buf1, "midiindev%d", i+1); | |||
sprintf(buf2, "%d", midiindev[i]); | |||
sys_putpreference(buf1, buf2); | |||
sprintf(buf1, "midiindevname%d", i+1); | |||
sys_mididevnumbertoname(0, midiindev[i], buf2, MAXPDSTRING); | |||
if (! *buf2) | |||
strcat(buf2, "?"); | |||
sys_putpreference(buf1, buf2); | |||
} | |||
sys_putpreference("nomidiout", (nmidioutdev <= 0 ? "True" : "False")); | |||
for (i = 0; i < nmidioutdev; i++) | |||
{ | |||
sprintf(buf1, "midioutdev%d", i+1); | |||
sprintf(buf2, "%d", midioutdev[i]); | |||
sys_putpreference(buf1, buf2); | |||
sprintf(buf1, "midioutdevname%d", i+1); | |||
sys_mididevnumbertoname(1, midioutdev[i], buf2, MAXPDSTRING); | |||
if (! *buf2) | |||
strcat(buf2, "?"); | |||
sys_putpreference(buf1, buf2); | |||
} | |||
/* file search path */ | |||
for (i = 0; 1; i++) | |||
{ | |||
char *pathelem = namelist_get(STUFF->st_searchpath, i); | |||
if (!pathelem) | |||
break; | |||
sprintf(buf1, "path%d", i+1); | |||
sys_putpreference(buf1, pathelem); | |||
} | |||
sprintf(buf1, "%d", i); | |||
sys_putpreference("npath", buf1); | |||
sprintf(buf1, "%d", sys_usestdpath); | |||
sys_putpreference("standardpath", buf1); | |||
sprintf(buf1, "%d", sys_verbose); | |||
sys_putpreference("verbose", buf1); | |||
/* startup */ | |||
for (i = 0; 1; i++) | |||
{ | |||
char *pathelem = namelist_get(STUFF->st_externlist, i); | |||
if (!pathelem) | |||
break; | |||
sprintf(buf1, "loadlib%d", i+1); | |||
sys_putpreference(buf1, pathelem); | |||
} | |||
sprintf(buf1, "%d", i); | |||
sys_putpreference("nloadlib", buf1); | |||
sprintf(buf1, "%d", sys_defeatrt); | |||
sys_putpreference("defeatrt", buf1); | |||
sys_putpreference("flags", | |||
(sys_flags ? sys_flags->s_name : "")); | |||
/* misc */ | |||
sprintf(buf1, "%d", sys_zoom_open); | |||
sys_putpreference("zoom", buf1); | |||
sys_putpreference("loading", "no"); | |||
sys_donesavepreferences(); | |||
} | |||
/* calls from GUI to load/save from/to a file */ | |||
void glob_loadpreferences(t_pd *dummy, t_symbol *filesym) | |||
{ | |||
sys_loadpreferences(filesym->s_name, 0); | |||
sys_close_audio(); | |||
sys_reopen_audio(); | |||
sys_close_midi(); | |||
sys_reopen_midi(); | |||
} | |||
void glob_savepreferences(t_pd *dummy, t_symbol *filesym) | |||
{ | |||
sys_savepreferences(filesym->s_name); | |||
} | |||
void glob_forgetpreferences(t_pd *dummy) | |||
{ | |||
#if !defined(_WIN32) && !defined(__APPLE__) | |||
if (system("cat ~/.pdsettings >& /dev/null\n")) | |||
post("no Pd settings to clear"); | |||
else if (!system("rm ~/.pdsettings\n")) | |||
post("removed .pdsettings file"); | |||
else post("couldn't delete .pdsettings file"); | |||
#endif /* !defined(_WIN32) && !defined(__APPLE__) */ | |||
#ifdef __APPLE__ | |||
char cmdbuf[MAXPDSTRING]; | |||
int warn = 1; | |||
if (!sys_getpreference("audioapi", cmdbuf, MAXPDSTRING)) | |||
post("no Pd settings to clear"), warn = 0; | |||
/* do it anyhow, why not... */ | |||
snprintf(cmdbuf, MAXPDSTRING, | |||
"defaults delete org.puredata.pd 2> /dev/null\n"); | |||
if (system(cmdbuf) && warn) | |||
post("failed to erase Pd settings"); | |||
else if(warn) post("erased Pd settings"); | |||
#endif /* __APPLE__ */ | |||
#ifdef _WIN32 | |||
HKEY hkey; | |||
if (RegOpenKeyEx(HKEY_CURRENT_USER, | |||
"Software", 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) | |||
post("no Pd settings to erase"); | |||
else | |||
{ | |||
if (RegDeleteKey(hkey, "Pure-Data") != ERROR_SUCCESS) | |||
post("no Pd settings to erase"); | |||
else post("erased Pd settings"); | |||
RegCloseKey(hkey); | |||
} | |||
#endif /* _WIN32 */ | |||
} | |||
int sys_oktoloadfiles(int done) | |||
{ | |||
#if defined(_WIN32) || defined(__APPLE__) | |||
if (done) | |||
{ | |||
sys_putpreference("loading", "no"); | |||
return (1); | |||
} | |||
else | |||
{ | |||
char prefbuf[MAXPDSTRING]; | |||
if (sys_getpreference("loading", prefbuf, MAXPDSTRING) && | |||
strcmp(prefbuf, "no")) | |||
{ | |||
post( | |||
"skipping loading preferences... Pd seems to have crashed on startup."); | |||
post("(re-save preferences to reinstate them)"); | |||
return (0); | |||
} | |||
else | |||
{ | |||
sys_putpreference("loading", "yes"); | |||
return (1); | |||
} | |||
} | |||
#else | |||
return (1); | |||
#endif | |||
} |
@@ -0,0 +1,492 @@ | |||
/* Copyright (c) 1997-1999 Miller Puckette. | |||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL | |||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | |||
#if defined(HAVE_LIBDL) || defined(__FreeBSD__) | |||
#include <dlfcn.h> | |||
#endif | |||
#ifdef HAVE_UNISTD_H | |||
#include <stdlib.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#endif | |||
#ifdef _WIN32 | |||
#include <io.h> | |||
#include <windows.h> | |||
#endif | |||
#ifdef __APPLE__ | |||
#include <mach-o/dyld.h> | |||
#endif | |||
#include <string.h> | |||
#include "m_pd.h" | |||
#include "s_stuff.h" | |||
#include <stdio.h> | |||
#include <sys/stat.h> | |||
#ifdef _MSC_VER /* This is only for Microsoft's compiler, not cygwin, e.g. */ | |||
#define snprintf _snprintf | |||
#define stat _stat | |||
#endif | |||
typedef void (*t_xxx)(void); | |||
/* naming convention for externs. The names are kept distinct for those | |||
who wish to make "fat" externs compiled for many platforms. Less specific | |||
fallbacks are provided, primarily for back-compatibility; these suffice if | |||
you are building a package which will run with a single set of compiled | |||
objects. The specific name is the letter b, l, d, or m for BSD, linux, | |||
darwin, or microsoft, followed by a more specific string, either "fat" for | |||
a fat binary or an indication of the instruction set. */ | |||
#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GNU__) || defined(__FreeBSD__) | |||
static char sys_dllextent2[] = ".pd_linux"; | |||
# ifdef __x86_64__ | |||
static char sys_dllextent[] = ".l_ia64"; // this should be .l_x86_64 or .l_amd64 | |||
# elif defined(__i386__) || defined(_M_IX86) | |||
static char sys_dllextent[] = ".l_i386"; | |||
# elif defined(__arm__) | |||
static char sys_dllextent[] = ".l_arm"; | |||
# else | |||
static char sys_dllextent[] = ".so"; | |||
# endif | |||
#elif defined(__APPLE__) | |||
# ifndef MACOSX3 | |||
static char sys_dllextent[] = ".d_fat", sys_dllextent2[] = ".pd_darwin"; | |||
# else | |||
static char sys_dllextent[] = ".d_ppc", sys_dllextent2[] = ".pd_darwin"; | |||
# endif | |||
#elif defined(_WIN32) || defined(__CYGWIN__) | |||
static char sys_dllextent[] = ".m_i386", sys_dllextent2[] = ".dll"; | |||
#else | |||
static char sys_dllextent[] = ".so", sys_dllextent2[] = ".so"; | |||
#endif | |||
/* maintain list of loaded modules to avoid repeating loads */ | |||
typedef struct _loadedlist | |||
{ | |||
struct _loadedlist *ll_next; | |||
t_symbol *ll_name; | |||
} t_loadlist; | |||
static t_loadlist *sys_loaded; | |||
int sys_onloadlist(const char *classname) /* return true if already loaded */ | |||
{ | |||
t_symbol *s = gensym(classname); | |||
t_loadlist *ll; | |||
for (ll = sys_loaded; ll; ll = ll->ll_next) | |||
if (ll->ll_name == s) | |||
return (1); | |||
return (0); | |||
} | |||
/* add to list of loaded modules */ | |||
void sys_putonloadlist(const char *classname) | |||
{ | |||
t_loadlist *ll = (t_loadlist *)getbytes(sizeof(*ll)); | |||
ll->ll_name = gensym(classname); | |||
ll->ll_next = sys_loaded; | |||
sys_loaded = ll; | |||
/* post("put on list %s", classname); */ | |||
} | |||
void class_set_extern_dir(t_symbol *s); | |||
static int sys_do_load_abs(t_canvas *canvas, const char *objectname, | |||
const char *path); | |||
static int sys_do_load_lib(t_canvas *canvas, const char *objectname, | |||
const char *path) | |||
{ | |||
char symname[MAXPDSTRING], filename[MAXPDSTRING], dirbuf[MAXPDSTRING], | |||
*nameptr, altsymname[MAXPDSTRING]; | |||
const char *classname, *cnameptr; | |||
void *dlobj; | |||
t_xxx makeout = NULL; | |||
int i, hexmunge = 0, fd; | |||
#ifdef _WIN32 | |||
HINSTANCE ntdll; | |||
#endif | |||
/* NULL-path is only used as a last resort, | |||
but we have already tried all paths */ | |||
if(!path)return (0); | |||
if ((classname = strrchr(objectname, '/'))) | |||
classname++; | |||
else classname = objectname; | |||
for (i = 0, cnameptr = classname; i < MAXPDSTRING-7 && *cnameptr; | |||
cnameptr++) | |||
{ | |||
char c = *cnameptr; | |||
if ((c>='0' && c<='9') || (c>='A' && c<='Z')|| | |||
(c>='a' && c<='z' )|| c == '_') | |||
{ | |||
symname[i] = c; | |||
i++; | |||
} | |||
/* trailing tilde becomes "_tilde" */ | |||
else if (c == '~' && cnameptr[1] == 0) | |||
{ | |||
strcpy(symname+i, "_tilde"); | |||
i += strlen(symname+i); | |||
} | |||
else /* anything you can't put in a C symbol is sprintf'ed in hex */ | |||
{ | |||
sprintf(symname+i, "0x%02x", c); | |||
i += strlen(symname+i); | |||
hexmunge = 1; | |||
} | |||
} | |||
symname[i] = 0; | |||
if (hexmunge) | |||
{ | |||
memmove(symname+6, symname, strlen(symname)+1); | |||
strncpy(symname, "setup_", 6); | |||
} | |||
else strcat(symname, "_setup"); | |||
#if 0 | |||
fprintf(stderr, "lib: %s\n", classname); | |||
#endif | |||
/* try looking in the path for (objectname).(sys_dllextent) ... */ | |||
if ((fd = sys_trytoopenone(path, objectname, sys_dllextent, | |||
dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0) | |||
goto gotone; | |||
/* same, with the more generic sys_dllextent2 */ | |||
if ((fd = sys_trytoopenone(path, objectname, sys_dllextent2, | |||
dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0) | |||
goto gotone; | |||
/* next try (objectname)/(classname).(sys_dllextent) ... */ | |||
strncpy(filename, objectname, MAXPDSTRING); | |||
filename[MAXPDSTRING-2] = 0; | |||
strcat(filename, "/"); | |||
strncat(filename, classname, MAXPDSTRING-strlen(filename)); | |||
filename[MAXPDSTRING-1] = 0; | |||
if ((fd = sys_trytoopenone(path, filename, sys_dllextent, | |||
dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0) | |||
goto gotone; | |||
if ((fd = sys_trytoopenone(path, filename, sys_dllextent2, | |||
dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0) | |||
goto gotone; | |||
#ifdef ANDROID | |||
/* Android libs have a 'lib' prefix, '.so' suffix and don't allow ~ */ | |||
char libname[MAXPDSTRING] = "lib"; | |||
strncat(libname, objectname, MAXPDSTRING - 4); | |||
int len = strlen(libname); | |||
if (libname[len-1] == '~' && len < MAXPDSTRING - 6) { | |||
strcpy(libname+len-1, "_tilde"); | |||
} | |||
if ((fd = sys_trytoopenone(path, libname, ".so", | |||
dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0) | |||
goto gotone; | |||
#endif | |||
return (0); | |||
gotone: | |||
close(fd); | |||
class_set_extern_dir(gensym(dirbuf)); | |||
/* rebuild the absolute pathname */ | |||
strncpy(filename, dirbuf, MAXPDSTRING); | |||
filename[MAXPDSTRING-2] = 0; | |||
strcat(filename, "/"); | |||
strncat(filename, nameptr, MAXPDSTRING-strlen(filename)); | |||
filename[MAXPDSTRING-1] = 0; | |||
#ifdef _WIN32 | |||
{ | |||
char dirname[MAXPDSTRING], *s, *basename; | |||
sys_bashfilename(filename, filename); | |||
/* set the dirname as DllDirectory, meaning in the path for | |||
loading other DLLs so that dependent libraries can be included | |||
in the same folder as the external. SetDllDirectory() needs a | |||
minimum supported version of Windows XP SP1 for | |||
SetDllDirectory, so WINVER must be 0x0502 */ | |||
strncpy(dirname, filename, MAXPDSTRING); | |||
s = strrchr(dirname, '\\'); | |||
basename = s; | |||
if (s && *s) | |||
*s = '\0'; | |||
if (!SetDllDirectory(dirname)) | |||
error("Could not set '%s' as DllDirectory(), '%s' might not load.", | |||
dirname, basename); | |||
/* now load the DLL for the external */ | |||
ntdll = LoadLibrary(filename); | |||
if (!ntdll) | |||
{ | |||
error("%s: couldn't load", filename); | |||
class_set_extern_dir(&s_); | |||
return (0); | |||
} | |||
makeout = (t_xxx)GetProcAddress(ntdll, symname); | |||
if (!makeout) | |||
makeout = (t_xxx)GetProcAddress(ntdll, "setup"); | |||
SetDllDirectory(NULL); /* reset DLL dir to nothing */ | |||
} | |||
#elif defined(HAVE_LIBDL) || defined(__FreeBSD__) | |||
dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL); | |||
if (!dlobj) | |||
{ | |||
error("%s: %s", filename, dlerror()); | |||
class_set_extern_dir(&s_); | |||
return (0); | |||
} | |||
makeout = (t_xxx)dlsym(dlobj, symname); | |||
if(!makeout) | |||
makeout = (t_xxx)dlsym(dlobj, "setup"); | |||
#else | |||
#warning "No dynamic loading mechanism specified, \ | |||
libdl or WIN32 required for loading externals!" | |||
#endif | |||
if (!makeout) | |||
{ | |||
error("load_object: Symbol \"%s\" not found", symname); | |||
class_set_extern_dir(&s_); | |||
return 0; | |||
} | |||
(*makeout)(); | |||
class_set_extern_dir(&s_); | |||
return (1); | |||
} | |||
/* linked list of loaders */ | |||
typedef struct loader_queue { | |||
loader_t loader; | |||
struct loader_queue *next; | |||
} loader_queue_t; | |||
static loader_queue_t loaders = {sys_do_load_lib, NULL}; | |||
/* register class loader function */ | |||
void sys_register_loader(loader_t loader) | |||
{ | |||
loader_queue_t *q = &loaders; | |||
while (1) | |||
{ | |||
if (q->loader == loader) /* already loaded - nothing to do */ | |||
return; | |||
else if (q->next) | |||
q = q->next; | |||
else | |||
{ | |||
q->next = (loader_queue_t *)getbytes(sizeof(loader_queue_t)); | |||
q->next->loader = loader; | |||
q->next->next = NULL; | |||
break; | |||
} | |||
} | |||
} | |||
#include "g_canvas.h" | |||
/* the data passed to the iter-function */ | |||
struct _loadlib_data | |||
{ | |||
t_canvas *canvas; | |||
const char *classname; | |||
int ok; | |||
}; | |||
int sys_loadlib_iter(const char *path, struct _loadlib_data *data) | |||
{ | |||
int ok = 0; | |||
loader_queue_t *q; | |||
for(q = &loaders; q; q = q->next) | |||
if ((ok = q->loader(data->canvas, data->classname, path))) | |||
break; | |||
/* if all loaders failed, try to load as abstraction */ | |||
if (!ok) | |||
ok = sys_do_load_abs(data->canvas, data->classname, path); | |||
data->ok = ok; | |||
return (ok == 0); | |||
} | |||
int sys_load_lib(t_canvas *canvas, const char *classname) | |||
{ | |||
int dspstate = canvas_suspend_dsp(); | |||
struct _loadlib_data data; | |||
data.canvas = canvas; | |||
data.ok = 0; | |||
if (sys_onloadlist(classname)) | |||
{ | |||
error("%s: already loaded", classname); | |||
return (1); | |||
} | |||
/* if classname is absolute, try this first */ | |||
if (sys_isabsolutepath(classname)) | |||
{ | |||
/* this is just copied from sys_open_absolute() | |||
LATER avoid code duplication */ | |||
char dirbuf[MAXPDSTRING], *z = strrchr(classname, '/'); | |||
int dirlen; | |||
if (!z) | |||
return (0); | |||
dirlen = (int)(z - classname); | |||
if (dirlen > MAXPDSTRING-1) | |||
dirlen = MAXPDSTRING-1; | |||
strncpy(dirbuf, classname, dirlen); | |||
dirbuf[dirlen] = 0; | |||
data.classname=classname+(dirlen+1); | |||
sys_loadlib_iter(dirbuf, &data); | |||
} | |||
data.classname = classname; | |||
if(!data.ok) | |||
canvas_path_iterate(canvas, (t_canvas_path_iterator)sys_loadlib_iter, | |||
&data); | |||
/* if loaders failed so far, we try a last time without a PATH | |||
* let the loaders search wherever they want */ | |||
if (!data.ok) | |||
sys_loadlib_iter(0, &data); | |||
if(data.ok) | |||
sys_putonloadlist(classname); | |||
canvas_resume_dsp(dspstate); | |||
return data.ok; | |||
} | |||
int sys_run_scheduler(const char *externalschedlibname, | |||
const char *sys_extraflagsstring) | |||
{ | |||
typedef int (*t_externalschedlibmain)(const char *); | |||
t_externalschedlibmain externalmainfunc; | |||
char filename[MAXPDSTRING]; | |||
struct stat statbuf; | |||
snprintf(filename, sizeof(filename), "%s%s", externalschedlibname, | |||
sys_dllextent); | |||
sys_bashfilename(filename, filename); | |||
/* if first-choice file extent can't 'stat', go for second */ | |||
if (stat(filename, &statbuf) < 0) | |||
{ | |||
snprintf(filename, sizeof(filename), "%s%s", externalschedlibname, | |||
sys_dllextent2); | |||
sys_bashfilename(filename, filename); | |||
} | |||
#ifdef _WIN32 | |||
{ | |||
HINSTANCE ntdll = LoadLibrary(filename); | |||
if (!ntdll) | |||
{ | |||
fprintf(stderr, "%s: couldn't load external scheduler\n", filename); | |||
error("%s: couldn't load external scheduler", filename); | |||
return (1); | |||
} | |||
externalmainfunc = | |||
(t_externalschedlibmain)GetProcAddress(ntdll, "pd_extern_sched"); | |||
if (!externalmainfunc) | |||
externalmainfunc = | |||
(t_externalschedlibmain)GetProcAddress(ntdll, "main"); | |||
} | |||
#elif defined HAVE_LIBDL | |||
{ | |||
void *dlobj; | |||
dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL); | |||
if (!dlobj) | |||
{ | |||
error("%s: %s", filename, dlerror()); | |||
fprintf(stderr, "dlopen failed for %s: %s\n", filename, dlerror()); | |||
return (1); | |||
} | |||
externalmainfunc = (t_externalschedlibmain)dlsym(dlobj, | |||
"pd_extern_sched"); | |||
} | |||
#else | |||
return (0); | |||
#endif | |||
if (externalmainfunc) | |||
return((*externalmainfunc)(sys_extraflagsstring)); | |||
else | |||
{ | |||
fprintf(stderr, "%s: couldn't find pd_extern_sched() or main()\n", | |||
filename); | |||
return (0); | |||
} | |||
} | |||
/* abstraction loading */ | |||
void canvas_popabstraction(t_canvas *x); | |||
int pd_setloadingabstraction(t_symbol *sym); | |||
static t_pd *do_create_abstraction(t_symbol*s, int argc, t_atom *argv) | |||
{ | |||
/* | |||
* TODO: check if the there is a binbuf cached for <canvas::symbol> | |||
and use that instead. We'll have to invalidate the cache once we | |||
are done (either with a clock_delay(0) or something else) | |||
*/ | |||
if (!pd_setloadingabstraction(s)) | |||
{ | |||
const char *objectname = s->s_name; | |||
char dirbuf[MAXPDSTRING], classslashclass[MAXPDSTRING], *nameptr; | |||
t_glist *glist = (t_glist *)canvas_getcurrent(); | |||
t_canvas *canvas = (t_canvas*)glist_getcanvas(glist); | |||
int fd = -1; | |||
t_pd *was = s__X.s_thing; | |||
snprintf(classslashclass, MAXPDSTRING, "%s/%s", objectname, objectname); | |||
if ((fd = canvas_open(canvas, objectname, ".pd", | |||
dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 || | |||
(fd = canvas_open(canvas, objectname, ".pat", | |||
dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 || | |||
(fd = canvas_open(canvas, classslashclass, ".pd", | |||
dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0) | |||
{ | |||
close(fd); | |||
canvas_setargs(argc, argv); | |||
binbuf_evalfile(gensym(nameptr), gensym(dirbuf)); | |||
if (s__X.s_thing && was != s__X.s_thing) | |||
canvas_popabstraction((t_canvas *)(s__X.s_thing)); | |||
else s__X.s_thing = was; | |||
canvas_setargs(0, 0); | |||
return (pd_this->pd_newest); | |||
} | |||
/* otherwise we couldn't do it; just return 0 */ | |||
} | |||
else error("%s: can't load abstraction within itself\n", s->s_name); | |||
pd_this->pd_newest = 0; | |||
return (0); | |||
} | |||
/* search for abstraction; register a creator if found */ | |||
static int sys_do_load_abs(t_canvas *canvas, const char *objectname, | |||
const char *path) | |||
{ | |||
int fd; | |||
static t_gobj*abstraction_classes = 0; | |||
char dirbuf[MAXPDSTRING], classslashclass[MAXPDSTRING], *nameptr; | |||
/* NULL-path is only used as a last resort, | |||
but we have already tried all paths */ | |||
if (!path) return (0); | |||
snprintf(classslashclass, MAXPDSTRING, "%s/%s", objectname, objectname); | |||
if ((fd = sys_trytoopenone(path, objectname, ".pd", | |||
dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0 || | |||
(fd = sys_trytoopenone(path, objectname, ".pat", | |||
dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0 || | |||
(fd = sys_trytoopenone(path, classslashclass, ".pd", | |||
dirbuf, &nameptr, MAXPDSTRING, 1)) >= 0) | |||
{ | |||
t_class*c=0; | |||
close(fd); | |||
/* found an abstraction, now register it as a new pseudo-class */ | |||
class_set_extern_dir(gensym(dirbuf)); | |||
if((c=class_new(gensym(objectname), | |||
(t_newmethod)do_create_abstraction, 0, | |||
0, 0, A_GIMME, 0))) | |||
{ | |||
/* store away the newly created class, maybe we will need it one day */ | |||
t_gobj*absclass=0; | |||
absclass=t_getbytes(sizeof(*absclass)); | |||
absclass->g_pd=c; | |||
absclass->g_next=abstraction_classes; | |||
abstraction_classes=absclass; | |||
} | |||
class_set_extern_dir(&s_); | |||
return (1); | |||
} | |||
return (0); | |||
} |